[RabbitMQ] JSON Message Format 사용하기 - 2

2021. 11. 1. 18:46 Spring Cloud/RabbitMQ

이번 글에서는 RabbitMQ에서 사용하는 JSON Message Format을 Customize 해보도록 하겠습니다.

1. Customize JSON Format

앞선 글에선 Jackson의 ObjectMapper를 사용해 Employee Entity를 JSON String 형식으로 변경할 수 있었습니다.

Employee

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Employee {

    private String employeeId;

    private String name;

    private LocalDate birthDate;
}

기본적으로 Jackson은 Default로 구현되어있는 serialize() 메서드를 참고해 아래와 같이 Serialize를 수행합니다.

{
    "employeeId":"minho",
    "name":"test",
    "birthDate":    {    
        "year":2019,
        "month":"DECEMBER",
        "dayOfMonth":30,
        "monthValue":12,
        "dayOfYear":364,
        "leapYear":false,
        "dayOfWeek":"MONDAY",
        "era":"CE",
        "chronology":{
                    "id":"ISO",
                        "calendarType":"iso8601"
                        }
         }
}

"employeeId"와 "name"의 JSON key값은 Entity의 필드명으로 value 값은 사용자가 입력한 "minho"와 "test"로 Serialize된 것을 확인할 수 있습니다.

하지만, birthDate는 지나치게 복잡하게 Serialize 되어있는 것을 확인할 수 있습니다. Spring 내부적으로 LocalDate 객체의 serialize() 값이 위 처럼 구현되어있기 때문에 위와 같이 Serialize 된 것입니다.

 

사용자는 Customize 기능을 이용해 위와 같은 Default JSON Format을 변경할 수 있습니다.

2. @JsonProperty

@JsonProperty를 사용하면 JSON Format의 Key값을 변경할 수 있습니다.

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Employee {

    @JsonProperty("employee_id")
    private String employeeId;

    private String name;

    @JsonProperty("birth_date")
    private LocalDate birthDate;
}

위와 같이 변경 후 Message를 열어보면, 아래와 같이 JSON String의 key값이 변경된 것을 확인할 수 있습니다.

✔ 변경전 : employeeId / birthDate
✔ 변경후 : employee_id / birth_date

{
    "employee_id":"minho",
    "name":"test",
    "birth_date":    {    
        "year":2019,
        "month":"DECEMBER",
        "dayOfMonth":30,
        "monthValue":12,
        "dayOfYear":364,
        "leapYear":false,
        "dayOfWeek":"MONDAY",
        "era":"CE",
        "chronology":{
                    "id":"ISO",
                        "calendarType":"iso8601"
                        }
         }
}

3. @JsonSerialize

@JsonSerialize를 사용하면 JSON Format의 Serialize 형식을 변경할 수 있습니다.

@JsonSerialize 사용해 LocalDate의 Serialize 값에서 불필요한 부분을 제거하고 필요한 부분만 Serialize 해보겠습니다.

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Employee {

    private String employeeId;

    private String name;

    @JsonSerialize(using = CustomLocalDateSerializer.class)
    private LocalDate birthDate;
}

@JsonSerialize(using = CustomLocalDateSerializer.class)을 입력해 앞으로 birthDate는 Serialize할 때 Default로 구현되어있는 값 대신 CustomLocalDateSerializer에 구현한 serialize 메서드를 사용하도록 지정합니다.

CustomLocalDateSerializer의 구조는 아래와 같습니다.

public class CustomLocalDateSerializer extends StdSerializer<LocalDate> {

    private static final long serialVersionUID = 1L;
    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MMM-dd");

    public CustomLocalDateSerializer() {
        this(null);
    }

    public CustomLocalDateSerializer(Class<LocalDate> t) {
        super(t);
    }

    @Override
    public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider arg2)
            throws IOException, JsonProcessingException {

        gen.writeString(formatter.format(value));
    }
}

위의 Custom Serializer를 이용하면 복잡한 Local Date의 Serialize 값을 "yyyy-MMM-dd" 형식으로 변경해 사용할 수 있습니다.

Producer Application을 실행시킨뒤 Message를 확인해보면 아래와 같이 LocalDate가 Serialize된 값이 변경된것을 확인할 수 있습니다.

 

 

4. @JsonDeserialize

만약 @JsonSerialize를 사용해서 JSON Stirng의 Format을 변경했다면, 반대로 Consumer에서는 @JsonDeserialize를 사용해 JSON String 값을 이전 객체의 모양으로 적절히 Deserialize 해야합니다.

만약 이를 구현하지 않는다면, Consumer에서는 해당 JSON String 값을 이전의 객체모양으로 Parse할 수 없습니다.

 

 

Consumer쪽 Entity에는 아래와 같이 Deserialize에 사용할 Custom Class를 지정해주면 됩니다.

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Employee {

    private String employeeId;

    private String name;

    @JsonDeserialize(using = CustomLocalDateDeserializer.class)
    private LocalDate birthDate;
}

 

CustomLocalDateDeserializer의 구조는 아래와 같습니다.

public class CustomLocalDateDeserializer extends StdDeserializer<LocalDate> {

    private static final long serialVersionUID = 1L;
    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MMM-dd");

    public CustomLocalDateDeserializer() {
        super(LocalDate.class);
    }

    @Override
    public LocalDate deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        return LocalDate.parse(parser.readValueAs(String.class), formatter);
    }

}

5. 정리

✔ Jackson의 ObjectMapper 클래스를 사용하면 "Entity to JSON" / "JSON to Entity"가 가능하다.

✔ Producer에서 Customize한 Serialize Class를 사용해 JSON String Format을 변경한다면, Consumer에서는 적절한 Deserialize Class를 사용해 JSON Stirng을 기존의 Entity로 Deserialize 해야 한다.


참고 자료 : https://www.udemy.com/course/rabbitmq-java-spring-boot-for-system-integration/

출처 : https://minholee93.tistory.com/entry/RabbitMQ-JSON-Message-Format-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-2