본문 바로가기
DEV/Spring & Spring Boot

Jackson Annotaion

by 무사뎀벨레 2024. 9. 12.

 

 

 

출처 : https://spring.io

 

 

 

 

 

1. Jackson Serialization Annotation


 

@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"}
    }
}

 

 

 

@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 필드로 직렬화

@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":"홍길동"}
    }
}

 

 

@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":"서울"}
    }
}

 

순서를 변경하려면 아래와 같이 @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}
    }
}

 

 

 

@JsonRawValue

JsonRawValue 어노테이션jackson으로 하여금 속성 그대로 직렬화하게 함

아래와 같이 json은 하나의 문자열로 직렬화됨

@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을 문자열 형태로 직렬화하고 싶다면 아래와 같이 @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}}
    }
}

 

 

 

@JsonValue

@JsonValue는 특정 필드를 직렬화할 때 사용

 

아래의 TypeEnumWithValue를 직렬화하면 TYPE1의 enum이 출력됨

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"
    }
}

 

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"
    }
}

 

 

 

@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


 

@JsonCreator

역직렬화할 때 생성자/팩토리를 조정할 때 @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());
    }
}

 

 

 

@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"}
        //@JacksonInject을 사용 할 경우 : {"id":1,"name":"My bean"}
    }
}

 

 

@JsonAnySetter

@JsonAnySetter는 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());
    }
}

 

 

 

@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"}
    }
}

 

 

 

@JsonAlias

@JsonAlias는 역직렬화할 때 하나 이상의 이름을 정의할 때 사용

 

아래 코드에서 fName는 필드에 없는데 fName을 필드에 매핑을 하려고 한다면 @JsonAlias를 사용하면 됨

@JsonAlias 없이 사용하면 UnrecognizedPropertyException이 발생

@JsonAlias({ "fName", "f_name" })는 fName과 f_name은 firstName으로 매핑을 하겠다는 의미

@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());
    }
}

 

 

 

 

 

 

 

 

3. Jackson Property Inclusion Annotations


 

@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로 설정하면 됨

 

 

@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":"홍길동"}
    }
}

 

 

 

@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());
    }
}

 

 

 

@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}
    }
}

 

 

 

@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"
    }
}


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


 

@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());
    }
}

 

 

 

@JsonFormat

JsonFormat 어노테이션Date/Time 값을 직렬화할 때 포맷을 지정할 때 사용할 수 있음

 

아래 코드에서 eventDate는 Date 타입인데 날짜 포맷을 특정 형식으로 표시하고자 할 때 @JsonFormat을 사용함

@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"}
    }
}

 

 

 

@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":"홍"
}

 

 

 

@JsonView

@JsonView는 직렬화/역직렬화에 포함될 프로퍼티의 뷰를 나타냄

 

아래 코드에서 writerWithView로 Views.Public을 설정하면 @JsonView에 Views.Public.class로 설정된 프로퍼티만 직렬화/역직렬화됨

@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"}
    }
}

 

 

 

@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"
    }
}

 

 

 

 

@JsonIdentityInfo

@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);
    }
}

 

 

 

@JsonFilter

JsonFilter 어노테이션은 직렬화할 때 사용할 필터를 정의

아래와 같이 직렬화할 때 filter를 정의하고 사용할 수 있음

@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);
    }
}

 

반응형

'DEV > Spring & Spring Boot' 카테고리의 다른 글

[Spring] JPA vs MyBatis  (0) 2024.05.09

댓글