Jackson2 JSON ISO 8601 от JodaTime в Spring 3.2RC1 - программирование
Подтвердить что ты не робот

Jackson2 JSON ISO 8601 от JodaTime в Spring 3.2RC1

Я работаю над REST API в Spring MVC 3.2RC1.

Я получаю объект JPA с отметкой времени org.joda.time.DateTime в нем и пусть Spring сериализует его в JSON, используя

@RequestMapping(value = "/foobar", method = RequestMethod.GET, produces = "application/json")
@ResponseBody

Использование стандартных настроек Jackson2 в Spring, поскольку я добавил только

<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 />

P.S. Я сохраняю объекты PostgreSQL с JPA/Hibernate4, используя UserType, чтобы получить поддержку 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>
4b9b3361

Ответ 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());
    }

}

Ответ 2

В итоге я начал работать с jackson-datatype-joda:

Добавьте еще одну зависимость от Maven (соответствует номеру версии вашего Джексона):

<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

Обратите внимание, что вам нужно установить (Simple) DateFormat, как показано в вопросе, но отключение SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, похоже, не имеет никакого значения.

Ответ 3

Просто подведем итоги и опубликуем рабочее решение для сериализации JodaTime в Spring (проверено на 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-версия 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>

После этого ваши поля JodaTime в ResponseBody будут автоматически сериализованы в JSON как   "createdDate": "2013-01-18T15: 15: 36.365 + 02: 00"

Ответ 4

Я боролся с тем же b @# $d, созданным jackson из поля entity с joda DayTime:

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

Я борюсь с той же проблемой и попытался упростить сериализацию DateTime Spring для JSON таким образом в app-servlet.xml:

<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>

Здесь вы можете найти no.bouvet.jsonclient.spring.JsonClientJackson2ObjectMapperFactoryBean из java-json-client