source

Jackson을 사용하여 Instant를 ISO8601로 직렬화할 때 강제로 밀리초

ittop 2023. 7. 21. 21:55
반응형

Jackson을 사용하여 Instant를 ISO8601로 직렬화할 때 강제로 밀리초

제가 사용하는 프로젝트에서 잭슨을 사용한 JSON 연재와 관련하여 몇 가지 질문이 있습니다.Spring Boot 2.0.0.M6,Spring Framework 5.0.1.RELEASE그리고.Jackson 2.9.2.

에서 다음과 같은 잭슨 관련 설정을 구성했습니다.application.properties:

spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false

직렬화는 대부분 필요에 따라 작동합니다.그럼에도 불구하고, 나는 잭슨이 만약 그들이 그렇다면 밀리초를 잘라내는 것처럼 보인다는 것을 알아챘습니다.000.

테스트 1: 밀리초로 설정된 인스턴트 직렬화000:

  • 다음을 사용하여 인스턴트 필드 초기화Instant.parse("2017-09-14T04:28:48.000Z")
  • 잭슨을 사용하여 일련화
  • 출력은 다음과 같습니다."2017-09-14T04:28:48Z"

테스트 2: 밀리초가 아닌 일부로 설정된 인스턴트 직렬화000값:

  • 다음을 사용하여 인스턴트 필드 초기화Instant.parse("2017-09-14T04:28:48.100Z")
  • 잭슨을 사용하여 일련화
  • 출력은 다음과 같습니다."2017-09-14T04:28:48.100Z"

질문:

  • 의도적으로 그런 행동을 한 건가요?
  • 제가 할 수 있는 일이 있습니까?000?

다음 방법을 사용하여 해결합니다.

ObjectMapper objectMapper = new ObjectMapper();
JavaTimeModule module = new JavaTimeModule();
module.addSerializer(Instant.class, new InstantSerializerWithMilliSecondPrecision());
objectMapper.registerModule(module);

또한 Instant Serializer의 경우MilliSecond Precision에서는 다음을 사용했습니다.

public class InstantSerializerWithMilliSecondPrecision extends InstantSerializer {

    public InstantSerializerWithMilliSecondPrecision() {
        super(InstantSerializer.INSTANCE, false, new DateTimeFormatterBuilder().appendInstant(3).toFormatter());
    }
}

이제 인스턴트 직렬화에는 항상 밀리초가 포함됩니다.예: 2019-09-27T02:59:59.000Z

여기에는 에 대한 Jackson 문제가 열려 있는 것 같습니다*.해당 링크에는 두 가지 해결 방법이 있습니다.

해결 방법 1

 ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new JavaTimeModule());
    SimpleModule module = new SimpleModule();
    module.addSerializer(ZonedDateTime.class, new JsonSerializer<ZonedDateTime>() {
        @Override
        public void serialize(ZonedDateTime zonedDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
            jsonGenerator.writeString(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZZ").format(zonedDateTime));
        }
    });
    objectMapper.registerModule(module);
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    objectMapper.enable(SerializationFeature.INDENT_OUTPUT);

해결 방법 2

JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(ZonedDateTime.class,
  new ZonedDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")));
ObjectMapper mapper = new ObjectMapper().registerModule(javaTimeModule);

*FasterX를 사용하지 않아 링크가 중단되었습니다.ML/jackson-datatype-jsr310을 jackson-modules-java8로 이동했습니다.https://github.com/FasterXML/jackson-modules-java8/issues/76 을 참조하십시오.

Spring Boot에서 이것을 시도하고 있고 @Gustavo의 대답을 사용하고 싶다면.

import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public Module javaTimeModule() {
        JavaTimeModule module = new JavaTimeModule();
        module.addSerializer(new InstantSerializerWithMilliSecondPrecision());
        return module;
    }

}

션 캐롤이 언급한 두 가지 해결책 중 어느 것도 저에게는 통하지 않습니다.저는 결국 Instant를 위한 저만의 연재물을 작성하게 됩니다.

final ObjectMapper mapper = new ObjectMapper();
final JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(Instant.class, new KeepMillisecondInstantSerializer());
mapper.registerModule(javaTimeModule);

public class KeepMillisecondInstantSerializer extends JsonSerializer<Instant> {

    private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")
            .withZone(ZoneId.of("UTC"));

    @Override
    public void serialize(final Instant instant, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) throws IOException {
        final String serializedInstant = dateTimeFormatter.format(instant);
        jsonGenerator.writeString(serializedInstant);
    }
}

잭슨은 기본적으로 인스턴트 객체를 직렬화하는 방법을 사용하는 것 같습니다.또한 StackOverflow에서 메서드에 대한 몇 가지 논의를 발견했습니다.

Jackson 라이브러리의 버그를 수정하는 대신 다음과 같은 간단한 해결 방법이 있을 수 있습니다. Timestamp 변수가 있는 POJO 클래스에 문자열 변수를 만듭니다.

private Timestamp createTimeStamp;

private String stringCreateTimeStamp;   

타임스탬프 값을 문자열로 캡처:

listOfPojo.forEach(pojo-> {
            pojo.setStringCreateTimeStamp(request.getcreateTimeStamp().toString());
        });

변환은 https://www.baeldung.com/java-string-to-timestamp 를 참조하십시오.

LocalDateTimeZoneDateTime 클래스에 대한 사용자 지정 직렬화 프로그램을 사용하여 문제를 해결합니다.

API 응답에서 날짜와 시간을 나타내기 위해 이 두 클래스만 사용하기 때문에 제 솔루션은 제게 적합합니다!저는 인스턴트나 날짜를 사용하지 않으니 주의하세요.

@Configuration
class JacksonConfig {

@Bean
fun objectMapper(): ObjectMapper {
    val mapper = ObjectMapper()
    val javaTimeModule = JavaTimeModule().apply {
        addSerializer(LocalDateTime::class.java, KeepMillisecondLocalDateTimeSerializer())
        addSerializer(ZonedDateTime::class.java, KeepMillisecondZonedDateTimeSerializer())
    }
    mapper.registerModule(javaTimeModule)
    return mapper
}

class KeepMillisecondZonedDateTimeSerializer : JsonSerializer<ZonedDateTime>() {
    private val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")

    @Throws(IOException::class)
    override fun serialize(
        value: ZonedDateTime,
        jsonGenerator: JsonGenerator,
        serializerProvider: SerializerProvider?
    ) {
        jsonGenerator.writeString(formatter.format(value))
    }
}

class KeepMillisecondLocalDateTimeSerializer : JsonSerializer<LocalDateTime>() {
    private val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")

    @Throws(IOException::class)
    override fun serialize(
        value: LocalDateTime,
        jsonGenerator: JsonGenerator,
        serializerProvider: SerializerProvider?
    ) {
        jsonGenerator.writeString(formatter.format(value))
    }
}
}

언급URL : https://stackoverflow.com/questions/47502158/force-milliseconds-when-serializing-instant-to-iso8601-using-jackson

반응형