티스토리 뷰

728x90

 

데이터 형태가 서버에서 파싱하여 사용하기 좋게 찰떡같이 수신되면 좋겠지만, 그렇지 않은 경우도 많다.

 

최근 진행하고있는 프로젝트에서 특정 프로토콜 기반으로 통신하기위해서 정해진 포멧으로 JSON을 생성해서 사용해야했는데, 그게 좀 특이한 형태였다.

 

그래서 데이터를 Map을 해당 프로토콜 기반 JSON 형태로 Serialize하고, 다시 Deserialize 해서 필요한 Object들에 맞게 파싱해주는 작업을 했다.

 

이 과정에서 주로 사용 및 테스트 했던 어노테이션을 위주로 정리하였으며, 아래 링크를 확인하면 더 많은 어노테이션을 확인 할 수 있다.

참고: https://www.baeldung.com/jackson-annotations

 

 

 

Serialization

 

1. @JsonAnyGetter : Map이 Json 형태로 serialization된다. 주의점은 Object의 경우 바로 serialzation해주지 않는다.

public class ExtendableBean {
    public String name;
    private Map<String, String> properties;

    @JsonAnyGetter
    public Map<String, String> getProperties() {
        return properties;
    }
}
 

2. @JsonGetter : getter method에 @JsonProperty의 대안으로 사용가능하다.

public class MyBean {
    public int id;
    private String name;

    @JsonGetter("name")
    public String getTheName() {
        return name;
    }
}
 

3. @JsonPropertyOrder: serialization 순서를 명시해줄 수 있다.

@JsonPropertyOrder({ "name", "id" })
public class MyBean {
    public int id;
    public String name;
}
 

4. @JsonRawValue: serailize할 property를 명시해줄 수 있다.

public class RawBean {
    public String name;

    @JsonRawValue
    public String json;
}
 
원본 데이터
출력 데이터
new RawBean("My bean", "{\"attr\":false}");
{ "name":"My bean", "json":{ "attr":false } }

 

5. @JsonValue : 전체를 대표할 하나의 메서드를 지정 할 수 있다. (Enum 중 대표값으로 출력할 때 유용하다)

public enum TypeEnumWithValue {
    TYPE1(1, "Type A"), TYPE2(2, "Type 2");

    private Integer id;
    private String name;

    // standard constructors

    @JsonValue
    public String getName() {
        return name;
    }
}
 

 

6. @JsonRootName: wrapping 할 root를 명시해줄 수 있다.

@JsonRootName(value = "user")
public class UserWithRoot {
    public int id;
    public String name;
}
원본 데이터
출력 데이터
{ "id": 1, "name": "John" }
{ "User": { "id": 1, "name": "John" } }

 

 

 

Deserialization

 

1. @JsonCreator: deserialize 대상 json과 target entity가 정확하게 매칭되지 않을때 유용하다.

public class BeanWithCreator {
    public int id;
    public String name;

    @JsonCreator
    public BeanWithCreator(
      @JsonProperty("id") int id, 
      @JsonProperty("theName") String name) {
        this.id = id;
        this.name = name;
    }
}
 

 

2. @JacksonInject: deserialize 대상 json에 값을 추가한 결과를 deserialize 할 때 사용한다.

public class BeanWithInject {
    @JacksonInject
    public int id;
    
    public String name;
}
 

--> Test

@Test
public void whenDeserializingUsingJsonInject_thenCorrect()
  throws IOException {
 
    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);
    
    assertEquals("My bean", bean.name);
    assertEquals(1, bean.id);
}
 

3. @JsonAnySetter: Json property 값을 Map 형태로 쉽게 담을 수 있게 한다.

public class ExtendableBean {
    public String name;
    private Map<String, String> properties;

    @JsonAnySetter
    public void add(String key, String value) {
        properties.put(key, value);
    }
}
 

--> test

