Read + Write Annotations
@JsonIgnore
-> Jackson이 해당 프로퍼티를 무시하도록 하는 역할을 한다.public class Test {
@JsonIgnore
public long id = 0;
public String name = null;
}<-->{"name":"circlee"}
@JsonIgnoreProperties
@JsonIgnoreProperties
-> @JsonIgnore 와 같은 기능, 해당 클래스의 여러 필드리스트를 무시하기 위해 사용한다.@JsonIgnoreProperties({"firstName", "lastName"})
public class PersonIgnoreProperties {
public long personId = 0;
public String firstName = null;
public String lastName = null;
}<-->{"firstName":"circlee7","lastName":"eldie"}
@JsonIgnoreType
-> JsonIgnoreType 은 해당타입이 사용되는 모든곳에서 무시되도록 한다.
@JsonBackReference
-> 부모자식 관계의 자식쪽에 작성함으로써 순환참조관계의 serialize 시 직렬화/역직렬화
시 참조하여 동작한다.참고 : https://stackoverflow.com/questions/37392733/difference-between-jsonignore-and-jsonbackreference-jsonmanagedreference
-> 부모자식 관계의 부모쪽에 작성함으로써 순환참조관계의 serialize 시 직렬화/역직렬화
시 참조하여 동작한다.
참고 : https://stackoverflow.com/questions/37392733/difference-between-jsonignore-and-jsonbackreference-jsonmanagedreference
@JsonAutoDetect
@JsonAutoDetect
-> JsonAutoDetect는 특정접근제한자의 필드들을 추가하라고 Jackson에게 알려주는 역할을 한다.@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY )
public class PersonAutoDetect {
private long personId = 123;
public String name = null;
}JsonAutoDetect.Visibility 는 접근레벨에 맞는 상수가 정의되어있다.
ANY
, DEFAULT
, NON_PRIVATE
, NONE
, PROTECTED_AND_PRIVATE
, PUBLIC_ONLY
@JsonView
JsonView 는 어노테이션 인자로 넘겨진 View 에 해당하는 클래스로 구분되어 직렬화/역직렬화 시 설정된 JsonView 에 따라 매칭되는 프로퍼티들이 역/직렬화 대상에 포함된다.
@AllArgsConstructor
public @Data class Person { private String name;
@JsonView(PersonView.NORMAL.class)
private String gender;
@JsonView(PersonView.PRIVATE.class)
private int age;
@JsonView(PersonView.ADDITIONAL.class)
private String address;
@JsonView({PersonView.ADDITIONAL.class, PersonView.HOBBIES.class})
private String hobbies;
public static class PersonView {
interface NORMAL{}
interface ADDITIONAL extends NORMAL{}
interface PRIVATE extends NORMAL{}
interface HOBBIES extends NORMAL{}}
}
실행: ObjectMapper writer/reader를 사용시 원하는 View를 지정한다.ObjectMapper om = new ObjectMapper();
Person p = new Person("eldi", "male", 10, "seoul", "basketball");
System.out.println(om.writeValueAsString(p));
System.out.println(om.writerWithView(PersonView.NORMAL.class).writeValueAsString(p));
System.out.println(om.writerWithView(PersonView.ADDITIONAL.class).writeValueAsString(p));
System.out.println(om.writerWithView(PersonView.PRIVATE.class).writeValueAsString(p));
System.out.println(om.writerWithView(PersonView.HOBBIES.class).writeValueAsString(p));
출력:{"name":"eldi","gender":"male","age":10,"address":"seoul","hobbies":"basketball"} <-- view 지정 하지 않는경우 전체 프로퍼티가 직렬화된다.{"name":"eldi","gender":"male"}
<-- NORMAL 로 직렬화시에는 JsonView를 지정하지 않은 name과 view 와 매칭되는 gender 만 노출된다.{"name":"eldi","gender":"male","address":"seoul","hobbies":"basketball"} <-- ADDITIONAL 로 직렬화 시에는 NORMAL 을 상속받았기 때문에 NORMAL, ADDITIONAL 해당하는 전체를 포함한다.{"name":"eldi","gender":"male","age":10}
<-- 위와 마찬가지로 PRIVATE 와 부모인 NORMAL 에 해당하는 프로퍼티를 포함한다.
{"name":"eldi","hobbies":"basketball"}
<-- hobbies 프로퍼티는 ADDITIONAL 과 HOBBIES VIEW 가 복수개로 정의되어 있어서 두개의 VIEW 모두에 포함된다.
Read Annotations (Json Object to Java Object : Deserialize)
@JsonSetter
-> Jackson은 Json Data와 Class 의 프로퍼티 이름이 일치해야 하지만
JsonSetter 를 사용하여, Json Data의 특정 프로퍼티 이름으로 Class의 Setter 메소드에 지정할수있다.{
"id" : 1234,
"name" : "John"
}<-->public class Bag {
private Map<String, Object> properties = new HashMap<>();
@JsonAnySetter
public void set(String fieldName, Object value){
this.properties.put(fieldName, value);
}
public Object get(String fieldName){
return this.properties.get(fieldName);
}
}
@JsonAnySetter
-> JSON Object 의 모든 setter 메소드를 인지할수 없는 필드에 대해
JsonAnySetter 어노테이션을 통해 Map<String, Object> 변수로 담을 수 있습니다.{
"id" : 1234,
"name" : "John"
}<-->public class Bag {
private Map<String, Object> properties = new HashMap<>();
@JsonAnySetter
public void set(String fieldName, Object value){
this.properties.put(fieldName, value);
}
public Object get(String fieldName){
return this.properties.get(fieldName);
}
}
@JsonCreator
-> JsonCreater 는 생성자메소드에 지정되어 JSON Object 의 필드 와 메소드의 파라미터 매칭을 통해 Java Object를 생성가능하게 한다.
@JsonSetter를 사용할수 없거나, 불변객체이기 때문에 setter 메소드가 존재하지 않을때
초기화 데이터 주입을 위해 유용하다.{
"id" : 1234,
"name" : "John"
}<-->public class PersonImmutable {
private long id = 0;
private String name = null;
@JsonCreator
public PersonImmutable(
@JsonProperty("id") long id,
@JsonProperty("name") String name ) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
}
@JacksonInject
-> JacksonInject 어노테이션은 Jackson 에의해 역직렬화된 Java Object에 공통정인 값을 주입할 수 있는 java Object의 프로퍼티를 지정한다.
예를들어 여러 소스에서 Person Json Object를 파싱할때에 , 이 Json Object 의 소스가 어디인지 주입을 통해 저장할수 있다.public class PersonInject {
public long id = 0;
public String name = null;
@JacksonInject
public String source = null;
}--- InjectableValues inject = new InjectableValues.Std().addValue(String.class, "jenkov.com");
PersonInject personInject = new ObjectMapper().reader(inject)
.forType(PersonInject.class)
.readValue(new File("data/person.json"));inject 리더가 지정된 ObjectMapper 를 이용하여 파싱하게 되면 jacksonInject 어노테이션을 확인하여 필드의 타입기반 매칭으로 값을 주입한다.
@JsonDeserialize
-> JsonDeserialize 는 필드가 커스텀한 Deserializer class를 사용할수 있도록 한다. public class PersonDeserialize {
public long id = 0;
public String name = null;
@JsonDeserialize(using = OptimizedBooleanDeserializer.class)
public boolean enabled = false;
}
---
public class OptimizedBooleanDeserializer
extends JsonDeserializer<Boolean> {
@Override
public Boolean deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws
IOException, JsonProcessingException {
String text = jsonParser.getText();
if("0".equals(text)) return false;
return true;
}
}JsonDeserializer<T t> 를 상속을 통해 구현할때 필드에 맞는 genericType을 지정하여 상속받고, desirialze 메소드를 작성한다.
Write Annotations (Java Object to Json Object : Serialize)
@JsonInclude
-> JsonInclude 는 특정한 상황? 상태? 의 필드만 Json Object 변경시 포함되도록 지정할수 있다. @JsonInclude(JsonInclude.Include.NON_EMPTY)
public class PersonInclude {
public long personId = 0;
public String name = null;
}JsonInclude.Include 는 아래와 같은 include 상수들이 지정되어 있고
NON_EMPTY의 경우 not null과 not empty를 의미한다.
java8 Optional 타입의 isAbsent 도 체크한다.ALWAYS
, NON_NULL
, NON_ABSENT
, NON_EMPTY
, NON_DEFAULT
, USE_DEFAULTS
@JsonGetter
-> @JsonSetter 와 반대로 setter메소드에 지정되며 해당하는 이름으로 Json Object 의 data field 가 생성된다.public class PersonGetter {
private long personId = 0;
@JsonGetter("id")
public long personId() { return this.personId; }
@JsonSetter("id")
public void personId(long personId) { this.personId = personId; }
}
@JsonAnyGetter
-> @JsonAnySetter 와 반대 역할로써 Key, Value 형식의 Map을 리턴하는 메소드에 지정함으로써 Json Object의 프로퍼티로 작성되게끔 한다.public class PersonAnyGetter {
private Map<String, Object> properties = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> properties() {
return properties;
}
}<-->
{
"map.key1" : "map.key1.value"
,"map.key2" : map.key2.value
...
}
@JsonPropertyOrder
-> JsonPropertyOrder는 Java Object가 Json 으로 직렬화 될때 필드의 순서를 지정할 수 있다.
(일반적으로 Jackson은 class 에서 필드를 발견하는 순서대록 직렬화 해버림)@JsonPropertyOrder({"name", "personId"})
public class PersonPropertyOrder {
public long personId = 0;
public String name = null;
}
@JsonRawValue
-> JsonRawValue 는 특정필드에 지정되어, 해당 필드의 값이 raw하게 Json Output이 되도록 할 수 있습니다.public class PersonRawValue {
public long personId = 0;
public String address = "$#";
}일반적으로 문자열은 Json Output 시에 쌍따옴표로 감싸진체 출려됩니다.{"personId":0,"address":"$#"}--- public class PersonRawValue {
public long personId = 0;
@JsonRawValue
public String address = "$#";
}@JsonRawValue를 사용하면 쌍따움표 없이 그대로 출력됩니다.{"personId":0,"address":$#}하지만, 이것은 잘못된 Json형식입니다.---@JsonRawValue 는 Raw Json 문자열을 String 타입변수에 담아 출력할때 사용될수 있습니다.public class PersonRawValue {
public long personId = 0;
@JsonRawValue
public String address =
"{ \"street\" : \"Wall Street\", \"no\":1}";
}{"personId":0,"address":{ "street" : "Wall Street", "no":1}}
@JsonValue
-> @JsonValue 를 지정함으로써 Jackson이 객체자체를 직렬화하지 않고 JsonValue 가 지정된 메소드를 호출하는것으로 대체할 수 있습니다.public class PersonValue {
public long personId = 0;
public String name = null;
@JsonValue
public String toJson(){
return this.personId + "," + this.name;
}
}출력 :
"0,null"쌍따옴표는 Jackson에 의해 붙여지게 됩니다.
반환된 문자열내의 쌍따옴표는 모두 이스케이프 처리됩니다.
@JsonSerialize
-> JsonSerialize를 이용하여 특정필드에 커스텀 serialzer를 지정할 수 있다.public class PersonSerializer {
public long personId = 0;
public String name = "John";
@JsonSerialize(using = OptimizedBooleanSerializer.class)
public boolean enabled = false;
}public class OptimizedBooleanSerializer extends JsonSerializer<Boolean> {
@Override
public void serialize(Boolean aBoolean, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider)
throws IOException, JsonProcessingException {
if(aBoolean){
jsonGenerator.writeNumber(1);
} else {
jsonGenerator.writeNumber(0);
}
}
}
Jackson 에서 다양한 어노테이션을 지원하기 때문에
적재적소에 잘 사용한다면 보다 간결한 코딩이 가능할것으로 생각된다.
물론, 무분별한 가독성을 해치거나 복잡도를 증가시키는 사용은 피해야겠다.
JsonSerialize/JsonDeserialize 어노테이션을 살펴보니 Type 도 target으로 설정되어있다.
해당 날짜타입의 클래스도 Jackson 레벨에서 특정패턴의 날짜형식으로 처리가 가능할것으로 보인다.
(Spring Converter와 별개로 확인을 위해)
출력:
{"name":"test","timeYmd":"2018-08-09 13:45:07"}
2018-08-09T13:45:07.551
2018-08-09T13:45:07 <- 파싱후의 LocalDateTime 객체이므로 이미 직렬화시 패턴에 의해 밀리세컨드는 절삭됨.
추가
@JsonIdentityReference
@JsonAppend
@JsonNaming
@JsonNaming 어노테이션은 프로퍼티 들의 직렬화 네이밍 전략을 선택하는데 사용되어진다.
이미 정의된 프로퍼티 네이밍 전략 들 또는 커스텀으로 작성된 전략을 사용할 수 있다.default는 LOWER_CAMEL_CASE 이고.Jackson 라이브러리는 4가지의 프로퍼티 네이밍 전략들을 내장하고 있다.KEBAB_CASE: 이름 요소 들은 하이픈 기호로 구분되어진다.
LOWER_CASE: 모든 문자는 구분자 없는 소문자로 이루어진다.
SNAKE_CASE: 모든 문자는 소문자로, 이름 요소들 사이에 underscore 로 구분된다.
UPPER_CAMEL_CASE: 첫번째 문자를 포함한 모든 이름요소들은 대문자로 시작하고 소문자로 이어지며, 구분자는 없다.ex>@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)|
public class NamingBean {
private int id;
private String beanName;}
@JsonPropertyDescription
@JsonPOJOBuilder
@JsonTypeId
@JsonTypeIdResolver
@JacksonAnnotationsInside
아래 참고
https://www.baeldung.com/jackson-annotations
끝