Files
java-examples/docs/jackson.md

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 플러그인 설치)을 통해 효율적으로 활용하는 것이 중요합니다.

궁금한 점이 있다면 언제든 물어보세요!