杰克逊(de)由JAX-RS客户端序列化Java8日期/时间
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了杰克逊(de)由JAX-RS客户端序列化Java8日期/时间,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5973字,纯文字阅读大概需要9分钟。
内容图文
我正在为REST端点创建一个服务器客户端,使用JAX-RS客户端进行HTTP请求,使用Jackson来(de)序列化JSON实体.为了处理JSR-310(Java8)日期/时间对象,我添加了com.fasterxml.jackson.datatype:jackson-datatype-jsr310模块作为服务客户端的依赖项,但我没有让它工作.
如何配置JAX-RS和/或Jackson以使用jsr310模块?
我使用以下依赖项:
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>${jax-rs.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
我不想让服务客户端(作为库发布)依赖于任何特定的实现 – 比如Jersey,所以我只依赖于JAX-RS API.为了运行我的集成测试,我添加了:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>${jersey.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
<scope>test</scope>
</dependency>
JAX-RS客户端的实例化在工厂对象中完成,如下所示:
import javax.ws.rs.Produces;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
@Produces
public Client produceClient() {
return ClientBuilder.newClient();
}
典型的DTO看起来像这样:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import java.time.Instant;
import static java.util.Objects.requireNonNull;
@JsonPropertyOrder({"n", "t"})
public final class Message {
private final String name;
private final Instant timestamp;
@JsonCreator
public Message(@JsonProperty("n") final String name,
@JsonProperty("t") final Instant timestamp) {
this.name = requireNonNull(name);
this.timestamp = requireNonNull(timestamp);
}
@JsonProperty("n")
public String getName() {
return this.name;
}
@JsonProperty("t")
public Instant getTimestamp() {
return this.timestamp;
}
// equals(Object), hashCode() and toString()
}
请求是这样完成的:
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
public final class Gateway {
private final WebTarget endpoint;
public Message postSomething(final Something something) {
return this.endpoint
.request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.json(something), Message.class);
}
// where Message is the class defined above and Something is a similar DTO
}
JSON序列化和反序列化适用于Strings,int,BigIntegers,Lists等.但是,当我执行类似System.out.println(gateway.postSomthing(new Something(“x”,“y”))的操作时;在我的测试中我得到以下异常:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.time.Instant` (no Creators, like default construct, exist): no String-argument constructor/factory method to deserialize from String value ('Fri, 22 Sep 2017 10:26:52 GMT')
at [Source: (org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream); line: 1, column: 562] (through reference chain: Message["t"])
at org.example.com.ServiceClientTest.test(ServiceClientTest.java:52)
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
Cannot construct instance of `java.time.Instant` (no Creators, like default construct, exist): no String-argument constructor/factory method to deserialize from String value ('Fri, 22 Sep 2017 10:26:52 GMT')
at [Source: (org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream); line: 1, column: 562] (through reference chain: Message["t"])
at org.example.com.ServiceClientTest.test(ServiceClientTest.java:52)
从中我得出结论,杰克逊不知道如何将字符串反序列化为Instants.我发现了关于这个主题的博客和SO问题,但我没有找到关于如何使其工作的明确解释.
请注意,我希望服务客户端处理日期字符串,如“星期五,2017年9月22日10:26:52 GMT”以及“2017-09-22T10:26:52.123Z”,但我希望它始终序列化到ISO 8601日期字符串.
谁能解释如何将反序列化转换为即时作品?
解决方法:
在示例代码中,您目前依赖于jersey-media-json-jackson.您可能更好地依赖于Jackson的JAX-RS JSON,因为您可以使用标准的JAX-RS API(以及Jackson API的cource)配置Jackson映射器.
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson.version}</version>
</dependency>
删除jersey-media-json-jackson并添加jackson-jaxrs-json-provider依赖项后,您可以配置JacksonJaxbJsonProvider并在生成Client的类中注册它:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import static com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS;
public class ClientProducer {
private JacksonJsonProvider jsonProvider;
public ClientProducer() {
// Create an ObjectMapper to be used for (de)serializing to/from JSON.
ObjectMapper objectMapper = new ObjectMapper();
// Register the JavaTimeModule for JSR-310 DateTime (de)serialization
objectMapper.registerModule(new JavaTimeModule());
// Configure the object mapper te serialize to timestamp strings.
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
// Create a Jackson Provider
this.jsonProvider = new JacksonJaxbJsonProvider(objectMapper, DEFAULT_ANNOTATIONS);
}
@Produces
public Client produceClient() {
return ClientBuilder.newClient()
// Register the jsonProvider
.register(this.jsonProvider);
}
}
希望这可以帮助.
内容总结
以上是互联网集市为您收集整理的杰克逊(de)由JAX-RS客户端序列化Java8日期/时间全部内容,希望文章能够帮你解决杰克逊(de)由JAX-RS客户端序列化Java8日期/时间所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。