## Jackson 어노테이션 완벽 정리 및 상세 설명

Jackson은 자바 객체를 JSON으로 직렬화하거나 JSON을 자바 객체로 역직렬화하는 데 가장 널리 사용되는 라이브러리입니다. Jackson은 기본적으로 많은 부분을 자동으로 처리하지만, 어노테이션을 사용하면 직렬화 및 역직렬화 과정을 세밀하게 제어할 수 있습니다.

이번 글에서는 Jackson에서 주로 사용되는 어노테이션들을 표로 정리하고, 각 어노테이션의 역할과 사용법을 상세히 설명하겠습니다.

### Jackson 주요 어노테이션 요약 표

| 어노테이션                     | 적용 대상         | 설명                                                                                                                               |
| :----------------------------- | :---------------- | :--------------------------------------------------------------------------------------------------------------------------------- |
| **클래스 레벨** |                   |                                                                                                                                  |
| `@JsonIgnoreProperties`       | 클래스            | 직렬화 또는 역직렬화 시 특정 필드를 무시합니다.                                                                                    |
| `@JsonPropertyOrder`          | 클래스            | JSON으로 직렬화될 때 필드의 순서를 지정합니다.                                                                                     |
| `@JsonRootName`               | 클래스            | JSON 최상위 레벨의 이름을 지정합니다. (특정 설정 필요)                                                                           |
| `@JsonTypeInfo`               | 클래스            | 상속 관계의 객체를 직렬화/역직렬화할 때 타입 정보를 포함하도록 설정합니다.                                                              |
| `@JsonTypeName`               | 클래스            | `@JsonTypeInfo` 와 함께 사용되어 특정 하위 타입의 이름을 지정합니다.                                                                |
| `@JsonUnwrapped`              | 필드              | 해당 필드의 내용을 현재 객체의 필드인 것처럼 펼쳐서 직렬화/역직렬화합니다.                                                              |
| **필드 레벨** |                   |                                                                                                                                  |
| `@JsonProperty`               | 필드, 메서드      | JSON 필드 이름과 자바 객체 필드 또는 메서드 이름을 매핑합니다. 역직렬화 시 필수 필드를 지정할 수도 있습니다.                           |
| `@JsonIgnore`                 | 필드, 메서드      | 해당 필드 또는 메서드를 직렬화 및 역직렬화 과정에서 무시합니다.                                                                    |
| `@JsonIgnoreType`             | 클래스, 필드      | 해당 타입의 모든 필드를 직렬화 및 역직렬화 과정에서 무시합니다.                                                                    |
| `@JsonSerialize`              | 필드, 메서드      | 해당 필드 또는 메서드의 값을 직렬화할 때 사용할 사용자 정의 Serializer를 지정합니다.                                                |
| `@JsonDeserialize`            | 필드, 메서드      | 해당 필드 또는 메서드의 값을 역직렬화할 때 사용할 사용자 정의 Deserializer를 지정합니다.                                              |
| `@JsonFormat`                 | 필드, 메서드      | 날짜, 시간 등의 특정 타입의 직렬화/역직렬화 포맷을 지정합니다.                                                                       |
| `@JsonValue`                  | 메서드            | 해당 메서드의 반환 값을 객체 전체의 JSON 값으로 사용합니다. (주로 Enum에서 사용)                                                      |
| `@JsonCreator`                | 생성자, 정적 팩토리 메서드 | 역직렬화 시 사용할 생성자 또는 정적 팩토리 메서드를 지정합니다. `@JsonProperty` 와 함께 사용하여 매개변수를 매핑합니다.           |
| `@JsonAnyGetter`              | 메서드            | 동적으로 생성되는 필드들을 JSON 객체로 직렬화할 때 사용됩니다. (Map 타입 필드에 적용)                                                |
| `@JsonAnySetter`              | 메서드            | JSON 객체의 알 수 없는 필드들을 역직렬화하여 자바 객체의 Map 타입 필드에 저장할 때 사용됩니다.                                          |
| `@JsonManagedReference`       | 필드              | 순환 참조 관계에서 직렬화를 제어하는 데 사용됩니다. (Forward reference)                                                              |
| `@JsonBackReference`        | 필드              | 순환 참조 관계에서 역직렬화를 제어하는 데 사용됩니다. (Back reference, 직렬화 시 무시)                                               |
| `@JsonView`                   | 필드, 메서드      | 특정 View 인터페이스를 활성화했을 때만 해당 필드 또는 메서드를 직렬화에 포함합니다.                                                    |
| `@JsonAlias`                  | 필드              | 역직렬화 시 JSON 필드 이름의 별칭을 지정합니다. 여러 개의 별칭을 지정할 수 있습니다.                                                  |
| `@JsonInclude`                | 클래스, 필드      | 특정 조건(null 값, 기본값 등)에 따라 필드를 직렬화에서 제외합니다.                                                                   |

