코덱 구성Spring Boot >= 2.0.1.REASE로 ZoneDateTime을 MongoDB에 저장할 때 예외 발생
MongoDB로 데이터 액세스를 위한 공식 스프링 부트 가이드를 최소한으로 수정하여 문제를 재현할 수 있었습니다. https://github.com/thokrae/spring-data-mongo-zoneddatetime 을 참조하십시오.
a를 추가java.time.ZonedDateTimeCustomer 클래스의 필드에서 가이드의 예제 코드를 실행하면 코덱 구성이 실패합니다.예외:
Customer.java:
public String lastName;
public ZonedDateTime created;
public Customer() {
출력:
...
Caused by: org.bson.codecs.configuration.CodecConfigurationException`: Can't find a codec for class java.time.ZonedDateTime.
at org.bson.codecs.configuration.CodecCache.getOrThrow(CodecCache.java:46) ~[bson-3.6.4.jar:na]
at org.bson.codecs.configuration.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:63) ~[bson-3.6.4.jar:na]
at org.bson.codecs.configuration.ChildCodecRegistry.get(ChildCodecRegistry.java:51) ~[bson-3.6.4.jar:na]
이 문제는 pom.xml에서 Spring Boot 버전을 2.0.5.REASE에서 2.0.1.REASE로 변경하여 해결할 수 있습니다.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
이제 예외가 사라지고 ZoneDateTime 필드를 포함한 Customer 개체가 MongoDB에 기록됩니다.
저는 스프링 데이터-몽고드 프로젝트에 버그(DATAAMONO-2106)를 제출했지만, 이 행동을 변경하는 것이 원하지 않거나 우선순위가 높은지 이해할 것입니다.
가장 좋은 해결 방법은 무엇입니까?Duckduck이 예외 메시지를 보낼 때 사용자 정의 코덱, 사용자 정의 변환기 또는 Jackson JSR 310을 사용하는 것과 같은 몇 가지 접근 방식을 발견합니다.java.time 패키지의 클래스를 처리하기 위해 프로젝트에 사용자 지정 코드를 추가하지 않습니다.
DATAMONO-2106에서 Oliver Drotbom이 직접 언급한 바와 같이, 표준 시간대가 있는 날짜 시간 유형을 유지하는 것은 Spring Data MongoDB에서 결코 지원되지 않았습니다.
알려진 해결 방법은 다음과 같습니다.
- 시간대가 없는 날짜 시간 유형(예: java.time)을 사용합니다.Instant. (일반적으로 백엔드에서만 UTC를 사용하는 것이 바람직하지만, 다른 접근 방식을 따르는 기존 코드 기반을 확장해야 했습니다.)
사용자 지정 변환기를 작성하고 AbstractMongoConfiguration을 확장하여 등록합니다.실행 예는 테스트 저장소의 분기 변환기를 참조하십시오.
@Component @WritingConverter public class ZonedDateTimeToDocumentConverter implements Converter<ZonedDateTime, Document> { static final String DATE_TIME = "dateTime"; static final String ZONE = "zone"; @Override public Document convert(@Nullable ZonedDateTime zonedDateTime) { if (zonedDateTime == null) return null; Document document = new Document(); document.put(DATE_TIME, Date.from(zonedDateTime.toInstant())); document.put(ZONE, zonedDateTime.getZone().getId()); document.put("offset", zonedDateTime.getOffset().toString()); return document; } } @Component @ReadingConverter public class DocumentToZonedDateTimeConverter implements Converter<Document, ZonedDateTime> { @Override public ZonedDateTime convert(@Nullable Document document) { if (document == null) return null; Date dateTime = document.getDate(DATE_TIME); String zoneId = document.getString(ZONE); ZoneId zone = ZoneId.of(zoneId); return ZonedDateTime.ofInstant(dateTime.toInstant(), zone); } } @Configuration public class MongoConfiguration extends AbstractMongoConfiguration { @Value("${spring.data.mongodb.database}") private String database; @Value("${spring.data.mongodb.host}") private String host; @Value("${spring.data.mongodb.port}") private int port; @Override public MongoClient mongoClient() { return new MongoClient(host, port); } @Override protected String getDatabaseName() { return database; } @Bean public CustomConversions customConversions() { return new MongoCustomConversions(asList( new ZonedDateTimeToDocumentConverter(), new DocumentToZonedDateTimeConverter() )); } }사용자 정의 코덱을 작성합니다.적어도 이론적으로는.내 코덱 테스트 브랜치는 스프링 부트 2.0.1과 정상적으로 작동하는 동안 스프링 부트 2.0.5를 사용할 때 데이터를 마샬링 해제할 수 없습니다.
public class ZonedDateTimeCodec implements Codec<ZonedDateTime> { public static final String DATE_TIME = "dateTime"; public static final String ZONE = "zone"; @Override public void encode(final BsonWriter writer, final ZonedDateTime value, final EncoderContext encoderContext) { writer.writeStartDocument(); writer.writeDateTime(DATE_TIME, value.toInstant().getEpochSecond() * 1_000); writer.writeString(ZONE, value.getZone().getId()); writer.writeEndDocument(); } @Override public ZonedDateTime decode(final BsonReader reader, final DecoderContext decoderContext) { reader.readStartDocument(); long epochSecond = reader.readDateTime(DATE_TIME); String zoneId = reader.readString(ZONE); reader.readEndDocument(); return ZonedDateTime.ofInstant(Instant.ofEpochSecond(epochSecond / 1_000), ZoneId.of(zoneId)); } @Override public Class<ZonedDateTime> getEncoderClass() { return ZonedDateTime.class; } } @Configuration public class MongoConfiguration extends AbstractMongoConfiguration { @Value("${spring.data.mongodb.database}") private String database; @Value("${spring.data.mongodb.host}") private String host; @Value("${spring.data.mongodb.port}") private int port; @Override public MongoClient mongoClient() { return new MongoClient(host + ":" + port, createOptions()); } private MongoClientOptions createOptions() { CodecProvider pojoCodecProvider = PojoCodecProvider.builder() .automatic(true) .build(); CodecRegistry registry = CodecRegistries.fromRegistries( createCustomCodecRegistry(), MongoClient.getDefaultCodecRegistry(), CodecRegistries.fromProviders(pojoCodecProvider) ); return MongoClientOptions.builder() .codecRegistry(registry) .build(); } private CodecRegistry createCustomCodecRegistry() { return CodecRegistries.fromCodecs( new ZonedDateTimeCodec() ); } @Override protected String getDatabaseName() { return database; } }
언급URL : https://stackoverflow.com/questions/52677253/codecconfigurationexception-when-saving-zoneddatetime-to-mongodb-with-spring-boo
'codememo' 카테고리의 다른 글
| JsonMappingException:java.lang의 인스턴스를 역직렬화할 수 없습니다.START_OBJECT 토큰의 정수가 벗어남 (0) | 2023.07.02 |
|---|---|
| Oracle에서 VARCHAR2의 크기가 1바이트로 선언된다는 것은 무엇을 의미합니까? (0) | 2023.06.27 |
| UnicodeError: 'charmap' 코덱을 인코딩할 수 없음 - 에 대한 문자 맵, 인쇄 함수 (0) | 2023.06.27 |
| 사용자가 이전 버전의 MS Office(MS Outlook)를 설치하여 Excel VBA 컴파일 오류를 방지합니까? (0) | 2023.06.27 |
| Oracle 문제의 매개 변수화된 쿼리 (0) | 2023.06.27 |