JodaTime 과 jackson json library 연동
설정
JodaTime 의 DateTime 클래스와 jackson 을 연동하여 사용하는 방법
public class User {
private Long id;
private String name;
private DateTime created_at;
};
CODE
maven pom 설정
<properties>
<jackson.version>2.4.4</jackson.version>
</properties>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
CODE
Spring 연동
Spring3.2.x DateTimeFormat annotation 참고
Serialize
JsonSerialize annotation 을 도메인에 기술
@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class User {
private Long id;
private String name;
@JsonSerialize(using=DateTimeSerializer.class)
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss", timezone="Asia/Seoul")
private DateTime createdAt;
};
CODE
User u = new User();
u.setId(1L);
u.setName("TestUser");
u.setCreatedAt(new DateTime());
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false);
mapper.writeValue(new File("user.json"), u);
CODE
DateTime 을 Serialize 할경우 다음 옵션이 추가되지 않으면 아래와 같이 불필요한 정보가 많이 추가된다.
mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
CODE
{
"created_at": {
"weekyear": 2015,
"monthOfYear": 4,
"yearOfCentury": 15,
"centuryOfEra": 20,
"millisOfSecond": 289,
"millisOfDay": 28518289,
"secondOfMinute": 18,
"secondOfDay": 28518,
"minuteOfHour": 55,
"minuteOfDay": 475,
"weekOfWeekyear": 15,
"yearOfEra": 2015,
"hourOfDay": 7,
"year": 2015,
"dayOfMonth": 10,
"dayOfWeek": 5,
"era": 1,
"dayOfYear": 100,
"chronology": {
"zone": {
"fixed": false,
"uncachedZone": {
"fixed": false,
"cachable": true,
"id": "Asia/Seoul"
},
"id": "Asia/Seoul"
}
},
"millis": 1428620118289,
"zone": {
"fixed": false,
"uncachedZone": {
"fixed": false,
"cachable": true,
"id": "Asia/Seoul"
},
"id": "Asia/Seoul"
},
"afterNow": false,
"beforeNow": true,
"equalNow": false
}
}
CODE
기본 시간 형식은 ISO 형식(2004-12-13T21:39:45.618-08:00) 이므로 @JsonFormat 으로 DateTime 형식을 기술해 준다.
DeSerialize
{
"id": 1,
"name": "TestUser",
"createdAt": "2014-01-09 23:59:59"
}
CODE
위와 같이 json encoding 된 DateTime 을 DeSerialize 할 경우 ISO 형식이 아니므로 예외가 발생한다.
ObjectMapper mapper = new ObjectMapper();
User u = mapper.readValue(new File("user.json"), User.class);
CODE
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class org.joda.time.DateTime] from String value ('2014-01-09 23:59:59'); no single-String constructor/factory method
at [Source: status.json; line: 3, column: 9] (through reference chain: com.example.User["createdAt"]->com.example.User["createdAt"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:770)
at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:277)
at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:289)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1141)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:135)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:126)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:538)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:99)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:238)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:118)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:538)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:99)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:238)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:118)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3066)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2115)
CODE
ISO 형식이 아닌 DateTime 을 파싱하기 위해서는 커스텀 DeSerializer 를 만들어야 한다.
public class CustomDateTimeDeserializer extends JsonDeserializer<DateTime> {
private static DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
@Override
public DateTime deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
String date = jp.getText();
return formatter.parseDateTime(date);
}
}
CODE
@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class User {
private Long id;
private String name;
@JsonSerialize(using=DateTimeSerializer.class)
@JsonDeserialize(using=CustomDateTimeDeserializer.class)
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss", timezone="Asia/Seoul")
private DateTime createdAt;
};
CODE
다시 다음 코드를 실행하면 정상적으로 동작할 것이다.
ObjectMapper mapper = new ObjectMapper();
User u = mapper.readValue(new File("user.json"), User.class);
CODE
JDBC 연동
JDBC 나 spring 의 JDBCTemplate 등에서 Joda Time 의 DateTime 클래스를 사용하려면 toDate() 로 java 의 Date 형식으로 변환해 주어야 함.( IterableNamedParameterJdbcTemplate 라이브러리는 https://github.com/alexkasko/springjdbc-iterable 참고).
IterableNamedParameterJdbcTemplate jdbcTemplate = iterableNamedParameterJdbcTemplate;
DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
DateTime from = dtf.parseDateTime("2014-01-01 00:00:00");
DateTime to = dtf.parseDateTime("2014-03-31 23:59:59");
SqlParameterSource parameters = new MapSqlParameterSource()
.addValue("from", from.toDate())
.addValue("to", to.toDate())
;
List<User> list = jdbcTemplate.query(
"select * from USERS WHERE created_at > :from and created_at < :to ",
parameters,
new BeanPropertyRowMapper(User.class));
CODE