Jackson에서 사용하는 Annotation에 대해 정리한다. Baeldung (Jackson Annotation Example)에 정리된 글을 참고하였다.
1. Jackson Serialization Annotations
1.1 @JsonAnyGetter
Map 필드에 대해서 일반 properties로 처리한다
public class ExtendableBean {
private String name;
private Map<String, String> properties;
@JsonAnyGetter
public Map<String, String> getProperties() {
return properties;
}
}
/** @JsonAnyGetter 적용 전 */
{
"name" : "My bean",
"properties" : {
"attr2" : "val2",
"attr1" : "val1"
}
}
/** @JsonAnyGetter 적용 후 */
{
"name" : "My bean",
"attr2" : "val2",
"attr1" : "val1"
}
1.2 @JsonGetter
method에 대하여 value로 정한 필드의 getter로 지정한다. 아래의 예시는 getTheName() 메서드를 name 필드의 getter로 지정한 모습이다. 즉, serialization 과정에서 key=name의 value=getTheName()이다.
public class MyBean {
public int id;
private String name;
@JsonGetter("name")
public String getTheName() {
return name;
}
}
1.3 @JsonPropertyOrder
serialization 순서를 정의한다.
@JsonPropertyOrder({ "name", "id" })
public class MyBean {
public int id;
public String name;
}
/** @JsonPropertyOrder 적용 전 */
{
"id" : 1,
"name" : "My bean"
}
/** @JsonPropertyOrder 적용 후 */
{
"name" : "My bean",
"id" : 1
}
1.4 @JsonRawValue
메서드나 필드에 적용되며, 그 필드를 그대로 직렬화하여 JSON 값으로 여긴다.
public class RawBean {
public String name;
@JsonRawValue
public String json;
}
@Test
public void testJsonRawValue() throws JsonProcessingException {
RawBean rawBean = new RawBean("My bean", "{\"key\":\"value\",\"isTrue\":false}");
System.out.println(new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(rawBean));
}
/** @JsonRawValue 적용 전 */
{
"name" : "My bean",
"json" : "{\"key\":\"value\",\"isTrue\":false}"
}
/** @JsonRawValue 적용 후 */
{
"name" : "My bean",
"json" : {"key":"value","isTrue":false}
}
1.5 @JsonValue
하나의 인스턴스를 직렬화하는것에 있어 하나의 메서드를 지정하도록 한다. 아래의 예시는 Enum타입 TypeEnumWithValue을 직렬화 시 value로 getName() 메서드를 사용하도록 지정한 것이다.
public enum TypeEnumWithValue {
TYPE1(1, "Type A"), TYPE2(2, "Type 2");
private Integer id;
private String name;
TypeEnumWithValue(Integer id, String name) {
this.id = id;
this.name = name;
}
@JsonValue
public String getName() {
return name;
}
}
@Test
public void testJsonValue() throws JsonProcessingException {
System.out.println(new ObjectMapper().writeValueAsString(TypeEnumWithValue.TYPE1));
System.out.println(new ObjectMapper().writeValueAsString(TypeEnumWithValue.TYPE2));
}
/** 적용 전 */
"TYPE1"
"TYPE2"
/** @JsonValue 적용 후*/
"Type A"
"Type 2"
1.6 @JsonRootName
Class, Enum, Interface위에 선언되어 해당 클래스가 wrapping 될 수 있다면, value가 root wrapper로 처리되도록 한다. 이 애노테이션은 ObjectMapper에서도 함께 enable.(SerializationFeature.WRAP_ROOT_VALUE)를 처리해주어야 동작한다. 주의할 점은 ObjectMapper에서만 처리하고 @JsonRootName 애노테이션을 붙여주지 않는다면 기본으로 root wrapper는 클래스의 이름으로 처리가 된다 (이러한 처리는 깔끔하지 못하다).
@JsonRootName(value = "user")
public class UserWithRoot {
public int id;
public String name;
}
@Test
public void testJsonRootName() throws JsonProcessingException {
UserWithRoot userWithRoot = new UserWithRoot(1, "changwoo.son");
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE); // enable wrapping
System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(userWithRoot));
}
/** @JsonRootName, SerializationFeature.WRAP_ROOT_VALUE 적용 전 */
{
"id" : 1,
"name" : "changwoo.son"
}
/** @JsonRootName 적용 전, SerializationFeature.WRAP_ROOT_VALUE 적용 후 */
{
"UserWithRoot" : {
"id" : 1,
"name" : "changwoo.son"
}
}
/** @JsonRootName, SerializationFeature.WRAP_ROOT_VALUE 적용 후 */
{
"user" : {
"id" : 1,
"name" : "changwoo.son"
}
}
1.7 @JsonSerialize
marshalling 과정에 custom serializer를 사용하도록 지정한다.
marshalling과 serialization은 차이가 있다. serialization은 객체를 byte stream으로 변환하는 것 만을 의미한다. 이에 반해 marshalling은 객체를 저장이나 전송을 위해 적당한 자료 형태로 변형하는 것을 의미한다.
Jackson 라이브러리의 StdSerializer를 상속하여 custom serializer를 만들 수 있다.
아래의 예시에선 Date 객체를 CustomDateSerializer를 이용하여 직렬화하도록 지정해주었다.
public class EventWithSerializer {
public String name;
@JsonSerialize(using = CustomDateSerializer.class)
public Date eventDate;
}
public class CustomDateSerializer extends StdSerializer<Date> {
private static SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
public CustomDateSerializer() {
this(null);
}
public CustomDateSerializer(Class<Date> t) {
super(t);
}
@Override
public void serialize(Date value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeString(formatter.format(value));
}
}
@Test
public void testJsonSerialize() throws JsonProcessingException, ParseException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String toParse = "2020-09-10 01:23:45";
Date date = format.parse(toParse);
EventWithSerializer event = new EventWithSerializer("party", date);
System.out.println(new ObjectMapper().writeValueAsString(event));
}
/** @JsonSerialize 적용 전 */
{
"name" : "party",
"eventDate" : 1599668625000
}
/** @JsonSerialize 적용 후 */
{
"name" : "party",
"eventDate" : "2020-09-10 01:23:45"
}