Spring

[ Springboot ] Jackson 라이브러리와 POJO, JSON 변환

구티맨 2020. 5. 27. 16:08

Springboot에서 컨트롤러를 개발하면, JSON으로 값을 받아 Java Object에 값을 저장하고,

반대로 Java Object 값을 JSON 으로 변환해서 응답으로 주는 경우가 많다.( 또는 XML )

직접 String 으로 JSON 을 만들거나, JSON 값을 Java Object에 일일히 값을 설정해줘도 되지만

Spring과 Jackson 라이브러리를 함께 사용하면, JSON <-> POJO 간 변환을 알아서 해준다.

POJO : Plain Old Java Object의 약자로 특정 자바 모델이나 기능, 프레임워크를 따르지 않는 순수? 자바 오브젝트 이다.

Jackson : Java를 위한 고성능 JSON 라이브러리이다. Spring에서는 기본으로 탑재가 되어있다.

POJO

먼저, JSON 값을 저장할 그리고, JSON 값으로 변환할 POJO class를 하나 만들어 준다.

@Getter
@Setter
public class UserVO {
    private String name;
    private String id;
}

Jackson은 Property 값을 기준으로 변환을 해주고, Getter/Setter의 이름을 프로퍼티로 사용을 한다.

( 클래스 멤버가 없어도 된다. 멤버 변수를 기준으로 property를 사용하기 위해서는 @JsonProperty를 사용하면 되는데 아래에서 추가로 설명을 한다. )

그래서 POJO <-> JSON 변환시에 JSON key값은 POJO의 property 값과 매치가 되어야 한다.

Controller - @RequestBody, @ResponseBody

이제, 컨트롤러에서 JSON을 입력 받고, 리턴해주는 부분을 작성해보자.

@PostMapping("/user")
@ResponseBody
public Object convertPOJOandJSON(@RequestBody UserVO userVO){
    log.info("user id: " + userVO.getId() + ", user name:" + userVO.getName());
    return userVO;
}

POST로 JSON을 받을 수 있도록 @PostMapping과 @RequestBody 를 선언한다.

POST로 JSON을 보내게 되면, UserVO객체에 JSON 값이 저장된다.

JSON 값을 리턴하도록 Object 리턴 타입과 @ResponseBody를 선언한다.

테스트

curl --location --request POST 'localhost:8080/user' \
--header 'Content-Type: application/json' \
--data-raw '{"name":"홍홍홍","id":"hong"}'

위와 같이 POST 요청을 보내면, UserVO 객체의 name과 id 변수에 값이 저장된다.

그리고, 이 객체를 리턴해 주면 아래와 같이
POJO의 property 명으로 Json의 key, POJO의 property 값으로 Json의 value가 만들어진다.

{"name":"홍홍홍","id":"hong"}

ResponseEntity

JSON 응답 시에, @ResponseBody 대신에 ResponseEntity 리턴 타입을 사용해도
body에 POJO가 들어가면 JSON 으로 변환이 되므로 용도에 맞게 골라서 사용을 하면 된다.

@PostMapping("/userEntity")
public ResponseEntity convertPOJOandHTTPJSON(@RequestBody UserVO userVO){
    return ResponseEntity.ok().body(userVO);
}

Jackson Annotation

@JsonInclude

Json 에 property를 생략할지에 대한 조건을 줄 수 있는데, NON_EMPTY에 대해서만 간략하게 알아보자.

타입에 따라 생략 조건이 다른데 아래 표와 같다.

타입 생략 조건
String length() 리턴 값이 0
Collection, Map isEmpty() 리턴 값이 0
Others null
@Getter
@Setter
public class UserVO {
    private String name;
    private String id;
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private String mobileNum;
}
POST http://localhost:8080/user
Content-Type: application/json

{
  "id": "xoxo",
  "name": "홍홍"
}

# @JsonInclude(JsonInclude.Include.NON_EMPTY) 미사용시
{
  "name": "홍홍",
  "id": "xoxo",
  "mobileNum": null
}

# @JsonInclude(JsonInclude.Include.NON_EMPTY) 사용시
{
  "name": "홍홍",
  "id": "xoxo"
}

@JsonProperty

Property 를 getter/setter의 이름을 가지고 사용하지만, 변수에 property이름을 지정해서 사용을 할 수도 있다.
mobileNum에 phone이라고 jsonproperty를 지정해주면, phone이라는 property 라는 이름을 사용하게 된다.

public class UserVO {
    private String name;
    private String id;
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    @JsonProperty("phone")
    private String mobileNum;
}
POST http://localhost:8080/user
Content-Type: application/json

{
  "id": "xoxo",
  "name": "홍홍",
  "mobileNum": "a"
}

# 응답
{
  "name": "홍홍",
  "id": "xoxo"
}

POST http://localhost:8080/user
Content-Type: application/json

{
  "id": "xoxo",
  "name": "홍홍",
  "phone": "a"
}

# 응답
{
  "name": "홍홍",
  "id": "xoxo",
  "phone": "a"
}

@JsonUnwrapped

property 를 포함하지 않고, property 의 object만 포함을 해준다.( 배열에는 적용되지 않는다 )

public class UserVO {
    private String name;
    private String id;
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    @JsonProperty("phone")
    private String mobileNum;
    @JsonUnwrapped
    private AddressVO address;
}

# @JsonUnwrapped 미사용시,
# 요청
POST http://localhost:8080/user
Content-Type: application/json

{
  "id": "xoxo",
  "name": "홍홍",
  "phone": "a",
  "address": {"sido": "부산광역시","gungu": "해운대구"}
}

# 응답
{
  "name": "홍홍",
  "id": "xoxo",
  "address": {
    "sido": "부산광역시",
    "gungu": "해운대구"
  },
  "phone": "a"
}

# @JsonUnwrapped 사용시,
# 요청
POST http://localhost:8080/user
Content-Type: application/json

{
  "id": "xoxo",
  "name": "홍홍",
  "phone": "a",
  "sido": "부산광역시","gungu": "해운대구"
}

# 응답
{
  "name": "홍홍",
  "id": "xoxo",
  "sido": "부산광역시",
  "gungu": "해운대구",
  "phone": "a"
}

이 외에도, @JsonIgnore, @JsonIgnoreProperties, @JsonPropertyOrder 등의 annotation 이 있다.

소스코드

https://github.com/ggamzang/spring-jackson