Подтвердить что ты не робот

Spring Проблемы с загрузкой сериализуют java.time.LocalDateTime с Jackson для возврата меток ISO-8601 JSON?

Я работаю над преобразованием некоторых моделей в приложение API REST spring -boot, чтобы использовать java 8 java.time.LocalDateTime вместо joda DateTime. Я хочу, чтобы временные метки возвращались из вызова API для привязки к формату ISO_8601. Мотивация должна быть совместима с Java 8 раз (подробнее здесь).

Часть, которая доказывает сложность, заключается в том, что для сериализации объекта, содержащего LocalDateTime, для JSON.

Например, у меня есть следующий объект:

// ... misc imports

import java.time.LocalDateTime;
import java.time.ZoneOffset;

@Data 
@Entity
@Table(name = "users")
public class User {

    @Id @Column
    private String id;

    @Column
    private String name;

    @Column
    private String email;

    @Column
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "UTC")
    private java.time.LocalDateTime createdAt;

    public User(String name, String email) {
        this.id = Utils.generateUUID();
        this.createdAt = LocalDateTime.now(ZoneOffset.UTC);
    }
}

Я также установил мой application.properties, чтобы отключить даты как функцию timestamp jackson:

spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false

Мои деления maven:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>1.3.6.RELEASE</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.8.1</version>
</dependency>

<dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate-core</artifactId>
     <version>5.0.1.Final</version>
 </dependency>

Наконец, я пытаюсь получить представление JSON через контроллер:

@RequestMapping("/users")
@RestController
public class UserController {

    private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @RequestMapping(
        value = "/{id}",
        method = RequestMethod.GET,
        produces = MediaType.APPLICATION_JSON_UTF8_VALUE
    )
    public User getUser(@PathVariable("id") String id) {
        return userService.findById(id);
    }
}

Когда я действительно звоню на эту конечную точку, я получаю следующее исключение:

java.lang.NoSuchMethodError: 
com.fasterxml.jackson.datatype.jsr310.ser.JSR310FormattedSerializerBase.findFormatOverrides(Lcom/fasterxml/jackson/databind/SerializerProvider;Lcom/fasterxml/jackson/databind/BeanProperty;Ljava/lang/Class;)Lcom/fasterxml/jackson/annotation/JsonFormat$Value;

В качестве альтернативы я также настроил приложение ObjectMapper в классе конфигурации:

@Configuration
public class ServiceConfiguration {

    @Bean
    public ObjectMapper getJacksonObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.configure(
            com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
            false
        );
        return objectMapper;
    }
}

Любые ссылки будут очень благодарны.


UPDATE:

Оказывается, это было несоответствие версии Spring версия Boot Jackson и та, что у меня была в моем pom.xml. Как предложил Милош и Энди, как только я установил правильную версию и запустил приложение с помощью spring.jackson.serialization.write_dates_as_timestamps=true, проблема была решена без необходимости настройки ObjectMapper или добавления аннотаций в мои поля модели LocalDateTime.

    ...
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>1.3.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>1.3.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
        </dependency>

    </dependencies>
4b9b3361

Ответ 1

NoSuchMethodError заключается в том, что вы смешиваете версии Jackson. Spring Boot 1.3.6 использует Jackson 2.6.7, и вы используете 2.8.1 из jackson-datatype-jsr310.

Spring Boot обеспечивает управление зависимостями для Jackson, включая jackson-datatype-jsr310, поэтому вы должны удалить версию из своего pom. Если вы хотите использовать другую версию Jackson, вы должны переопределить свойство jackson.version:

<properties>
    <jackson.version>2.8.1</jackson.version>
</properties>

Это гарантирует, что все ваши зависимости от Jackson имеют одну и ту же версию, что позволит избежать проблем с несогласованными версиями.

Вы также можете, если хотите, удалить код Java, который настраивает ObjectMapper. Модуль Java Time будет автоматически зарегистрирован, когда он находится в пути к классам и записывает даты, поскольку временные метки могут быть настроены в application.properties:

spring.jackson.serialization.write-dates-as-timestamps=false

Ответ 2

Ваш ObjectMapper bean должен быть помечен как @Primary, чтобы его подхватили Spring. Кроме того, вы можете просто создать JavaTimeModule bean, и он будет подхвачен с помощью Spring и добавлен к объекту сопоставления объектов по умолчанию.

Возможно, вы уже видели это, но посмотрите официальную документацию.