### Jackson 어노테이션 상세 설명

이제 각 어노테이션에 대해 더 자세히 알아보겠습니다. 예시 코드를 통해 각 어노테이션의 동작 방식을 명확히 이해할 수 있습니다.

**클래스 레벨 어노테이션**

* **`@JsonIgnoreProperties({"field1", "field2"})`**:
    * 직렬화 또는 역직렬화 시 지정된 이름의 필드를 무시합니다.
    * `ignoreUnknown = true` 속성을 사용하면 JSON에 정의되지 않은 필드가 있어도 예외를 발생시키지 않고 무시합니다.

    ```java
    @JsonIgnoreProperties({"internalId", "creationDate"})
    public class User {
        public int id;
        public String name;
        private String internalId;
        private Date creationDate;

        // ... (생성자, Getter, Setter)
    }

    // JSON -> User 역직렬화 시 "internalId", "creationDate" 필드는 무시됨
    // User -> JSON 직렬화 시 "internalId", "creationDate" 필드는 포함되지 않음
    ```

* **`@JsonPropertyOrder({"name", "id", "email"})`**:
    * JSON으로 직렬화될 때 필드의 순서를 명시적으로 지정합니다. 지정되지 않은 필드는 지정된 필드 뒤에 알파벳 순으로 나타납니다.

    ```java
    @JsonPropertyOrder({"name", "id", "email"})
    public class Person {
        public int id;
        public String name;
        public String email;

        // ...
    }

    // Person 객체를 JSON으로 직렬화하면 "name", "id", "email" 순서로 필드가 나타남
    ```

* **`@JsonRootName("user")`**:
    * JSON을 최상위 레벨의 이름으로 래핑합니다. Jackson의 `SerializationFeature.WRAP_ROOT_VALUE` 설정을 활성화해야 동작합니다.

    ```java
    @JsonRootName("user")
    public class Profile {
        public String username;
        public String role;

        // ...
    }

    // ObjectMapper mapper = new ObjectMapper();
    // mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
    // mapper.writeValueAsString(new Profile("testuser", "admin"));
    // 결과: {"user":{"username":"testuser","role":"admin"}}
    ```

* **`@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type")`**:
    * 상속 관계에 있는 클래스들을 직렬화/역직렬화할 때 타입 정보를 JSON에 포함하도록 설정합니다.
    * `use`: 타입 정보를 식별하는 방식을 지정 (예: `NAME`, `CLASS`)
    * `include`: 타입 정보를 JSON에 포함하는 방식 (예: `PROPERTY`, `WRAPPER_OBJECT`)
    * `property`: 타입 정보를 저장할 JSON 필드 이름

* **`@JsonTypeName("circle")`**:
    * `@JsonTypeInfo` 와 함께 사용되어 특정 하위 타입의 이름을 지정합니다.

    ```java
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type")
    abstract class Shape {
        public String color;
    }

    @JsonTypeName("circle")
    public class Circle extends Shape {
        public double radius;
    }

    @JsonTypeName("rectangle")
    public class Rectangle extends Shape {
        public double width;
        public double height;
    }

    // Circle 객체를 직렬화하면 JSON에 "@type":"circle" 정보가 포함됨
    ```

