1. 개요

이 빠른 사용방법(예제)에서는 Java Enum이 Jackson 2로 직렬화 및 역직렬화 되는 방식을 제어하는 ​​방법을 배웁니다 .

잭슨 2로 할 수 있는 다른 멋진 일들을 좀 더 깊이 파고들고 배우 려면 기본 잭슨 예제 로 가십시오 .

2. 열거형 표현 제어

다음 Enum을 정의해 보겠습니다.

public enum Distance {
    KILOMETER("km", 1000), 
    MILE("miles", 1609.34),
    METER("meters", 1), 
    INCH("inches", 0.0254),
    CENTIMETER("cm", 0.01), 
    MILLIMETER("mm", 0.001);

    private String unit;
    private final double meters;

    private Distance(String unit, double meters) {
        this.unit = unit;
        this.meters = meters;
    }

    // standard getters and setters
}

3. 열거형을 JSON으로 직렬화

3.1. 기본 열거형 표현

기본적으로 Jackson은 Java Enum을 간단한 문자열로 나타냅니다. 예를 들어:

new ObjectMapper().writeValueAsString(Distance.MILE);

결과:

"MILE"

그러나 이 Enum을 JSON 객체로  마샬링할 때 다음과 같은 결과를 얻고 싶습니다.

{"unit":"miles","meters":1609.34}

3.2. 열거형을 JSON 객체로

Jackson 2.1.2부터 이러한 종류의 표현을 처리할 수 있는 구성 옵션이 있습니다. 이것은 클래스 수준에서 @JsonFormat 어노테이션을 통해 수행할 수 있습니다.

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Distance { ... }

이것은 Distance 에 대해 이 열거형 을 직렬화할 때 원하는 결과로 이어집니다 . 마일:

{"unit":"miles","meters":1609.34}

3.3. 열거형 및 @JsonValue

열거형에 대한 마샬링 출력을 제어하는 ​​또 다른 간단한 방법은 getter에서 @JsonValue 어노테이션을 사용하는 것입니다.

public enum Distance { 
    ...
 
    @JsonValue
    public String getMeters() {
        return meters;
    }
}

여기서 표현하는 것은 getMeters() 가 이 열거형의 실제 표현이라는 것입니다. 따라서 직렬화 결과는 다음과 같습니다.

1609.34

3.4. Enum용 사용자 지정 직렬 변환기

2.1.2 이전 버전의 Jackson을 사용하거나 열거형에 대해 더 많은 사용자 지정이 필요한 경우 사용자 지정 Jackson 직렬 변환기를 사용할 수 있습니다. 먼저 다음과 같이 정의해야 합니다.

public class DistanceSerializer extends StdSerializer {
    
    public DistanceSerializer() {
        super(Distance.class);
    }

    public DistanceSerializer(Class t) {
        super(t);
    }

    public void serialize(
      Distance distance, JsonGenerator generator, SerializerProvider provider) 
      throws IOException, JsonProcessingException {
        generator.writeStartObject();
        generator.writeFieldName("name");
        generator.writeString(distance.name());
        generator.writeFieldName("unit");
        generator.writeString(distance.getUnit());
        generator.writeFieldName("meters");
        generator.writeNumber(distance.getMeters());
        generator.writeEndObject();
    }
}

그런 다음 직렬화할 클래스에 직렬화기를 적용할 수 있습니다.

@JsonSerialize(using = DistanceSerializer.class)
public enum TypeEnum { ... }

그 결과:

{"name":"MILE","unit":"miles","meters":1609.34}

4. JSON을 열거형으로 역직렬화

먼저 Distance 멤버 가 있는 City 클래스를 정의해 보겠습니다 .

public class City {
    
    private Distance distance;
    ...    
}

그런 다음 JSON 문자열을 Enum으로 역직렬화하는 다양한 방법에 대해 논의합니다.

4.1. 기본 동작

기본적으로 Jackson은 Enum 이름을 사용하여 JSON에서 역직렬화 합니다.

예를 들어 JSON을 역직렬화합니다.

{"distance":"KILOMETER"}

Distance.KILOMETER 개체 로 :

City city = new ObjectMapper().readValue(json, City.class);
assertEquals(Distance.KILOMETER, city.getDistance());

Jackson이 Enum 이름으로 JSON에서 대소문자를 구분하지 않고 역직렬화 하도록 하려면 ACCEPT_CASE_INSENSITIVE_ENUMS 기능 을 활성화하도록 ObjectMapper 를 사용자 지정 해야 합니다 .

다른 JSON이 있다고 가정해 보겠습니다.

{"distance":"KiLoMeTeR"}

이제 대소문자를 구분하지 않는 역직렬화를 수행해 보겠습니다.

ObjectMapper objectMapper = JsonMapper.builder()
  .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)
  .build();
City city = objectMapper.readValue(json, City.class);
                                                     
