잭슨이 Spring Boot에서 ZonedDateTime을 잘못 시리얼화함
Spring Boot과 Jetty의 심플한 어플이 있습니다.Java 8을 탑재한 오브젝트를 반환하는 심플한 컨트롤러가 있다.ZonedDateTime
:
public class Device {
// ...
private ZonedDateTime lastUpdated;
public Device(String id, ZonedDateTime lastUpdated, int course, double latitude, double longitude) {
// ...
this.lastUpdated = lastUpdated;
// ...
}
public ZonedDateTime getLastUpdated() {
return lastUpdated;
}
}
인마이RestController
다음과 같은 것이 있습니다.
@RequestMapping("/devices/")
public @ResponseBody List<Device> index() {
List<Device> devices = new ArrayList<>();
devices.add(new Device("321421521", ZonedDateTime.now(), 0, 39.89011333, 24.438176666));
return devices;
}
난 기대했어ZonedDateTime
ISO 포맷에 따라 포맷됩니다만, 대신 다음과 같은 클래스의 JSON 덤프 전체를 가져옵니다.
"lastUpdated":{"offset":{"totalSeconds":7200,"id":"+02:00","rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]}},"zone":{"id":"Europe/Berlin","rules":{"fixedOffset":false,"transitionRules":[{"month":"MARCH","timeDefinition":"UTC","standardOffset":{"totalSeconds":3600,"id":"+01:00","rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]}},"offsetBefore":{"totalSeconds":3600,"id":"+01:00","rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]}},"offsetAfter":{"totalSeconds":7200,"id":"+02:00", ...
저는 그냥...spring-boot-starter-web
응용 프로그램, 사용spring-boot-starter-jetty
제외하다spring-boot-starter-tomcat
.
스프링 부츠에서 잭슨은 왜 이렇게 행동하지?
** 업데이트 **
이 문제를 해결하는 방법에 대한 자세한 가이드를 찾으시는 분들을 위해 다음 질문을 한 후 이 가이드를 찾았습니다.http://lewandowski.io/2016/02/formatting-java-time-with-spring-boot-using-json/
라이브러리 jackson-datatype-jsr310이 있습니다.먹어봐.
이 라이브러리에서는 새로운 datetime API에 대해 설명하며 의 시리얼라이저를 포함합니다.ZonedDateTime
너무.
추가만 하면 됩니다.JavaTimeModule
:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
갱신하다
datetime을 문자열로 변환하려면 기능을 비활성화해야 합니다.다음 중 하나를 덮어쓰면 쉽게 할 수 있습니다.ObjectMapper
bean 또는 응용 프로그램 속성 사용:
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false
Spring Boot의 자동 구성 기능에 의존하지 않는 경우,spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false
컨피규레이션파일에 속성을 저장합니다.또는 어떤 이유로 작성하든 상관없습니다.ObjectMapper
수동으로 인스턴스화 합니다.다음과 같이 이 기능을 프로그램적으로 디세블로 할 수 있습니다.
ObjectMapper m = new ObjectMapper();
m.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
이것은 잭슨을 위한 것이다.2.8.7
답변은 이미 위에서 언급되었지만 정보가 빠진 것 같습니다.Java 8 타임스탬프를 (ZonedDateTime뿐만 아니라) 다양한 형식으로 해석하려는 사용자용.의 최신 버전이 필요합니다.jackson-datatype-jsr310
다음 모듈을 등록합니다.
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
이 코드를 테스트하려면
@Test
void testSeliarization() throws IOException {
String expectedJson = "{\"parseDate\":\"2018-12-04T18:47:38.927Z\"}";
MyPojo pojo = new MyPojo(ZonedDateTime.parse("2018-12-04T18:47:38.927Z"));
// serialization
assertThat(objectMapper.writeValueAsString(pojo)).isEqualTo(expectedJson);
// deserialization
assertThat(objectMapper.readValue(expectedJson, MyPojo.class)).isEqualTo(pojo);
}
Spring 또는 drop wizard에서 오브젝트 맵퍼를 글로벌하게 설정할 수 있습니다.커스텀(디)시리얼라이저를 등록하지 않고 필드의 주석으로 이 작업을 수행할 수 있는 적절한 방법을 아직 찾지 못했습니다.
잭슨을 위해서2.10
그 이상은
부모 pom.xml
<!-- https://github.com/FasterXML/jackson-bom -->
<dependencyManagement>
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>2.10.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>
모듈 pom.xml
<!-- https://github.com/FasterXML/jackson-modules-java8 -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
JsonMapper 생성(아마도 사용자 이름에서)@Configuration
학급
@Bean
public JsonMapper jsonMapper() {
return JsonMapper.builder()
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
.addModule(new JavaTimeModule())
.build();
}
추가 정보:
설정spring.jackson.serialization.write-dates-as-timestamps=false
에서application.yml
우리 프로젝트에 도움이 되지 않는다.아마도 잭슨과 함께 작업하는 추가 라이브러리가 있을 것입니다.Swagger / OpenAPI / OpenAPI Generator.
해서 도움이 된 것은 이 '이러다', '이러다'를 입니다.@EventListener
★★★★★★★★★★★★★★★★의 경우RequestMappingHandlerAdapter
@SpringBootApplication
를 누릅니다
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
@SpringBootApplication
public class SpringBootInitializer {
@Autowired
private RequestMappingHandlerAdapter handlerAdapter;
public static void main(String[] args) {
SpringApplication.run(SpringBootInitializer.class, args);
}
@EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
// see https://github.com/FasterXML/jackson-modules-java8/issues/11#issuecomment-913199874
// spring.jackson.serialization.write-dates-as-timestamps=false setting does not work in our configuration (probably because of Swagger / OpenAPI / OpenAPI Generator libraries used)
handlerAdapter
.getMessageConverters()
.forEach(c -> {
if (c instanceof MappingJackson2HttpMessageConverter jsonMessageConverter) {
ObjectMapper objectMapper = jsonMessageConverter.getObjectMapper();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
});
}
}
이 솔루션은 https://github.com/FasterXML/jackson-modules-java8/issues/11#issuecomment-913199874에서 찾을 수 있습니다.
언급URL : https://stackoverflow.com/questions/39086472/jackson-serializes-a-zoneddatetime-wrongly-in-spring-boot
'code' 카테고리의 다른 글
AngularJs에서 ng-repeat으로 필터링(키, 값)하는 방법 (0) | 2023.02.12 |
---|---|
서비스/팩토리에서 컨트롤러로의 바인딩 변수 (0) | 2023.02.12 |
스프링 부트 1.3.0M1에서1.3.0으로 전환 시 "NoClassDefFoundError: GenericApplicationListener"M2 (0) | 2023.02.12 |
Rails는 빈 어레이를 요청 매개 변수에서 nil로 변환합니다. (0) | 2023.02.12 |
AngularJS: 컨트롤러에서 해결 기능을 사용할 경우 최소화할 수 있는 구문 수정 (0) | 2023.02.12 |