【问题标题】:jackson2 JSON ISO 8601 date from JodaTime in Spring 3.2RC1春季 3.2RC1 中来自 JodaTime 的 jackson2 JSON ISO 8601 日期
【发布时间】:2012-11-21 22:59:18
【问题描述】:

我正在使用 Spring MVC 3.2RC1 中的 REST API。

我正在获取一个带有 org.joda.time.DateTime 时间戳的 JPA 实体,并让 Spring 使用

将其序列化为 JSON
@RequestMapping(value = "/foobar", method = RequestMethod.GET, produces = "application/json")
@ResponseBody

在 Spring 中使用默认的 Jackson2 设置,因为我只添加了

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.1.1</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.1.1</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.1.1</version>
</dependency>

到我的 POM 并让 Spring 自行连接。

控制器正在生成:

"created":{"year":2012,"dayOfMonth":30,"dayOfWeek":5,"era":1,"dayOfYear":335,"weekOfWeekyear":48,"weekyear":2012,"monthOfYear":11,"yearOfEra":2012,"yearOfCentury":12,"centuryOfEra":20,"millisOfSecond":39,"millisOfDay":52684039,"secondOfMinute":4,"secondOfDay":52684,"minuteOfHour":38,"minuteOfDay":878,"hourOfDay":14,"millis":1354282684039,"zone":{"uncachedZone":{"cachable":true,"fixed":false,"id":"Europe/Stockholm"},"fixed":false,"id":"Europe/Stockholm"},"chronology":{"zone":{"uncachedZone":{"cachable":true,"fixed":false,"id":"Europe/Stockholm"},"fixed":false,"id":"Europe/Stockholm"}},"afterNow":false,"beforeNow":true,"equalNow":false}

但我希望它是 ISO8601 日期,例如 2007-11-16T20:14:06.3Z(或带有偏移量)。

我的猜测是我需要访问 ObjectMapper 并设置 mapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);但是在使用时如何访问 ObjectMapper

<mvc:annotation-driven />

附:我使用 UserType 使用 JPA/Hibernate4 将对象持久化到 PostgreSQL 以获得 JodaTime 支持。 D.S.

更新

下面的配置解决了 java.util.Date 的问题,但 JodaTime 仍然没有骰子。

<annotation-driven>
    <message-converters>
        <beans:bean
            class="org.springframework.http.converter.StringHttpMessageConverter" />
        <beans:bean
            class="org.springframework.http.converter.ResourceHttpMessageConverter" />
        <beans:bean
            class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <beans:property name="objectMapper">
                <beans:bean
                    class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
                    p:indentOutput="true" p:simpleDateFormat="yyyy-MM-dd'T'HH:mm:ss.SSSZ">
                </beans:bean>
            </beans:property>
        </beans:bean>
    </message-converters>
</annotation-driven>

【问题讨论】:

  • 不,不是。我放弃了 Joda 时间类型,并在我的 DTO 中使用了常规日期。如果你没记错的话,请添加 : array> 在 Jackson2ObjectMapperFactoryBean bean 中,您将其作为纪元时间戳获取,并且 joda jackson 模块需要补丁才能使用 simpleDateFormat。

标签: json spring spring-mvc jackson jodatime


【解决方案1】:

或者,如果您更喜欢使用 Java 进行配置,它可能如下所示:

@Configuration
@EnableWebMvc
public class RestConfig extends WebMvcConfigurerAdapter {

    private ObjectMapper objectMapper() {
        Jackson2ObjectMapperFactoryBean bean = new Jackson2ObjectMapperFactoryBean();
        bean.setIndentOutput(true);
        bean.setSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
        bean.afterPropertiesSet();
        ObjectMapper objectMapper = bean.getObject();
        objectMapper.registerModule(new JodaModule());
        return objectMapper;
    }

    private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setObjectMapper(objectMapper());
        return converter;
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(mappingJackson2HttpMessageConverter());
    }

}

【讨论】:

  • 无需显式注册JodaModuleJackson2ObjectMapperFactoryBean 使用 Jackson2ObjectMapperBuilder 如果它在类路径上可用,它会自动注册模块。
【解决方案2】:

我最终使用jackson-datatype-joda

添加另一个 Maven 依赖项(匹配您的 Jackson 版本号):

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-joda</artifactId>
    <version>${jackson.version}</version>
</dependency>

然后将 JodaModule(处理转换)注册到 Jackson 的 ObjectMapper(这里在 Spring 中完成,但您可以创建一个辅助类):

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
    p:targetObject-ref="objectMapper" p:targetMethod="registerModule">
    <property name="arguments">
        <list><bean class="com.fasterxml.jackson.datatype.joda.JodaModule"/></list>
    </property>
</bean>

(您需要为 ObjectMapper 提供一个 id 以便可以通过这种方式引用它)。

Hibernate模块也是这样注册的:https://github.com/FasterXML/jackson-module-hibernate

请注意,您需要设置一个(简单)日期格式,如问题所示,但禁用 SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS 似乎没有任何区别。

