容器内的JAX-RS客户端ISO8601日期serialization

时间:2018-05-04 15:29:27

标签: json rest java-ee jackson jax-rs

我有一个带有POST /items端点的JSON REST API,它需要一个像:

这样的对象

{"name": "item_name", "timestamp": "2018-01-01T01:01:01.001"}

我需要从部署在WildFly10上的JEE7应用程序调用此端点。

为了用Java建模对象,我定义了一个简单的DTO类:

class ItemDTO {

  private String name;
  private LocalDateTime timestamp;

  // default constructor and getters/setters omitted for brevity
}

默认情况下,LocalDateTime的序列化会导致复杂的JSON对象而不是ISO8601字符串。

根据我在网络上发现的内容,我添加了我的依赖项:

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jdk8</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
        <version>${jackson.version}</version>
    </dependency>

使用jackson.version = 2.7.4

ClientBuilder builder = ClientBuilder.newBuilder()
  .register(new RequestLogger())
  .register(
    new JacksonJsonProvider(
      new ObjectMapper()
        .registerModule(new JavaTimeModule()) 
        .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
        .configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false)
        .setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"))
      , DEFAULT_ANNOTATIONS)
);

上面的代码将clientBuilder配置为构建配备了ObjectMapper的客户端,该对象将Java8日期/时间类型序列化为ISO8601字符串。

Response creation = builder.build()
  .target("http://localhost:8080/my-api/v1.0/items")
  .request().accept(MediaType.APPLICATION_JSON)
  .post(Entity.entity(itemDTO, MediaType.APPLICATION_JSON));

意外地此请求失败,因为LocalDateTime中包含的ItemDTO仍然被序列化为复杂的JSON对象。

N.B。:我的REST API完全能够将ISO8601字符串反序列化为LocalDateTime

N.B。:如果没有在容器内运行,那么发出POST请求的代码就能完美运行(即LocalDateTime被序列化为ISO8601)

1 个答案:

答案 0 :(得分:0)

  

“如果不在容器内运行,则使POST请求的代码完美无缺”

您注册客户端的JacksonJsonProvider很可能不是正在使用的ObjectMapper。在容器中,RESTEasy已经有一个自动注册到客户端的Jackson模块,这就是正在使用的模块。

您可以使用ContextResolver而不是配置ObjectMapper并将其传递给提供商。提供程序将查找此解析程序并从那里获取@Provider public class ObjectMapperResolver implements ContextResolver<ObjectMapper> { private final ObjectMapper mapper; public ObjectMapperResolver() { mapper = new ObjectMapper(); // configure mapper } @Override public ObjectMapper getContext(Class<?> cls) { return mapper; } }

ClientBuilder builder = ClientBuilder.newBuilder()
        .register(ObjectMapperResolver.class)

然后只需向客户注册解析器。

Array.findIndex()

如果 这是我怀疑的情况,那么已经有一个JSON提供程序在幕后自动注册,那么你就不需要注册另一个了。