View
JAVA에서 JSON 데이터를 응답으로 보내기 위한 다양한 직렬화 방법이 존재한다.
그중Jackson 라이브러리 사용한 직렬화(Serialize) 방법을 알아보자.
(예전에 진행했던 카카오톡 챗봇 예제를 이용해 진행했습니다.)
1. 직렬화(Serialize)란?
- Java에서 사용되는 Object 또는 Data를 외부의 자바 시스템에서도 사용할 수 있도록 byte 형태로 데이터를 변환하는 기술
- 범용적인 API나 데이터를 변환하여 추출할 때 많이 사용된다.
- Java Object → Json Data 변환
2. 예제
어떤 서드파티 애플리케이션을 사용하기 위해 정해진 Json 응답 형식이 있다고 생각해보자.
정해진 응답 형식을 만족해야만 애플리케이션이 정상적으로 동작할 것이다.
아래는 카카오톡 챗봇에서 요구하는 Json 응답 형식이다.
{
"version": "2.0",
"template": {
"outputs": [
{
"simpleText": {
"text": "string"
}
}
]
}
}
이러한 구조를 가진 Json 데이터를 응답으로 넘겨줘야만 정상적으로 메시지가 출력된다.
Java 객체를 Json 형태로 바꾸어 응답을 해야 하기 때문에 이를 직렬화해보자.
1. HashMap을 이용한 직렬화
먼저, HashMap을 이용한 직렬화 방법이다.
HashMap<String, Object> resultJson = new HashMap<>();
List<HashMap<String,Object>> outputs = new ArrayList<>();
HashMap<String,Object> template = new HashMap<>();
List<HashMap<String,Object>> quickReplies = new ArrayList<>();
HashMap<String, Object> simpleText = new HashMap<>();
HashMap<String, Object> text = new HashMap<>();
HashMap<String, Object> label = new HashMap<>();
resultJson.put("version", "2.0");
text.put("text", "응답 메세지");
simpleText.put("simpleText", text);
outputs.add(simpleText);
template.put("outputs", outputs);
resultJson.put("template", template);
위의 Json 구조대로 HashMap과 List를 만들어서 값을 하나씩 넣어주고 있다.
정상적으로 Json 데이터가 만들어지지만 가독성이 떨어지고 유지보수에 좋지 않을 것 같다.
이러한 코드를 DTO 형태로 만들어 개선해보자.
2. DTO를 이용한 직렬화
복잡한 구조를 가지고 있는 Json 데이터를 DTO로 만들기 쉽지 않다. 하지만 IntelliJ는 다양한 플러그인을 제공하고 있고 이를 이용하면 쉽게 처리할 수 있다.
Json → DTO를 쉽게 만들어주는 DTO Generator라는 플러그인이 존재한다. 이용하면 손쉽게 DTO를 만들어낼 수 있다.
자세한 내용은 DTO Generator에 정리해 놓았다.
카카오 챗봇에서 사용되는 다양한 메시지 전송 방법(말풍선 메시지, 카드형 메시지, 기본 메시지 등)의 JSON 응답 형식은 기본 메시지 응답에서 확장된 형태를 가지고 있다.
아래의 예시를 보면, 말풍선 메시지 응답은 기본 메시지 응답 형식에서
quickReplies가 추가된 형태를 가지고 있다.
이 두 가지 타입의 응답 형식을 만족하는 DTO를 만들어보자.
먼저, DTO Generator를 이용해 DTO를 만들어준다.
responseDTO의 구성 파일들을 차근차근 살펴보자.
1. MessageDTO
최상단의 version과 template를 나타내는 Class이다.
public class MessageDTO {
@JsonProperty("version") // "version"으로 Mapping
private String version;
@JsonProperty("template")
private Template template;
public MessageDTO(String version, Template template) {
this.version = version;
this.template = template;
}
}
@JsonProperty → Jackson Annotation
- 명시된 value를 논리 속성으로 인식하여 Mapping
- 명시하지 않을 시 필드명으로 Mapping
2. Template
@RequiredArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Template {
@JsonProperty("quickReplies")
private List<QuickReplies> quickReplies;
@JsonProperty("outputs")
@NonNull
private List<Outputs> outputs;
public Template(List<QuickReplies> quickReplies, List<Outputs> outputs) {
this.quickReplies = quickReplies;
this.outputs = outputs;
}
}
@RequiredArgsConstructor → Lombok Annotation
- final이나 @NonNull이 명시된 필드 값만 파라미터로 받는 생성자를 생성
@JsonInclude(JsonInclude.Include.NON_NULL) → Jackson Annotation
- 필드 값이 NonNull인 경우에만 데이터를 직렬화한다. 즉, Null 값인 필드는 직렬화에서 제외
3. QuickReplies
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
public class QuickReplies {
@JsonProperty("label")
private String label;
@JsonProperty("action")
private String action;
@JsonProperty("messageText")
private String messageText;
@JsonProperty("blockId")
private String blockId;
public QuickReplies(String label, String action, String messageText, String blockId) {
this.label = label;
this.action = action;
this.messageText = messageText;
this.blockId = blockId;
}
}
@NoArgsConstructor → Lombok Annotation
- 파라미터가 없는 기본 생성자를 생성
4. Outputs
public class Outputs {
@JsonProperty("simpleText")
private SimpleText simpleText;
public Outputs(SimpleText simpleText) {
this.simpleText = simpleText;
}
}
5. SimpleText
public class SimpleText {
@JsonProperty("text")
private String text;
public SimpleText(String text) {
this.text = text;
}
}
3. DTO를 이용한 응답 메시지 만들기
말풍선 응답 메시지
List<Outputs> outputs = new ArrayList<>();
List<QuickReplies> quickReplies = new ArrayList<>();
outputs.add(
new Outputs(
new SimpleText("응답 메세지")
)
);
quickReplies.add(
new QuickReplies("돌아가기", "block", "돌아가기", "5e54a8bf8192ac0")
);
Template template = new Template(quickReplies, outputs);
MessageDTO messageDTO = new MessageDTO("2.0", template);
생성자를 통해 원하는 값을 넣어주고 있다.
위에 설명한 대로 @JsonInclude(JsonInclude.Include.NON_NULL)을 명시한 필드는 값이 Null이면 직렬화에 포함하지 않는다. 따라서 원하는 응답 형식을 유연하게 설정할 수 있다.
기본 응답 메시지
List<Outputs> outputs = new ArrayList<>();
outputs.add(
new Outputs(
new SimpleText("응답 메세지")
)
);
Template template = new Template(outputs);
MessageDTO messageDTO = new MessageDTO("2.0", template);
'BackEnd > Java' 카테고리의 다른 글
[Java8] 자바에서 제공하는 함수형 인터페이스 (0) | 2021.05.04 |
---|---|
[Java8] 함수형 인터페이스와 람다 표현식 (0) | 2021.04.19 |
[Java] 역직렬화(Deserialize) (0) | 2020.07.16 |
[Java] JUnit5 - Assertion (0) | 2020.07.11 |
[Java] JUnit5을 이용한 테스트 시작하기 (0) | 2020.07.03 |