16 KiB
16 KiB
자바의 Jackson에 대해 설명하는 글을 작성하겠습니다. Jackson은 자바에서 JSON 데이터를 처리하기 위해 널리 사용되는 라이브러리로, 객체와 JSON 간의 직렬화(Serialization) 및 역직렬화(Deserialization)를 쉽게 수행할 수 있게 해줍니다. 특히, Jackson의 어노테이션은 이러한 변환 과정을 세밀하게 제어할 수 있도록 도와줍니다. 아래에서는 Jackson의 주요 어노테이션을 표로 정리한 뒤, 각 어노테이션에 대한 상세 설명과 예시를 제공하겠습니다.
Jackson 주요 어노테이션 표
| 어노테이션 | 설명 |
|---|---|
@JsonProperty |
JSON 키와 자바 필드/메서드 이름을 매핑하거나, 직렬화/역직렬화 시 속성 이름을 지정 |
@JsonIgnore |
직렬화 및 역직렬화 시 특정 필드를 무시 |
@JsonIgnoreProperties |
클래스 레벨에서 직렬화/역직렬화 시 무시할 속성(들)을 지정 |
@JsonInclude |
직렬화 시 특정 조건(예: null 값 제외)에 따라 필드를 포함하거나 제외 |
@JsonCreator |
역직렬화 시 사용할 생성자나 팩토리 메서드를 지정 |
@JsonSetter |
역직렬화 시 특정 Setter 메서드를 JSON 속성과 매핑 |
@JsonGetter |
직렬화 시 특정 Getter 메서드를 JSON 속성으로 사용 |
@JsonAnySetter |
정의되지 않은 JSON 속성을 Map 형태로 처리 |
@JsonAnyGetter |
Map의 내용을 추가적인 JSON 속성으로 직렬화 |
@JsonManagedReference |
객체 간 순환 참조에서 부모 객체를 직렬화 |
@JsonBackReference |
객체 간 순환 참조에서 자식 객체를 직렬화에서 제외 |
@JsonIdentityInfo |
순환 참조 문제를 해결하기 위해 객체의 고유 식별자를 사용 |
@JsonTypeInfo |
다형성 타입 정보를 JSON에 포함시켜 직렬화/역직렬화 시 올바른 타입으로 처리 |
@JsonSubTypes |
@JsonTypeInfo와 함께 사용되며, 하위 타입을 명시 |
@JsonView |
특정 뷰(View)에 따라 직렬화/역직렬화 대상을 제한 |
@JacksonInject |
JSON 데이터 대신 외부에서 주입된 값을 필드에 설정 |
각 어노테이션 상세 설명 및 예시
1. @JsonProperty
- 설명: JSON 속성 이름과 자바 필드/메서드 이름을 매핑하거나, 이름을 강제로 지정합니다.
- 예시:
import com.fasterxml.jackson.annotation.JsonProperty;
public class Person {
@JsonProperty("fullName")
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Person person = new Person();
person.setName("홍길동");
String json = mapper.writeValueAsString(person);
System.out.println(json); // {"fullName":"홍길동"}
}
}
2. @JsonIgnore
- 설명: 직렬화 및 역직렬화 시 특정 필드를 제외합니다.
- 예시:
import com.fasterxml.jackson.annotation.JsonIgnore;
public class Person {
private String name;
@JsonIgnore
private int age;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Person person = new Person();
person.setName("김영희"); person.setAge(25);
String json = mapper.writeValueAsString(person);
System.out.println(json); // {"name":"김영희"}
}
}
3. @JsonIgnoreProperties
- 설명: 클래스 레벨에서 무시할 속성을 지정하거나, 알 수 없는 속성을 무시하도록 설정합니다.
- 예시:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties({"age", "ignoreUnknown = true"})
public class Person {
private String name;
private int age;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"이철수\",\"age\":30,\"extra\":\"data\"}";
Person person = mapper.readValue(json, Person.class);
System.out.println(person.getName()); // "이철수"
}
}
4. @JsonInclude
- 설명: 직렬화 시 null 값이나 빈 값 등을 제외하는 조건을 설정합니다.
- 예시:
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Person {
private String name;
private String address;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getAddress() { return address; }
public void setAddress(String address) { this.address = address; }
}
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Person person = new Person();
person.setName("박민수");
String json = mapper.writeValueAsString(person);
System.out.println(json); // {"name":"박민수"}
}
}
5. @JsonCreator
- 설명: 역직렬화 시 사용할 생성자나 팩토리 메서드를 지정합니다.
- 예시:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Person {
private final String name;
@JsonCreator
public Person(@JsonProperty("name") String name) {
this.name = name;
}
public String getName() { return name; }
}
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"최수진\"}";
Person person = mapper.readValue(json, Person.class);
System.out.println(person.getName()); // "최수진"
}
}
6. @JsonSetter
- 설명: 역직렬화 시 Setter 메서드를 특정 JSON 속성과 매핑합니다.
- 예시:
import com.fasterxml.jackson.annotation.JsonSetter;
public class Person {
private String name;
@JsonSetter("fullName")
public void setName(String name) { this.name = name; }
public String getName() { return name; }
}
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"fullName\":\"김지영\"}";
Person person = mapper.readValue(json, Person.class);
System.out.println(person.getName()); // "김지영"
}
}
7. @JsonGetter
- 설명: 직렬화 시 Getter 메서드를 JSON 속성으로 사용합니다.
- 예시:
import com.fasterxml.jackson.annotation.JsonGetter;
public class Person {
private String name;
@JsonGetter("fullName")
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Person person = new Person();
person.setName("윤서진");
String json = mapper.writeValueAsString(person);
System.out.println(json); // {"fullName":"윤서진"}
}
}
8. @JsonAnySetter
- 설명: 정의되지 않은 JSON 속성을 Map으로 처리합니다.
- 예시:
import com.fasterxml.jackson.annotation.JsonAnySetter;
import java.util.HashMap;
import java.util.Map;
public class Person {
private Map<String, Object> properties = new HashMap<>();
@JsonAnySetter
public void setProperty(String key, Object value) {
properties.put(key, value);
}
public Map<String, Object> getProperties() { return properties; }
}
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"이정훈\",\"age\":29}";
Person person = mapper.readValue(json, Person.class);
System.out.println(person.getProperties()); // {name=이정훈, age=29}
}
}
9. @JsonAnyGetter
- 설명: Map의 내용을 추가적인 JSON 속성으로 직렬화합니다.
- 예시:
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import java.util.HashMap;
import java.util.Map;
public class Person {
private Map<String, Object> properties = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> getProperties() { return properties; }
public void setProperty(String key, Object value) { properties.put(key, value); }
}
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Person person = new Person();
person.setProperty("name", "최영미");
person.setProperty("age", 35);
String json = mapper.writeValueAsString(person);
System.out.println(json); // {"name":"최영미","age":35}
}
}
10. @JsonManagedReference와 @JsonBackReference
- 설명: 순환 참조 문제를 해결하기 위해 부모-자식 관계를 정의합니다.
- 예시:
import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.fasterxml.jackson.annotation.JsonBackReference;
public class Parent {
@JsonManagedReference
public Child child;
public void setChild(Child child) { this.child = child; }
}
public class Child {
@JsonBackReference
public Parent parent;
public void setParent(Parent parent) { this.parent = parent; }
}
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Parent parent = new Parent();
Child child = new Child();
parent.setChild(child);
child.setParent(parent);
String json = mapper.writeValueAsString(parent);
System.out.println(json); // {"child":{}}
}
}
11. @JsonIdentityInfo
- 설명: 순환 참조를 객체 ID로 해결합니다.
- 예시:
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Person {
private int id;
private String name;
private Person friend;
public Person(int id, String name) { this.id = id; this.name = name; }
public void setFriend(Person friend) { this.friend = friend; }
public String getName() { return name; }
}
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Person p1 = new Person(1, "김태양");
Person p2 = new Person(2, "이수진");
p1.setFriend(p2);
p2.setFriend(p1);
String json = mapper.writeValueAsString(p1);
System.out.println(json); // {"id":1,"name":"김태양","friend":{"id":2,"name":"이수진","friend":1}}
}
}
12. @JsonTypeInfo와 @JsonSubTypes
- 설명: 다형성을 처리하기 위해 타입 정보를 JSON에 포함합니다.
- 예시:
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
@Type(value = Dog.class, name = "dog"),
@Type(value = Cat.class, name = "cat")
})
public abstract class Animal {
public String name;
}
public class Dog extends Animal {}
public class Cat extends Animal {}
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Dog dog = new Dog(); dog.name = "멍멍이";
String json = mapper.writeValueAsString(dog);
System.out.println(json); // {"type":"dog","name":"멍멍이"}
}
}
13. @JsonView
- 설명: 특정 뷰에 따라 직렬화 대상을 제한합니다.
- 예시:
import com.fasterxml.jackson.annotation.JsonView;
public class Person {
public interface PublicView {}
public interface PrivateView extends PublicView {}
@JsonView(PublicView.class)
private String name;
@JsonView(PrivateView.class)
private int age;
public Person(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public int getAge() { return age; }
}
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Person person = new Person("박준영", 27);
String json = mapper.writerWithView(Person.PublicView.class).writeValueAsString(person);
System.out.println(json); // {"name":"박준영"}
}
}
14. @JacksonInject
- 설명: JSON 데이터가 아닌 외부에서 주입된 값을 사용합니다.
- 예시:
import com.fasterxml.jackson.annotation.JacksonInject;
public class Person {
@JacksonInject
private String source;
private String name;
public Person(String name) { this.name = name; }
public String getSource() { return source; }
public String getName() { return name; }
}
public class Main {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
InjectableValues inject = new InjectableValues.Std().addValue(String.class, "외부 소스");
Person person = mapper.reader(inject).forType(Person.class)
.readValue("{\"name\":\"최민수\"}");
System.out.println(person.getSource()); // "외부 소스"
}
}
결론
Jackson은 강력한 JSON 처리 기능을 제공하며, 위의 어노테이션들은 이를 세밀하게 제어할 수 있게 해줍니다. 다형성 처리, 순환 참조 해결, 속성 이름 매핑 등 다양한 기능을 통해 개발자는 유연하고 효율적인 JSON 처리를 구현할 수 있습니다. 프로젝트에서 Jackson을 사용할 때는 팀원 모두가 관련 어노테이션을 이해하고, 적절한 설정(예: 의존성 추가, IDE 플러그인 설치)을 통해 효율적으로 활용하는 것이 중요합니다.
궁금한 점이 있다면 언제든 물어보세요!