【问题标题】:(De)Serialize DateTime (Joda) with Jackson(De) 使用 Jackson 序列化 DateTime (Joda)
【发布时间】:2017-06-20 11:45:50
【问题描述】:

我正在构建一个 REST 网络服务。某些类具有DateTime (JodaTime) 类型的属性。

当将此对象发送给我的客户端(Javascript)时,我的对象

private DateTime date;

转化为

{ date: { chronology: {}, millis: 1487289600000 } }

问题是我在将此对象发送回服务器时出错,因为我无法实例化chronology

我想要{ date: 1487289600000} 之类的东西 - 任何其他格式都可以。

环境

  • jackson-annotations 2.8.8
  • 杰克逊核心 2.8.8
  • 杰克逊数据库 2.8.8
  • jackson-datatype-joda 2.8.8
  • joda-time 2.7

我的上下文解析器是

@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {

    final ObjectMapper mapper = new ObjectMapper();

    public ObjectMapperContextResolver() {
        mapper.registerModule(new JodaModule());
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return mapper;
    }
}

我错过了什么?如果我不使用ObjectMapperContextResolver,我会得到相同的结果

根据@Cássio Mazzochi Molin 的回答更新

我添加了jackson-jaxrs-json-provider 2.8.8jackson-jaxrs-base 2.8.8jackson-module-jaxb-annotations 2.8.8

我的上下文解析器现在是这样的

@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {

    final ObjectMapper mapper = new ObjectMapper();

    public ObjectMapperContextResolver() {
        mapper.registerModule(new JodaModule());
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return mapper;
    }
}

还有我的应用配置

@javax.ws.rs.ApplicationPath("/")
public class ApplicationConfig extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> resources = new java.util.HashSet<>();
        resources.add(AuthenticationFilter.class);
        resources.add(CORSFilter.class);
        resources.add(ObjectMapperContextResolver.class);
        resources.add(JacksonJsonProvider.class);
        resources.add(ServiceResource.class);
        return resources;
    }
}

我的服务资源

@Path("service")
public class ServiceResource {

    @Path("/forecast/stocks/{modelId}")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<Value> getStocks(@PathParam("modelId") String modelId, @QueryParam("startDate") String startDate, @QueryParam("endDate") String endDate) {
        try {
            DateTime datetimeStart = formatStringToDatetime(startDate);
            DateTime datetimeEnd = formatStringToDatetime(endDate);
            return logicClass.getStocks(modelId, datetimeStart, datetimeEnd);
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Error calling /hydromax/forecast/stocks", e);
            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
        }
    }

}

还有Value 对象

public class Value {

    private DateTime date;
    private Float value;

    public Value() {
    }

    //getter and setter

}

更新

我在ApplicationConfig中添加了以下代码

@Override
public Map<String, Object> getProperties() {
    Map<String, Object> props = new HashMap<>();
    props.put("jersey.config.server.disableMoxyJson", true);
    return props;
}

我的DateTime 现在转换为

"date":{"dayOfMonth":16,"dayOfWeek":4,"era":1,"year":2017,"dayOfYear":47,"weekOfWeekyear":7,"secondOfMinute":0,"millisOfSecond":0,"weekyear":2017,"monthOfYear":2,"hourOfDay":10,"minuteOfHour":0,"yearOfEra":2017,"yearOfCentury":17,"centuryOfEra":20,"millisOfDay":36000000,"secondOfDay":36000,"minuteOfDay":600,"millis":1487235600000,"zone":{"fixed":false,"uncachedZone":{"fixed":false,"cachable":true,"id":"Europe/Paris"},"id":"Europe/Paris"},"chronology":{"zone":{"fixed":false,"uncachedZone":{"fixed":false,"cachable":true,"id":"Europe/Paris"},"id":"Europe/Paris"}},"afterNow":false,"beforeNow":true,"equalNow":false} 

而且我部署后第一次调用服务,我有这个错误

javax.servlet.ServletException: org.glassfish.jersey.server.ContainerException: java.lang.NoClassDefFoundError: com/fasterxml/jackson/module/jaxb/JaxbAnnotationIntrospector

【问题讨论】:

  • 您的ContextResolver注册了吗?
  • @CássioMazzochiMolin 是的resources.add(ObjectMapperContextResolver.class);
  • 对我来说,它有效:{"date":"2017-02-17T00:00:00.000Z"}
  • @Hugo 除了注册这个课程,你还使用其他什么东西吗?你使用任何注释吗?还有其他配置吗?
  • @Hugo 你说的它对我有用是什么意思?你复制粘贴我的代码了吗?

标签: java datetime jackson jodatime


【解决方案1】:

您的应用程序中可能缺少jackson-jaxrs-json-provider 模块。

此模块是 JAX-RS 实现(例如 Jersey 和 RESTeasy)的 Jackson JSON 提供程序。

仅当您需要为 Jackson JSON 提供程序自定义 ObjectMapper 时,才需要用于 ObjectMapperContextResolver。但是如果 Jackson 提供者没有注册,ContextResolver 将不会做任何事情。


这是您需要的依赖项:

<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-json-provider</artifactId>
    <version>2.8.8</version>
</dependency>

如果您不使用 Maven,请将 jackson-jaxrs-json-provider-2.8.8.jar 添加到类路径中。

然后根据您的需要注册JacksonJsonProvider(仅使用Jackson 注释)或JacksonJaxbJsonProvider(同时使用Jackson 和JAXB 注释)。

【讨论】:

  • 我还添加了jackson-jaxrs-json-provider的依赖。因此我应该只注册resources.add(JacksonJsonProvider.class); 而不是resources.add(ObjectMapperContextResolver.class); ?
  • @Weedoze 注册两者。 JacksonJsonProvider 让 Jackson 处理 JSON(反)序列化,ObjectMapperContextResolver 为 Jackson 提供程序自定义 ObjectMapper
  • 添加模块+依赖并注册JacksonJsonProvider+ObjectMapperContextResolver就完成了。我仍然有相同的结果。我应该在我的属性上使用任何注释吗?
  • @Weedoze 向ObjectMapperContextResolver#getContext() 方法添加断点并确保它被调用。
  • Okok - 我已经用您的回答结果更新了我的问题
猜你喜欢
  • 2015-06-20
  • 2011-08-07
  • 2013-09-25
  • 2011-03-17
  • 2018-03-14
  • 1970-01-01
  • 2014-11-13
  • 2016-07-24
  • 2017-09-17
相关资源
最近更新 更多