18 KiB
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에 정의되지 않은 필드가 있어도 예외를 발생시키지 않고 무시합니다.
@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으로 직렬화될 때 필드의 순서를 명시적으로 지정합니다. 지정되지 않은 필드는 지정된 필드 뒤에 알파벳 순으로 나타납니다.
@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설정을 활성화해야 동작합니다.
@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"}} - JSON을 최상위 레벨의 이름으로 래핑합니다. Jackson의
-
@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와 함께 사용되어 특정 하위 타입의 이름을 지정합니다.
@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속성을 사용하여 펼쳐진 필드 이름에 공통 접두사를 추가할 수 있습니다.
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에 반드시 존재해야 함을 명시할 수 있습니다.
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:- 해당 필드를 직렬화 및 역직렬화 과정에서 완전히 무시합니다.
public class Employee { public int id; public String name; @JsonIgnore private String password; // JSON으로 노출하지 않음 // ... } -
@JsonIgnoreType:- 해당 타입의 모든 필드를 직렬화 및 역직렬화 과정에서 무시합니다.
@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등의 속성을 사용할 수 있습니다.
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으로 표현하고자 할 때 사용됩니다.
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 필드와 매핑합니다.
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 객체의 필드로 동적으로 추가합니다.
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에 동적으로 저장합니다. 메서드는 필드 이름과 값을 매개변수로 받아야 합니다.
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필드를 통해 관계가 복원됩니다.
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 개발에 유용합니다.
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 모두 포함됨 - 특정 View 인터페이스를 정의하고,
-
@JsonAlias({"oldName1", "oldName2"}):- 역직렬화 시 JSON 필드 이름의 별칭을 지정합니다. API 버전 관리 등으로 인해 필드 이름이 변경되었을 때 이전 이름으로도 역직렬화를 허용할 수 있습니다.
public class LegacyUser { @