아래 내용은 baeldung에 있는 내용을 정리한 것이다. (https://www.baeldung.com/jackson-annotations)
1. Jackson Serialization Annotation
1.1. @JsonAnyGetter
@JsonAnyGetter
어노테이션은 맵을 기본 필드로 동작하게 한다.
예를 들면, ExtendableBean은 name과 key/value 의 값을 가진 속성들로 구성되어 있다.
public class ExtendableBean {
public String name;
private Map<String, String> properties;
public static void main(String[] args) {
ExtendableBean bean = new ExtendableBean("My Bean");
bean.add("attr1", "val1");
bean.add("attr2", "val2");
System.out.println(bean.toString());
}
}
기본적으로 위의 객체를 직렬화하면 아래와 같이 나타날 것이다.
{"name":"My Bean","properties":{"attr2":"val2","attr1":"val1"}}
하지만 @JsonAnyGetter
를 사용하면 Map이 필드 속성으로 직렬화된다.
public class ExtendableBean {
public String name;
private Map<String, String> properties;
public ExtendableBean(String name) {
this.name = name;
this.properties = new HashMap<>();
}
@JsonAnyGetter
public Map<String, String> getProperties() {
return properties;
}
public static void main(String[] args) {
ExtendableBean bean = new ExtendableBean("My Bean");
bean.add("attr1", "val1");
bean.add("attr2", "val2");
System.out.println(bean.toString());
}
}
결과
{"name":"My Bean","attr2":"val2","attr1":"val1"}
1.2. @JsonGetter
@JsonGetter
는 getter 메소드를 나타내는 @JsonProperty
의 대안이다.
아래 예를 보자.
@AllArgsConstructor
public class MyBean {
public int id;
private String name;
public String getTheName() {
return name;
}
public static void main(String[] args) throws JsonProcessingException {
MyBean bean = new MyBean(123, "홍길동");
String result = new ObjectMapper().writeValueAsString(bean);
System.out.println(result); // {"id":123,"theName":"홍길동"}
}
}
MyBean을 직렬화하면 name은 theName 필드로 직렬화된다.
theName을 name으로 변경하고자 하면 @JsonGetter
를 사용하면 된다.
@AllArgsConstructor
public class MyBean {
public int id;
private String name;
@JsonGetter("name")
public String getTheName() {
return name;
}
public static void main(String[] args) throws JsonProcessingException {
MyBean bean = new MyBean(123, "홍길동");
String result = new ObjectMapper().writeValueAsString(bean);
System.out.println(result); // {"id":123,"name":"홍길동"}
}
}
1.3. @JsonPropertyOrder
직렬화할 때 프로퍼티의 순서를 명시하고자 할 때 @JsonPropertyOrder
를 사용할 수 있다.
@AllArgsConstructor
@Getter
public class MyBeanOrder {
private int id;
private String name;
private String address;
public static void main(String[] args) throws JsonProcessingException {
MyBeanOrder bean = new MyBeanOrder(123, "홍길동", "서울");
String result = new ObjectMapper().writeValueAsString(bean);
System.out.println(result); // {"id":123,"name":"홍길동","address":"서울"}
}
}
위의 같이 필드의 순서대로 직렬화가 된다. // {"id":123,"name":"홍길동","address":"서울"}
순서를 변경하려면 아래와 같이 @JsonPropertyOrder
를 사용하면 된다.
@AllArgsConstructor
@Getter
@JsonPropertyOrder({ "name", "address", "id" })
public class MyBeanOrder {
private int id;
private String name;
private String address;
public static void main(String[] args) throws JsonProcessingException {
MyBeanOrder bean = new MyBeanOrder(123, "홍길동", "서울");
String result = new ObjectMapper().writeValueAsString(bean);
System.out.println(result); // {"name":"홍길동","address":"서울","id":123}
}
}
1.4. @JsonRawValue
@JsonRawValue
어노테이션은 jackson으로 하여금 속성 그대로 직렬화하게 한다.
@AllArgsConstructor
@Getter
public class RawBean {
private String name;
public String json;
public static void main(String[] args) throws JsonProcessingException {
RawBean bean = new RawBean("My bean", "{\"attr\":false}");
String result = new ObjectMapper().writeValueAsString(bean);
System.out.println(result); // {"name":"My bean","json":"{\"attr\":false}"}
}
}
위와 같이 json은 하나의 문자열로 직렬화가 된다.
하지만 json이 json문자열 형태로 직렬화하고 싶다면 아래와 같이 @JsonRawValue
를 사용하면 된다.
@AllArgsConstructor
@Getter
public class RawBean {
private String name;
@JsonRawValue
public String json;
public static void main(String[] args) throws JsonProcessingException {
RawBean bean = new RawBean("My bean", "{\"attr\":false}");
String result = new ObjectMapper().writeValueAsString(bean);
System.out.println(result); // {"name":"My bean","json":{"attr":false}}
}
}
@JsonRawValue
를 사용하면 json값이 json형태로 직렬화가 된다.
1.5. @JsonValue
@JsonValue
는 특정 필드를 직렬화할 때 사용한다.
public enum TypeEnumWithValue {
TYPE1(1, "Type A"), TYPE2(2, "Type 2");
private Integer id;
private String name;
TypeEnumWithValue(int id, String name) {
this.id = id;
this.name = name;
}
public static void main(String[] args) throws JsonProcessingException {
TypeEnumWithValue typeEnumWithValue = TypeEnumWithValue.TYPE1;
String result = new ObjectMapper().writeValueAsString(typeEnumWithValue);
System.out.println(result); // "TYPE1"
}
}
위의 TypeEnumWithValue를 직렬화하면 TYPE1의 enum이 출력된다.
위에서 name이 출력되게 하고 싶다면 @JsonValue
를 사용하면 된다.
public enum TypeEnumWithValue {
TYPE1(1, "Type A"), TYPE2(2, "Type 2");
private Integer id;
private String name;
@JsonValue
public String getName() {
return name;
}
TypeEnumWithValue(int id, String name) {
this.id = id;
this.name = name;
}
public static void main(String[] args) throws JsonProcessingException {
TypeEnumWithValue typeEnumWithValue = TypeEnumWithValue.TYPE1;
String result = new ObjectMapper().writeValueAsString(typeEnumWithValue);
System.out.println(result); // "Type A"
}
}
1.6. @JsonRootName
상위 래퍼의 이름을 명시하고자 할 때 @JsonRootName
어노테이션이 사용된다.
@Getter
@AllArgsConstructor
public class UserWithRoot {
public int id;
public String name;
public static void main(String[] args) throws JsonProcessingException {
UserWithRoot root = new UserWithRoot(123, "홍길동");
String result = new ObjectMapper().writeValueAsString(root);
System.out.println(result); // {"id":123,"name":"홍길동"}
}
}
위의 UserWithRoot를 직렬화하면 {"id":123,"name":"홍길동"}으로 직렬화되지만 상위에 특정 이름을 부여하고 싶다면 아래와 같이 @JsonRootName
을 사용하면 된다.
@Getter
@AllArgsConstructor
@JsonRootName(value = "user")
public class UserWithRoot {
public int id;
public String name;
public static void main(String[] args) throws JsonProcessingException {
UserWithRoot root = new UserWithRoot(123, "홍길동");
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE); // WRAP_ROOT_VALUE 설정을 해줘야 함
String result = mapper.writeValueAsString(root);
System.out.println(result); // {"user":{"id":123,"name":"홍길동"}}
}
}
2. Jackson Deserialization Annotation
2.1 @JsonCreator
역직렬화할 때 생성자/팩토리를 조정할 때 @JsonCreator
를 사용할 수 있다.
다음과 같은 JSON형태로 역직렬화할 필요가 있다고 하자.
{
"id":1,
"theName":"My bean"
}
하지만, 필드에 theName은 없고 name필드가 있다. 필드 자체를 수정하고 싶지 않고 단지 @JsonCreator
를 통해서만 사용하고 싶다.
@Getter
public class BeanWithCreator {
private int id;
private String name;
@JsonCreator
public BeanWithCreator(
@JsonProperty("id") int id,
@JsonProperty("theName") String name
) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws JsonProcessingException {
String json = "{\"id\":1,\"theName\":\"My bean\"}";
BeanWithCreator bean = new ObjectMapper().readerFor(BeanWithCreator.class).readValue(json);
System.out.println(bean.toString());
}
}
2.2 @JacksonInject
@JacksonInject
는 필드가 JSON 데이터가 아니라 주입된 값임을 알려준다.
@Getter
public class BeanWithInject {
//@JacksonInject
private int id;
private String name;
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws JsonProcessingException {
String json = "{\"name\":\"My bean\"}";
InjectableValues inject = new InjectableValues.Std()
.addValue(int.class, 1);
BeanWithInject bean = new ObjectMapper().reader(inject)
.forType(BeanWithInject.class)
.readValue(json);
System.out.println(bean.toString());
}
}
위 코드를 실행할 때 @JacksonInject
가 있는 경우와 없는 경우의 결과는 아래와 같다.
없는 경우
{"id":0,"name":"My bean"}
있는 경우
{"id":1,"name":"My bean"}
2.3 @JsonAnySetter
@JsonAnySetter
는 Map을 기본 프로퍼티로 사용할 수 있게 한다. 역직렬화할 때 JSON의 프로퍼티는 단순히 맵(Map)에 추가될 것이다.
@Getter
public class ExtendableBean {
private String name;
private Map<String, String> properties = new HashMap<>();
@JsonAnySetter
public void add(String key, String value) {
this.properties.put(key, value);
}
@JsonAnyGetter
public Map<String, String> getProperties() {
return properties;
}
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws JsonProcessingException{
String json = "{\"name\":\"My bean\",\"attr2\":\"val2\",\"attr1\":\"val1\"}";
ExtendableBean bean = new ObjectMapper()
.readerFor(ExtendableBean.class)
.readValue(json);
System.out.println(bean.toString());
}
2.4 @JsonSetter
@JsonSetter
는 setter 메소드를 나타내는 @JsonProperty
의 대안이다.
JSON 데이터를 읽을 때 매우 유용하지만 대상 엔티티 클래스에 정확히 매칭되지 않고 몇가지 작업이 필요할 수도 있다.
@Getter
public class MyBean {
private int id;
private String name;
@JsonSetter("name")
public void setTheName(String name) {
this.name = name;
}
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws JsonProcessingException {
String json = "{\"id\":1,\"name\":\"My bean\"}";
MyBean bean = new ObjectMapper()
.readerFor(MyBean.class)
.readValue(json);
System.out.println(bean.toString()); // {"id":1,"name":"My bean"}
}
}
2.5 @JsonAlias
@JsonAlias
는 역직렬화할 때 하나 이상의 이름을 정의할 때 사용된다.
@Getter
public class AliasBean {
@JsonAlias({ "fName", "f_name" })
private String firstName;
private String lastName;
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws JsonProcessingException {
String json = "{\"fName\": \"John\", \"lastName\": \"Green\"}";
AliasBean aliasBean = new ObjectMapper()
.readerFor(AliasBean.class)
.readValue(json);
System.out.println(aliasBean.toString());
}
}
위의 코드에서 fName는 필드에 없다. fName을 필드에 매핑을 하려고 한다면 @JsonAlias
를 사용하면 된다.
@JsonAlias없이 사용하면 UnrecognizedPropertyException
이 발생할 것이다.
위에서 fName
과 f_name
은 firstName
으로 매핑을 하겠다는 의미이다.
3. Jackson Property Inclusion Annotations
3.1 @JsonIgnoreProperties
@JsonIgnoreProperties
는 Jackson이 무시할 프로퍼티를 표시하는 클래스 레벨의 어노테이션이다.
@Getter
@AllArgsConstructor
public class BeanWithIgnore {
private int id;
private String name;
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
BeanWithIgnore bean = new BeanWithIgnore(123, "홍길동");
System.out.println(bean.toString()); // {"id":123,"name":"홍길동"}
}
}
위의 코드에서 BeanWithIgnore를 출력하면 {"id":123,"name":"홍길동"}로 표시될 것이다.
여기서 id는 제외하고 출력하고 싶다면 @JsonIgnoreProperties
를 사용하면 된다.
@JsonIgnoreProperties({ "id" })
@Getter
@AllArgsConstructor
public class BeanWithIgnore {
private int id;
private String name;
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
BeanWithIgnore bean = new BeanWithIgnore(123, "홍길동");
System.out.println(bean.toString()); // {"name":"홍길동"}
}
}
JSON 입력값이 예외없이 정의되지 않은 특정 프로퍼티를 제외하려면, ignoreUnknown=true로 설정하면 된다.
3.2 @JsonIgnore
@JsonIgnore
어노테이션은 필드 수준에서 무시할 프로퍼티를 표시하는데 사용된다.
@Getter
@AllArgsConstructor
public class BeanWithIgnoreField {
@JsonIgnore // 이 필드는 역직렬화할 때 무시된다.
public int id;
public String name;
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
BeanWithIgnoreField bean = new BeanWithIgnoreField(123, "홍길동");
System.out.println(bean.toString()); // {"name":"홍길동"}
}
}
3.3 @JsonIgnoreType
@JsonIgnoreType
은 프로퍼티에서 무시될 어노테이션 타입을 표시한다.
아래 코드에서 Name을 무시하려면 @JsonIgnoreType
을 사용하면 된다.
@Getter
@AllArgsConstructor
public class User {
private int id;
private Name name;
@JsonIgnoreType
@AllArgsConstructor
public static class Name {
public String firstName;
public String lastName;
}
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
User user = new User(123, new User.Name("길동", "홍"));
System.out.println(user.toString());
}
}
3.4 @JsonInclude
공백, null값, 기본값인 프로퍼티를 제외할 때 @JsonInclude
를 사용한다.
@Getter
@AllArgsConstructor
public class MyBean {
private int id;
private String name;
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
MyBean bean = new MyBean(123, null);
System.out.println(bean.toString()); // {"id":123,"name":null}
}
}
위의 코드를 출력하면 {"id":123,"name":null} 으로 표시가 된다. 여기서 name은 null이므로 name을 역직렬화에서 제외하고 싶을 경우에 @JsonInclude
를 사용하면 된다.
@JsonInclude(JsonInclude.Include.NON_NULL)
@Getter
@AllArgsConstructor
public class MyBean {
private int id;
private String name;
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
MyBean bean = new MyBean(123, null);
System.out.println(bean.toString()); // {"id":123}
}
}
3.5 @JsonAutoDetect
@JsonAutoDetect
는 프로퍼티의 가시성 여부와 상관없이 사용할 수 있다.
@AllArgsConstructor
public class PrivateBean {
private int id;
private String name;
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
PrivateBean bean = new PrivateBean(123, "홍길동");
System.out.println(bean.toString()); // No serializer found for class com.example.jackson_annotation.inclusion.PrivateBean and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
}
}
위의 코드를 역직렬화하면 프로퍼티가 없어서 오류를 발생시킨다. 그래서 프로퍼티의 가시성과 여부와 상관없이 역직렬화하려면 @JsonAutoDetect
를 사용하면 된다.
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
@AllArgsConstructor
public class PrivateBean {
private int id;
private String name;
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
PrivateBean bean = new PrivateBean(123, "홍길동");
System.out.println(bean.toString()); // {"id":123,"name":"홍길동"}
}
}
4. Jackson Polymorphic Type Handling Annotations
Jackson의 다형성 관련 어노테이션을 살펴보자.
- @JsonTypeInfo - 직렬화 때 포함될 상세 정보
- @JsonSubTypes - 어노테이션 유형의 하위 유형
- @JsonTypeName - 어노테이션 클래스로 사용할 이름을 정의
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class Zoo {
private Animal animal;
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
})
@AllArgsConstructor
@NoArgsConstructor
public static class Animal {
public String name;
}
@JsonTypeName("dog")
@NoArgsConstructor
public static class Dog extends Animal {
public double barkVolume;
public Dog(String name, double barkVolume) {
super(name);
this.barkVolume = barkVolume;
}
}
@JsonTypeName("cat")
@NoArgsConstructor
public static class Cat extends Animal {
boolean likesCream;
public int lives;
public Cat(String name, boolean likesCream, int lives) {
super(name);
this.likesCream = likesCream;
this.lives = lives;
}
}
public static void main(String[] args) throws JsonProcessingException {
Zoo.Dog dog = new Zoo.Dog("lacy", 0);
Zoo zoo = new Zoo(dog);
String result = new ObjectMapper().writeValueAsString(zoo);
System.out.println(result);
}
}
위의 코드를 역직렬화하면 아래와 같을 것이다.
{
"animal": {
"type": "dog",
"name": "lacy",
"barkVolume": 0
}
}
다시 아래 구조로 역직렬화를 해보자.
{
"animal":{
"name":"lacy",
"type":"cat"
}
}
아래와 같이 Cat이 출력될 것이다.
public static void main(String[] args) throws JsonProcessingException {
String json = "{\"animal\":{\"name\":\"lacy\",\"type\":\"cat\"}}";
Zoo zoo = new ObjectMapper()
.readerFor(Zoo.class)
.readValue(json);
System.out.println(zoo.animal.getClass()); // class com.example.jackson_annotation.polymorphic.Zoo$Cat
}
5. Jackson General Annotations
5.1 @JsonProperty
JSON에서 프로퍼티 이름을 나타내기 위해 @JsonProperty
를 추가할 수 있다.
@Getter
@AllArgsConstructor
public class MyBean {
private int id;
private String name;
@JsonProperty("name")
public void setTheName(String name) {
this.name = name;
}
@JsonProperty("name")
public String getTheName() {
return name;
}
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
MyBean bean = new MyBean(123, "홍길동");
System.out.println(bean.toString());
}
}
@JsonProperty
를 사용하여 직렬화/역직렬화할 프로퍼티를 설정할 수 있다.
5.2 @JsonFormat
@JsonFormat
어노테이션은 Date/Time 값을 직렬화할 때 포맷을 지정할 때 사용할 수 있다.
@Getter
@AllArgsConstructor
public class EventWithFormat {
private String name;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
private Date eventDate;
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws ParseException {
SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
String toParse = "20-12-2014 02:30:00";
Date date = df.parse(toParse);
EventWithFormat event = new EventWithFormat("홍길동", date);
System.out.println(event.toString()); // {"name":"홍길동","eventDate":"20-12-2014 02:30:00"}
}
}
위의 코드에서 eventDate는 Date 타입인데 날짜 포맷을 특정 형식으로 표시하고자 할 때 @JsonFormat
을 사용하면 된다.
5.3 @JsonUnwrapped
@JsonUnwrapped
는 직렬화/역직렬화할 때 flat하게 표시하고자 할 때 사용된다.
@AllArgsConstructor
@Getter
public class UnwrappedUser {
private int id;
private Name name;
@AllArgsConstructor
@Getter
public static class Name {
public String firstName;
public String lastName;
}
@Override
public String toString() {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
UnwrappedUser user = new UnwrappedUser(123, new Name("길동", "홍"));
System.out.println(user.toString());
}
}
위의 코드를 출력하면 아래와 같은 형태가 될 것이다.
{
"id":123,
"name": {
"firstName":"길동",
"lastName":"홍"
}
}
여기서 name을 제외하고 firstName, lastName을 1단계로 flat하게 표시하고자 하면 @JsonUnwrapped
를 사용하면 된다.
public class UnwrappedUser {
private int id;
@JsonUnwrapped
private Name name;
...
}
출력하면 아래와 같이 표시될 것이다.
{
"id":123,
"firstName":"길동",
"lastName":"홍"
}
5.4 @JsonView
@JsonView
는 직렬화/역직렬화에 포함될 프로퍼티의 뷰를 나타낸다.
@AllArgsConstructor
@Getter
public class Item {
@JsonView(Views.Public.class)
private int id;
@JsonView(Views.Public.class)
private String itemName;
@JsonView(Views.Internal.class)
private String ownerName;
public static void main(String[] args) throws JsonProcessingException {
Item item = new Item(2, "book", "John");
String result = new ObjectMapper()
.writerWithView(Views.Public.class)
.writeValueAsString(item);
System.out.println(result); // {"id":2,"itemName":"book"}
}
}
위의 코드에서 writerWithView로 Views.Public을 설정하면 @JsonView
에 Views.Public.class로 설정된 프로퍼티만 직렬화/역직렬화된다.
5.5 @JsonManagedReference, @JsonBackReference
@JsonManagedReference
어노테이션은 parent/child 관계를 처리할 때 사용된다.
@Getter
@AllArgsConstructor
public class ItemWithRef {
private int id;
private String itemName;
public ItemWithRef(int id, String itemName) {
this.id = id;
this.itemName = itemName;
}
@JsonManagedReference
public UserWithRef owner;
public static void main(String[] args) throws JsonProcessingException {
UserWithRef user = new UserWithRef(1, "John");
ItemWithRef item = new ItemWithRef(2, "book", user);
user.addItem(item);
String result = new ObjectMapper().writeValueAsString(item);
System.out.println(result);
}
}
@Getter
@AllArgsConstructor
public class UserWithRef {
private int id;
private String name;
public UserWithRef(int id, String name) {
this.id = id;
this.name = name;
this.userItems = new ArrayList<>();
}
@JsonBackReference
public List<ItemWithRef> userItems;
public void addItem(ItemWithRef item) {
this.userItems.add(item);
}
}
위의 코드를 실행하면 아래와 같이 출력된다.
{"id":2,
"itemName":"book",
"owner": {
"id":1,
"name":"John"
}
}
5.6 @JsonIdentityInfo
@JsonIdentityInfo
는 직렬화/역직렬화 할 때 무한 루프 문제를 처리할 때 사용된다.
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
@Getter
@AllArgsConstructor
public class ItemWithIdentity {
private int id;
private String itemName;
private UserWithIdentity owner;
public static void main(String[] args) throws JsonProcessingException {
UserWithIdentity user = new UserWithIdentity(1, "John");
ItemWithIdentity item = new ItemWithIdentity(2, "book", user);
user.addItem(item);
String result = new ObjectMapper().writeValueAsString(item);
System.out.println(result);
}
}
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
@Getter
public class UserWithIdentity {
private int id;
private String name;
private List<ItemWithIdentity> userItems;
public UserWithIdentity(int id, String name) {
this.id = id;
this.name = name;
this.userItems = new ArrayList<>();
}
public void addItem(ItemWithIdentity item) {
this.userItems.add(item);
}
}
위의 코드에서 @JsonIdentityInfo
를 사용하지 않으면 무한루프가 발생한다.
5.7 @JsonFilter
@JsonFilter
어노테이션은 직렬화할 때 사용할 필터를 정의한다.
@JsonFilter("myFilter")
@Getter
@AllArgsConstructor
public class BeanWithFilter {
private int id;
private String name;
public static void main(String[] args) throws JsonProcessingException {
BeanWithFilter bean = new BeanWithFilter(123, "홍길동");
FilterProvider filters
= new SimpleFilterProvider().addFilter(
"myFilter",
SimpleBeanPropertyFilter.filterOutAllExcept("name"));
String result = new ObjectMapper().writer(filters).writeValueAsString(bean);
System.out.println(result);
}
}
위와 같이 직렬화할 때 filter를 정의하고 사용할 수 있다.