433 lines
16 KiB
Markdown
433 lines
16 KiB
Markdown
자바의 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 속성 이름과 자바 필드/메서드 이름을 매핑하거나, 이름을 강제로 지정합니다.
|
|
- **예시**:
|
|
```java
|
|
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`
|
|
- **설명**: 직렬화 및 역직렬화 시 특정 필드를 제외합니다.
|
|
- **예시**:
|
|
```java
|
|
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`
|
|
- **설명**: 클래스 레벨에서 무시할 속성을 지정하거나, 알 수 없는 속성을 무시하도록 설정합니다.
|
|
- **예시**:
|
|
```java
|
|
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 값이나 빈 값 등을 제외하는 조건을 설정합니다.
|
|
- **예시**:
|
|
```java
|
|
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`
|
|
- **설명**: 역직렬화 시 사용할 생성자나 팩토리 메서드를 지정합니다.
|
|
- **예시**:
|
|
```java
|
|
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 속성과 매핑합니다.
|
|
- **예시**:
|
|
```java
|
|
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 속성으로 사용합니다.
|
|
- **예시**:
|
|
```java
|
|
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으로 처리합니다.
|
|
- **예시**:
|
|
```java
|
|
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 속성으로 직렬화합니다.
|
|
- **예시**:
|
|
```java
|
|
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`
|
|
- **설명**: 순환 참조 문제를 해결하기 위해 부모-자식 관계를 정의합니다.
|
|
- **예시**:
|
|
```java
|
|
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로 해결합니다.
|
|
- **예시**:
|
|
```java
|
|
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에 포함합니다.
|
|
- **예시**:
|
|
```java
|
|
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`
|
|
- **설명**: 특정 뷰에 따라 직렬화 대상을 제한합니다.
|
|
- **예시**:
|
|
```java
|
|
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 데이터가 아닌 외부에서 주입된 값을 사용합니다.
|
|
- **예시**:
|
|
```java
|
|
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 플러그인 설치)을 통해 효율적으로 활용하는 것이 중요합니다.
|
|
|
|
궁금한 점이 있다면 언제든 물어보세요! |