* **`@JsonUnwrapped`**:
    * 포함된 객체의 필드를 현재 객체의 필드처럼 펼쳐서 직렬화/역직렬화합니다. 이름 충돌에 주의해야 합니다.
    * `prefix` 속성을 사용하여 펼쳐진 필드 이름에 공통 접두사를 추가할 수 있습니다.

    ```java
    public class Address {
        public String street;
        public String city;
    }

    public class PersonInfo {
        public String name;
        @JsonUnwrapped
        public Address address;
    }

    // PersonInfo 객체를 직렬화하면 JSON은 {"name":"...", "street":"...", "city":"..."} 형태가 됨
    ```

**필드 레벨 어노테이션**

* **`@JsonProperty("fieldNameInJson")`**:
    * 자바 필드 이름과 JSON 필드 이름을 다르게 매핑합니다.
    * `required = true` 속성을 사용하여 역직렬화 시 해당 필드가 JSON에 반드시 존재해야 함을 명시할 수 있습니다.

    ```java
    public class Product {
        @JsonProperty("product_id")
        public int id;
        @JsonProperty(value = "product_name", required = true)
        public String name;

        // ...
    }

    // JSON {"product_id": 123, "product_name": "Laptop"} 은 Product 객체로 역직렬화됨
    // 역직렬화 시 "product_name" 필드가 없으면 예외 발생
    ```

* **`@JsonIgnore`**:
    * 해당 필드를 직렬화 및 역직렬화 과정에서 완전히 무시합니다.

    ```java
    public class Employee {
        public int id;
        public String name;
        @JsonIgnore
        private String password; // JSON으로 노출하지 않음

        // ...
    }
    ```

* **`@JsonIgnoreType`**:
    * 해당 타입의 모든 필드를 직렬화 및 역직렬화 과정에서 무시합니다.

    ```java
    @JsonIgnoreType
    public class InternalInfo {
        public String securityCode;
        public Date lastAccessed;
    }

    public class SystemData {
        public String version;
        public InternalInfo internal; // InternalInfo 타입의 필드는 직렬화/역직렬화 시 무시됨
    }
    ```

* **`@JsonSerialize(using = CustomSerializer.class)`**:
    * 해당 필드를 직렬화할 때 사용할 사용자 정의 Serializer 클래스를 지정합니다. 복잡한 객체나 특정 포맷으로 직렬화해야 할 때 유용합니다.

* **`@JsonDeserialize(using = CustomDeserializer.class)`**:
    * 해당 필드를 역직렬화할 때 사용할 사용자 정의 Deserializer 클래스를 지정합니다. JSON 데이터를 특정 객체로 변환하는 로직을 직접 구현할 수 있습니다.

* **`@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")`**:
    * 날짜, 시간 등의 특정 타입의 직렬화/역직렬화 포맷을 지정합니다. `pattern`, `timezone`, `locale` 등의 속성을 사용할 수 있습니다.

    ```java
    public class Event {
        public String name;
        @JsonFormat(pattern = "yyyy-MM-dd")
        public Date eventDate;
    }

    // Event 객체의 eventDate는 "yyyy-MM-dd" 형식의 문자열로 직렬화됨
    // 해당 형식의 문자열은 Date 객체로 역직렬화됨
    ```

* **`@JsonValue`**:
    * 메서드에 적용하며, 해당 메서드의 반환 값을 객체 전체의 JSON 값으로 사용합니다. 주로 Enum에서 Enum의 특정 값을 JSON으로 표현하고자 할 때 사용됩니다.

    ```java
    public enum Status {
        OK("정상"),
        ERROR("오류");

        private final String description;

        Status(String description) {
            this.description = description;
        }

        @JsonValue
        public String getDescription() {
            return description;
        }
    }

    // Status.OK 객체를 직렬화하면 "정상" 문자열이 됨
    ```

* **`@JsonCreator`**:
    * 클래스의 생성자 또는 정적 팩토리 메서드에 적용하여 역직렬화 시 사용할 방법을 지정합니다.
    * 생성자 파라미터 또는 정적 팩토리 메서드의 매개변수에 `@JsonProperty` 어노테이션을 함께 사용하여 JSON 필드와 매핑합니다.

    ```java
    public class Point {
        private final int x;
        private final int y;

        @JsonCreator
        public Point(@JsonProperty("x_coordinate") int x, @JsonProperty("y_coordinate") int y) {
            this.x = x;
            this.y = y;
        }

        public int getX() { return x; }
        public int getY() { return y; }
    }

    // JSON {"x_coordinate": 10, "y_coordinate": 20} 은 Point 객체로 역직렬화됨
    ```