assertEquals(Distance.KILOMETER, city.getDistance());

위의 테스트에서 알 수 있듯이 JsonMapper 빌더 를 사용하여 ACCEPT_CASE_INSENSITIVE_ENUMS 기능을 활성화합니다.

4.2. @JsonValue 사용

Enum 을 직렬화 하기 위해 @JsonValue 를 사용하는 방법을 배웠습니다 . 역직렬화에도 동일한 어노테이션을 사용할 수 있습니다. 이것은 Enum 값이 상수이기 때문에 가능합니다.

먼저 getter 메서드 중 하나인 getMeters() 와 함께 @JsonValue 를 사용합니다 .

public enum Distance {
    ...

    @JsonValue
    public double getMeters() {
        return meters;
    }
}

getMeters() 메서드 의 반환 값은 Enum 개체를 나타냅니다. 따라서 샘플 JSON을 역직렬화할 때:

{"distance":"0.0254"}

Jackson은 getMeters() 반환 값이 0.0254인 Enum 객체를 찾습니다. 이 경우 객체는 거리입니다. 인치:

assertEquals(Distance.INCH, city.getDistance());

4.3. @JsonProperty 사용

@JsonProperty 어노테이션은 열거형 인스턴스에 사용됩니다.

public enum Distance {
    @JsonProperty("distance-in-km")
    KILOMETER("km", 1000), 
    @JsonProperty("distance-in-miles")
    MILE("miles", 1609.34);
 
    ...
}

이 어노테이션을 사용하여 우리는 단순히 @JsonProperty 값 을 이 값으로 어노테이션이 달린 객체 에 매핑하도록 Jackson에 지시합니다 .

위 선언의 결과로 예제 JSON 문자열은 다음과 같습니다.

{"distance": "distance-in-km"}

Distance.KILOMETER 개체 에 매핑됩니다 .

assertEquals(Distance.KILOMETER, city.getDistance());

4.4. @JsonCreator 사용

Jackson은 @JsonCreator 로 어노테이션이 달린 메서드를 호출 하여 둘러싸는 클래스의 인스턴스를 가져옵니다.

JSON 표현을 고려하십시오.

{
    "distance": {
        "unit":"miles", 
        "meters":1609.34
    }
}

그런 다음 @JsonCreator 어노테이션 을 사용하여 forValues() 팩토리 메서드를 정의합니다.

public enum Distance {
   
    @JsonCreator
    public static Distance forValues(@JsonProperty("unit") String unit,
      @JsonProperty("meters") double meters) {
        for (Distance distance : Distance.values()) {
            if (
              distance.unit.equals(unit) && Double.compare(distance.meters, meters) == 0) {
                return distance;
            }
        }

        return null;
    }

    ...
}

@JsonProperty 어노테이션을 사용하여 JSON 필드를 메서드 인수와 바인딩하는 것에 유의하십시오 .

그런 다음 JSON 샘플을 역직렬화하면 결과가 표시됩니다.

assertEquals(Distance.MILE, city.getDistance());

4.5. 사용자 지정 디시리얼라이저 사용

설명된 기술을 사용할 수 없는 경우 사용자 지정 디시리얼라이저를 사용할 수 있습니다. 예를 들어 Enum 소스 코드에 액세스할 수 없거나 지금까지 다룬 어노테이션 중 하나 이상을 지원하지 않는 이전 Jackson 버전을 사용하고 있을 수  있습니다 .

사용자 지정 역직렬화 기사 에 따르면 이전 섹션에서 제공한 JSON을 역직렬화하기 위해 역직렬화 클래스를 만드는 것으로 시작합니다.

public class CustomEnumDeserializer extends StdDeserializer<Distance> {

    @Override
    public Distance deserialize(JsonParser jsonParser, DeserializationContext ctxt)
      throws IOException, JsonProcessingException {
        JsonNode node = jsonParser.getCodec().readTree(jsonParser);

        String unit = node.get("unit").asText();
        double meters = node.get("meters").asDouble();

        for (Distance distance : Distance.values()) {
           
            if (distance.getUnit().equals(unit) && Double.compare(
              distance.getMeters(), meters) == 0) {
                return distance;
            }
        }

        return null;
    }
}

그런 다음 Enum에서 @JsonDeserialize 어노테이션을 사용하여 사용자 지정 deserializer를 지정합니다.

@JsonDeserialize(using = CustomEnumDeserializer.class)
public enum Distance {
   ...
}

결과는 다음과 같습니다.

assertEquals(Distance.MILE, city.getDistance());

5. 결론

이 기사에서는 Java Enums의 직렬화 및 역직렬화 프로세스와 형식을 더 잘 제어하는 ​​방법을 설명했습니다 .

이러한 모든 예제와 코드 스니펫의 구현은 GitHub 에서 찾을 수 있습니다 .

Jackson footer banner