@Test
public void whenDeserializingUsingJsonAnySetter_thenCorrect()
  throws IOException {
    String json
      = "{\"name\":\"My bean\",\"attr2\":\"val2\",\"attr1\":\"val1\"}";

    ExtendableBean bean = new ObjectMapper()
      .readerFor(ExtendableBean.class)
      .readValue(json);
    
    assertEquals("My bean", bean.name);
    assertEquals("val2", bean.getProperties().get("attr2"));
}
 

4. @JsonSetter: deserialize 대상 json과 target entity가 정확하게 매칭되지 않을때 유용하다. 나의 경우 대문자로 시작하는 필드를 전달받는데, jackson은 기본적으로 JavaBean naming을 따르기 때문에, 소문자로 치환되서 들어와 어노테이션만 붙였을 때 파싱이 안되는 문제가 있었다.

그래서 대문자 필드를 정확히 명시해주어 해결했다. ex)@JsonSetter("Name")

public class MyBean {
    public int id;
    private String name;

    @JsonSetter("Name")
    public void setTheName(String name) {
        this.name = name;
    }
}
 

--> test

@Test
public void whenDeserializingUsingJsonSetter_thenCorrect()
  throws IOException {
 
    String json = "{\"id\":1,\"name\":\"My bean\"}";

    MyBean bean = new ObjectMapper()
      .readerFor(MyBean.class)
      .readValue(json);
    assertEquals("My bean", bean.getTheName());
}
 
 

Property Inclusion

 

1. @JsonIgnoreProperties: class-level 어노테이션이며, 포함하지 않을 property를 명시 할 수 있다.

@JsonIgnoreProperties({ "id" })
public class BeanWithIgnore {
    public int id;
    public String name;
}
 

2. @JsonIgnore: field level로, 무시 할 property를 지정해 줄 수 있다.

public class BeanWithIgnore {
    @JsonIgnore
    public int id;

    public String name;
}
 

3. @JsonIgnoreType: 무시 할 property를 한꺼번에 지정해 줄 수 있다.

public class User {
    public int id;
    public Name name;

    @JsonIgnoreType
    public static class Name {
        public String firstName;
        public String lastName;
    }
}
 

4. @JsonInclude: Json 데이터에서 제외 할 조건을 설정 할 수 있다.

@JsonInclude(Include.NON_NULL)
public class MyBean {
    public int id;
    public String name;
}
 

5. @JsonAutoDetect: 접근 제한자에 따라 어떤 데이터를 JSON에 포함할 지 설정 할 수 있다. (ANY, NON_PRIVATE, PROTECTED_AND_PUBLIC 등...)

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class PrivateBean {
    private int id;
    private String name;
}
 
 

General

 

1. @JsonProperty: JSON의 property name을 지정해준다.

public class MyBean {
    public int id;
    private String name;

    @JsonProperty("name")
    public void setTheName(String name) {
        this.name = name;
    }

    @JsonProperty("name")
    public String getTheName() {
        return name;
    }
}
 

2. @JsonFormat: JSON 데이터 포멧을 지정해준다.

public class EventWithFormat {
    public String name;

    @JsonFormat(
      shape = JsonFormat.Shape.STRING,
      pattern = "dd-MM-yyyy hh:mm:ss")
    public Date eventDate;
}
 

3. @JsonUnwrapped: 데이터의 Wrapping을 풀어줄 때 사용한다.

public class UnwrappedUser {
    public int id;

    @JsonUnwrapped
    public Name name;

    public static class Name {
        public String firstName;
        public String lastName;
    }
}
결과 데이터
{ "id":1, "firstName":"John", "lastName":"Doe" }
728x90

'Spring' 카테고리의 다른 글

@EnableKafkaStreams 분석 - 어떻게 streams는 start 되는가?  (1) 2022.05.17
Kafka Streams - Spring boot example  (0) 2022.05.17
Filter, Interceptor, AOP  (0) 2022.04.13
JSON 매핑 필드 대소문자 이슈  (0) 2022.04.02
Json 맵핑 원리  (0) 2022.04.02
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31