Java 8 LocalDate Jackson 형식
java.util의 경우.할 때 날짜
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy")
private Date dateOfBirth;
JSON 요청으로 보내드립니다.
{ {"dateOfBirth":"01/01/2000"} }
그건 효과가 있다.
Java 8의 LocalDate 필드에 대해 어떻게 해야 합니까?
제가 한번 해봤는데
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate dateOfBirth;
효과가 없었어요.
누가 어떻게 하면 좋을지 좀 알려주시겠어요?
의존관계는 다음과 같습니다.
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>jaxrs-api</artifactId>
<version>3.0.9.Final</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>com.wordnik</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.3.10</version>
</dependency>
주석을 사용하여 간단하게 조작할 수 없었습니다.이 기능을 수행하기 위해ObjectMapper
그리고 나서,JSR310Module
(갱신: 현재는 갱신되었습니다).또한 경고는 write-date-as-filse를 false로 설정해야 한다는 것입니다.자세한 내용은 JSR310 모듈의 매뉴얼을 참조하십시오.여기 제가 사용한 것의 예가 있습니다.
의존
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.4.0</version>
</dependency>
주의: 이 문제에 직면한 한 가지 문제는jackson-annotation
다른 종속성(사용 버전 2.3.2)에 의해 풀인된 버전은 에 필요한 2.4를 취소했습니다.jsr310
어떻게 된 거죠?NoClassDefFound를 취득했습니다ObjectIdResolver
2.4 클래스입니다.따라서 포함된 종속 버전만 나열하면 됩니다.
콘텍스트 리졸버
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JSR310Module;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper MAPPER;
public ObjectMapperContextResolver() {
MAPPER = new ObjectMapper();
// Now you should use JavaTimeModule instead
MAPPER.registerModule(new JSR310Module());
MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
}
@Override
public ObjectMapper getContext(Class<?> type) {
return MAPPER;
}
}
자원 클래스
@Path("person")
public class LocalDateResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getPerson() {
Person person = new Person();
person.birthDate = LocalDate.now();
return Response.ok(person).build();
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response createPerson(Person person) {
return Response.ok(
DateTimeFormatter.ISO_DATE.format(person.birthDate)).build();
}
public static class Person {
public LocalDate birthDate;
}
}
시험
curl -v http://localhost:8080/api/person
결과:{"birthDate":"2015-03-01"}
curl -v -POST -H "Content-Type:application/json" -d "{\"birthDate\":\"2015-03-01\"}" http://localhost:8080/api/person
결과:2015-03-01
JAXB 솔루션에 대해서는, 여기를 참조해 주세요.
갱신하다
그JSR310Module
Jackson 버전 2.7에서는 권장되지 않습니다.대신 모듈을 등록해야 합니다.JavaTimeModule
그것은 여전히 같은 의존관계입니다.
@JsonSerialize와 @JsonDeserialize는 정상적으로 동작했습니다.따라서 추가 jsr310 모듈을 Import할 필요가 없습니다.
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate dateOfBirth;
디시리얼라이저:
public class LocalDateDeserializer extends StdDeserializer<LocalDate> {
private static final long serialVersionUID = 1L;
protected LocalDateDeserializer() {
super(LocalDate.class);
}
@Override
public LocalDate deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
return LocalDate.parse(jp.readValueAs(String.class));
}
}
시리얼라이저:
public class LocalDateSerializer extends StdSerializer<LocalDate> {
private static final long serialVersionUID = 1L;
public LocalDateSerializer(){
super(LocalDate.class);
}
@Override
public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider sp) throws IOException, JsonProcessingException {
gen.writeString(value.format(DateTimeFormatter.ISO_LOCAL_DATE));
}
}
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
잭슨과 JSR 310 버전 '2.8.5'를 탑재한 Spring Boot 웹 앱
compile "com.fasterxml.jackson.core:jackson-databind:2.8.5"
runtime "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.5"
그@JsonFormat
동작:
import com.fasterxml.jackson.annotation.JsonFormat;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate birthDate;
가장 심플한 솔루션(디시리얼라이제이션과 시리얼라이제이션도 지원)은 다음과 같습니다.
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy")
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate dateOfBirth;
프로젝트에서 다음과 같은 종속성을 사용하는 동안.
메이븐
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.9.7</version>
</dependency>
그라들
compile "com.fasterxml.jackson.core:jackson-databind:2.9.7"
compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.7"
Context Resolver, Serializer 또는 Deserializer 추가 구현은 필요하지 않습니다.
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime createdDate;
부터LocalDateSerializer
디폴트로는 "year-month-day"(json 문자열)가 아닌 "year, month, day"(json 배열)로 변환됩니다.특별한 것은 필요 없습니다.ObjectMapper
셋업(사용할 수 있습니다)LocalDateSerializer
비활성화 시 문자열 생성SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
단, 이 경우 추가 셋업이 필요합니다.ObjectMapper
, 다음을 사용합니다.
Import:
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
코드:
// generates "yyyy-MM-dd" output
@JsonSerialize(using = ToStringSerializer.class)
// handles "yyyy-MM-dd" input just fine (note: "yyyy-M-d" format will not work)
@JsonDeserialize(using = LocalDateDeserializer.class)
private LocalDate localDate;
그리고 이제 난 그냥 쓸 수 있어new ObjectMapper()
특별한 설정 없이 객체를 읽고 쓸 수 있습니다.
지금까지의 가장 심플하고 최단:
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate localDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;
Spring Boot > = 2.2+의 경우 종속성이 필요 없음
다음 주석은 나에게 잘 작동했다.
추가 종속성은 필요하지 않습니다.
@JsonProperty("created_at")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime createdAt;
크리스토퍼의 답변에 대한 최신 정보입니다.
버전 2.6.0 이후
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.9.0</version>
</dependency>
JSR310 Module 대신 Java Time Module을 사용합니다(권장되지 않음).
@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper MAPPER;
public ObjectMapperContextResolver() {
MAPPER = new ObjectMapper();
MAPPER.registerModule(new JavaTimeModule());
MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
}
@Override
public ObjectMapper getContext(Class<?> type) {
return MAPPER;
}
}
매뉴얼에 따르면 새로운 Java Time Module은 타임존 ID를 사용하지 않는 시리얼라이제이션에 동일한 표준 설정을 사용하고 대신 ISO-8601에 준거한 타임존 오프셋만 사용합니다.
동작은 Serialization Feature를 사용하여 변경할 수 있습니다.WRITE_DATES_ZONE_ID 포함
https://stackoverflow.com/a/53251526/1282532 는 속성을 시리얼화/디시리얼라이즈 하는 가장 간단한 방법입니다.저는 이 접근법에 대해 두 가지 우려가 있습니다. 어느 정도 DRY 원칙 위반과 pojo와 mapper의 높은 결합입니다.
public class Trade {
@JsonFormat(pattern = "yyyyMMdd")
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate tradeDate;
@JsonFormat(pattern = "yyyyMMdd")
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate maturityDate;
@JsonFormat(pattern = "yyyyMMdd")
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate entryDate;
}
여러 LocalDate 필드가 있는 POJO의 경우 POJO 대신 매퍼를 설정하는 것이 좋습니다.ISO-8601 값("2019-01-31")을 사용하는 경우 https://stackoverflow.com/a/35062824/1282532처럼 간단할 수 있습니다.
커스텀 포맷을 취급할 필요가 있는 경우는, 코드는 다음과 같습니다.
ObjectMapper mapper = new ObjectMapper();
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyyMMdd")));
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyyMMdd")));
mapper.registerModule(javaTimeModule);
논리는 한 번만 작성되므로 여러 POJO에 재사용할 수 있습니다.
2020년 및 Jackson 2.10.1 시점에서는 특별한 코드가 필요 없으며, Jackson에게 원하는 것을 말하면 됩니다.
ObjectMapper objectMapper = new ObjectMapper();
// Register module that knows how to serialize java.time objects
// Provided by jackson-datatype-jsr310
objectMapper.registerModule(new JavaTimeModule());
// Ask Jackson to serialize dates as String (ISO-8601 by default)
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
이는 이미 이 답변에 언급되어 있습니다.기능을 검증하는 유닛테스트를 추가합니다.
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.Data;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class LocalDateSerializationTest {
@Data
static class TestBean {
// Accept default ISO-8601 format
LocalDate birthDate;
// Use custom format
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy")
LocalDate birthDateWithCustomFormat;
}
@Test
void serializeDeserializeTest() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
// Register module that knows how to serialize java.time objects
objectMapper.registerModule(new JavaTimeModule());
// Ask Jackson to serialize dates as String (ISO-8601 by default)
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// The JSON string after serialization
String json = "{\"birthDate\":\"2000-01-02\",\"birthDateWithCustomFormat\":\"03/02/2001\"}";
// The object after deserialization
TestBean object = new TestBean();
object.setBirthDate(LocalDate.of(2000, 1, 2));
object.setBirthDateWithCustomFormat(LocalDate.of(2001, 2, 3));
// Assert serialization
assertEquals(json, objectMapper.writeValueAsString(object));
// Assert deserialization
assertEquals(object, objectMapper.readValue(json, TestBean.class));
}
}
TestBean은 Lombok을 사용하여 콩의 보일러 플레이트를 생성합니다.
컨피규레이션클래스에서 LocalDateSerializer 및 LocalDateDeserializer 클래스를 정의하고 다음과 같이 JavaTimeModule을 통해 ObjectMapper에 등록합니다.
@Configuration
public class AppConfig
{
@Bean
public ObjectMapper objectMapper()
{
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON_EMPTY);
//other mapper configs
// Customize de-serialization
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer());
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer());
mapper.registerModule(javaTimeModule);
return mapper;
}
public class LocalDateSerializer extends JsonSerializer<LocalDate> {
@Override
public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(value.format(Constant.DATE_TIME_FORMATTER));
}
}
public class LocalDateDeserializer extends JsonDeserializer<LocalDate> {
@Override
public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
return LocalDate.parse(p.getValueAsString(), Constant.DATE_TIME_FORMATTER);
}
}
}
스프링 부츠 2.3.9 탑재.릴리즈, 방금 POJO 클래스에 명시적 주석이 없는 자바 타임 모듈을 LocalDate 필드가 있는 상태로 등록했는데 작동했습니다.
var objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
봄을 위해 조금 더 쉽게:
///...
@Configuration
public class ApplicationCtxBeans {
//....
@Bean
public ObjectMapper objectMapper() {
ObjectMapper MAPPER = new ObjectMapper();
MAPPER.registerModule(new JavaTimeModule()); // to handle LocalDateTime etc
return MAPPER;
}
//...
}
사용방법:
@Service
public class SomeService {
//...
@Autowired
ObjectMapper jsonMapper;
//...
JsonNode node = jsonMapper.readTree(
jsonMapper.writeValueAsString(instance_Of_Class_With_LocalDate_Fields)
);
//...
}
요청에 다음과 같은 개체가 포함되어 있는 경우:
{
"year": 1900,
"month": 1,
"day": 20
}
다음으로 다음을 사용할 수 있습니다.
data class DateObject(
val day: Int,
val month: Int,
val year: Int
)
class LocalDateConverter : StdConverter<DateObject, LocalDate>() {
override fun convert(value: DateObject): LocalDate {
return value.run { LocalDate.of(year, month, day) }
}
}
필드 위:
@JsonDeserialize(converter = LocalDateConverter::class)
val dateOfBirth: LocalDate
코드는 Kotlin에 있지만, Java에서도 물론 동작합니다.
추가 종속성을 사용하지 않고 Pojo에서 주석 지정
@DateTimeFormat (pattern = "yyyy/MM/dd", iso = DateTimeFormat.ISO.DATE)
private LocalDate enddate;
언급URL : https://stackoverflow.com/questions/28802544/java-8-localdate-jackson-format
'programing' 카테고리의 다른 글
채워진 원을 그리는 빠른 알고리즘? (0) | 2022.09.01 |
---|---|
스테이트먼트와 Prepared 스테이트먼트의 차이 (0) | 2022.09.01 |
vuex에서 데이터 분리 (0) | 2022.09.01 |
Java에 상수 기능이 없는 이유는 무엇입니까? (0) | 2022.09.01 |
컴파일러가 세미콜론을 찾을 수 없는 이유는 무엇입니까? (0) | 2022.09.01 |