* **`@JsonAnyGetter`**:
    * Map 타입의 필드에 적용된 메서드에 사용됩니다. 직렬화 시 Map의 키-값 쌍을 JSON 객체의 필드로 동적으로 추가합니다.

    ```java
    public class Attributes {
        private Map<String, Object> properties = new HashMap<>();

        public void addProperty(String key, Object value) {
            this.properties.put(key, value);
        }

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

    // Attributes 객체에 addProperty("color", "blue"), addProperty("size", "large")를 호출 후 직렬화하면
    // JSON은 {"color":"blue", "size":"large"} 형태가 됨
    ```

* **`@JsonAnySetter`**:
    * Map 타입의 필드에 적용된 메서드에 사용됩니다. 역직렬화 시 JSON 객체에 정의되지 않은 필드들을 Map에 동적으로 저장합니다. 메서드는 필드 이름과 값을 매개변수로 받아야 합니다.

    ```java
    public class UnknownProperties {
        private Map<String, Object> unknown = new HashMap<>();

        @JsonAnySetter
        public void addUnknown(String name, Object value) {
            this.unknown.put(name, value);
        }

        public Map<String, Object> getUnknown() {
            return unknown;
        }
    }

    // JSON {"name":"Product A", "price": 25.99, "category": "Electronics"} 를 UnknownProperties 객체로 역직렬화하면
    // "category": "Electronics" 정보는 unknown Map에 저장됨
    ```

* **`@JsonManagedReference` & `@JsonBackReference`**:
    * 객체 간의 순환 참조(예: 부모-자식 관계)가 있을 때 직렬화/역직렬화 과정에서 무한 루프를 방지하고 관계를 올바르게 처리하는 데 사용됩니다.
    * `@JsonManagedReference`: 순환 참조의 "정방향" (부모 -> 자식) 관계를 나타내는 필드에 적용합니다. 이 필드는 정상적으로 직렬화됩니다.
    * `@JsonBackReference`: 순환 참조의 "역방향" (자식 -> 부모) 관계를 나타내는 필드에 적용합니다. 이 필드는 직렬화 시 무시됩니다. 역직렬화 시에는 `@JsonManagedReference` 필드를 통해 관계가 복원됩니다.

    ```java
    public class Parent {
        public String name;
        @JsonManagedReference
        public List<Child> children;
    }

    public class Child {
        public String childName;
        @JsonBackReference
        public Parent parent;
    }

    // Parent 객체를 직렬화하면 children 리스트가 포함되지만, 각 Child 객체의 parent 필드는 제외됨
    // 역직렬화 시 children 정보를 바탕으로 각 Child 객체의 parent 필드가 올바르게 설정됨
    ```

* **`@JsonView(MyView.Public.class)`**:
    * 특정 View 인터페이스를 정의하고, `@JsonView` 어노테이션을 사용하여 해당 View가 활성화되었을 때만 필드를 직렬화에 포함하도록 제어합니다. 다양한 수준의 정보 공개가 필요한 API 개발에 유용합니다.

    ```java
    public class Item {
        public interface Public {}
        public interface Internal extends Public {}

        @JsonView(Public.class)
        public int id;
        @JsonView(Public.class)
        public String itemName;
        @JsonView(Internal.class)
        public String internalCode;
    }

    // ObjectMapper mapper = new ObjectMapper();
    // mapper.setConfig(mapper.getSerializationConfig().withView(Item.Public.class));
    // Item 객체를 직렬화하면 id와 itemName만 포함됨
    // mapper.setConfig(mapper.getSerializationConfig().withView(Item.Internal.class));
    // Item 객체를 직렬화하면 id, itemName, internalCode 모두 포함됨
    ```

* **`@JsonAlias({"oldName1", "oldName2"})`**:
    * 역직렬화 시 JSON 필드 이름의 별칭을 지정합니다. API 버전 관리 등으로 인해 필드 이름이 변경되었을 때 이전 이름으로도 역직렬화를 허용할 수 있습니다.

    ```java
    public class LegacyUser {
        @