【讨论】:

  • 请注意,如果您使用的是 GAE(Google App Engine),它们会将一些类重新打包,其中一个是 org.joda.time.LocalDatecom.google.appengine.repackaged.org.joda.time.LocalDate,如果您使用的是 Google 重新打包的类,则这些类将不起作用. (尽管为JodaModule +1!)
  • 您也可以直接调用JodaMapper,例如:private static final JodaMapper mapper = (JodaMapper) new JodaMapper().setPropertyNamingStrategy(new UpperCamelCaseStrategy());
  • 这在Junit测试中不起作用,序列化的日期是测试期间的时间戳,而应用生命周期中的ISO格式
【解决方案3】:

只是为了总结答案并发布 Spring 中 JodaTime 序列化的工作解决方案(在 Spring 3.2 上测试)

spring-context.xml

<bean id="objectMapper"
    class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
    p:indentOutput="true" p:simpleDateFormat="yyyy-MM-dd'T'HH:mm:ss.SSSZ">
</bean>
<bean
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
    p:targetObject-ref="objectMapper" p:targetMethod="registerModule">
    <property name="arguments">
        <list>
            <bean class="com.fasterxml.jackson.datatype.joda.JodaModule" />
        </list>
    </property>
</bean>

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
        <bean
            class="org.springframework.http.converter.ResourceHttpMessageConverter" />

        <bean
            class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper" ref="objectMapper" />
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

Maven 依赖项(com.fasterxml.jackson-version 为 2.1.1)

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>${com.fasterxml.jackson-version}</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>${com.fasterxml.jackson-version}</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-joda</artifactId>
    <version>${com.fasterxml.jackson-version}</version>
</dependency>

在此之后,您在 ResponseBody 中的 JodaTime 字段将在 JSON 中自动序列化为 “创建日期”:“2013-01-18T15:15:36.365+02:00”

【讨论】:

  • 另一个选项是配置全局日期和时间格式official documentation
  • 我尝试了几种不同的解决方案,这个很棒,因为您无需编写任何代码并且可以完美运行。
  • 如果你使用Jackson2ObjectMapperFactoryBean,你不需要显式注册JodaModule(你使用MethodInvokingFactoryBean做什么)。 Jackson2ObjectMapperFactoryBean 使用 Jackson2ObjectMapperBuilder 如果它在类路径上可用,它会自动注册模块。
【解决方案4】:

我正在努力处理杰克逊从实体字段与 joda DayTime 创建的完全相同的 b@#$d:

modifiedOn": {

"year": 2013,
"dayOfWeek": 6,
"era": 1,
"dayOfYear": 124,
"dayOfMonth": 4,
"weekOfWeekyear": 18,
"monthOfYear": 5,
"yearOfCentury": 13,
"centuryOfEra": 20,
"millisOfSecond": 0,
"millisOfDay": 81801000,
"secondOfMinute": 21,
"secondOfDay": 81801,
"minuteOfHour": 43,
"minuteOfDay": 1363,
"weekyear": 2013,
"yearOfEra": 2013,
"hourOfDay": 22,
"millis": 1367700201000,
"zone": {
    "uncachedZone": {
        "cachable": true,
        "fixed": false,
        "id": "Europe/Belgrade"
    },
    "fixed": false,
    "id": "Europe/Belgrade"
},
"chronology": {
    "zone": {
        "uncachedZone": {
            "cachable": true,
            "fixed": false,
            "id": "Europe/Belgrade"
        },
        "fixed": false,
        "id": "Europe/Belgrade"
    }
},
"afterNow": false,
"beforeNow": true,
"equalNow": false
}

正如这里提到的 https://github.com/FasterXML/jackson-datatype-joda 使用 Jackson 2.0 很容易,但对于像我这样的新手来说,很难弄清楚如何让它工作,但最终找到了可以工作的代码:

maven 中的依赖 - 这很简单

<dependency>
 <groupId>com.fasterxml.jackson.datatype</groupId>
 <artifactId>jackson-datatype-joda</artifactId>
 <version>2.1.2</version>
</dependency>

还有一些来自 FasterXML 文档的代码

objectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());

...但是如何实现呢?这是示例 - 新类:

public class JodaObjectMapper extends ObjectMapper {

    public JodaObjectMapper() {
        super();
        registerModule(new JodaModule());
    }
}

最后一步 - 除了 spring.xml

<mvc:annotation-driven>
 <mvc:message-converters register-defaults="true">
 <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
 <property name="objectMapper">
 <bean class="net.jvw.JodaObjectMapper"/>
 </property>
 </bean>
 </mvc:message-converters>
</mvc:annotation-driven>

现在让我们看看生成的 json

"modifiedOn": 1367701129075

终于有件容易处理的事情了

来自博文http://vanwilgenburg.wordpress.com/2013/01/14/return-usable-joda-dates-in-json-with-jackson/

如果有人想查看我的实体类或控制器的更多代码 - 请在评论中提问,我会在此答案中添加足够的代码。

【讨论】:

    【解决方案5】:

    我一直在努力解决同样的问题,并尝试在app-servlet.xml 中以这种方式将 DateTime 的 Spring 序列化简化为 JSON:

    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean class="no.bouvet.jsonclient.spring.JsonClientJackson2ObjectMapperFactoryBean"/>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    

    您可以在这里找到来自java-json-client 库的no.bouvet.jsonclient.spring.JsonClientJackson2ObjectMapperFactoryBean

    【讨论】:

      猜你喜欢
      • 2017-04-26
      • 2014-12-12
      • 2015-02-28
      • 1970-01-01
      • 2013-05-14
      • 2013-02-03
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多