티스토리 뷰

Java

[Java] Json 변환 Jackson ObjectMapper

snail voyager 2022. 8. 1. 18:47
728x90
반응형

Overview

JSON 형태의 데이터를 java에서 활용할 수 있도록 데이터 타입을 변환해주는 기능

build.gradle

dependencies {
	implementation group:'com.fasterxml.jackson.core', name:'jackson-databind', version:'2.12.3'
}

readValue()

  • Text JSON → Object, JSON 데이터를 Java 객체로 역직렬화하는 데 사용
  • Object Mapper는 객체의 default 생성자가 필요
//json = {"name":"KKK","age":34,"cars":[{"name":"K5","car_number":"0161","TYPE":"SUV"},{"name":"K7","car_number":"1111","TYPE":"SEDAN"}]}
ObjectMapper objectMapper = new ObjectMapper();
var objectUser = objectMapper.readValue(json, User.class);

System.out.println(objectUser);	//User{name='KKK', age=34}
  • 문자열, 파일, URL, InputStream 등 여러 형식의 입력을 받을 수 있다.
<T> T readValue(Reader src, Class<T> valueType) throws IOException;
<T> T readValue(String content, Class<T> valueType) throws IOException;
<T> T readValue(InputStream src, Class<T> valueType) throws IOException;
<T> T readValue(URL src, Class<T> valueType) throws IOException;
<T> T readValue(File src, Class<T> valueType) throws IOException;

writeValueAsString()

  • Object → Text json,  Java 객체를 JSON 문자열로 직렬화하는 데 사용
  • Object Mapper가 객체의 get method를 활용
  • 객체에서 get method 이외의 method명에 get을 붙이면 안됨
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("snail", 34);

String json = objectMapper.writeValueAsString(user);
System.out.println(json);		//{"name":"snail", "age":34}

readTree()

  • JSON 데이터를 트리 구조로 파싱하려면 readTree() 메서드를 사용
  • JSON 문자열을 전달받아 해당 문자열을 트리 구조로 파싱한 JsonNode를 반환
  • JsonNode를 사용하여 JSON 데이터를 탐색하고 필요한 작업을 수행

JsonNode

  • JsonNode는 JSON 데이터를 표현하는 데 사용되는 트리 형식의 데이터 구조
  • 이 트리를 사용하여 JSON 데이터를 탐색하고 쿼리하거나 수정할 수 있다.
  • JsonNode에는 여러 가지 하위 클래스가 있으며, ObjectNode(객체), ArrayNode(배열), TextNode(텍스트), NumericNode(숫자), BooleanNode(부울) 등이 있다.
//json = {"name":"KKK","age":34,"cars":[{"name":"K5","car_number":"0161","TYPE":"SUV"},{"name":"K7","car_number":"1111","TYPE":"SEDAN"}]}
JsonNode jsonNode = objectMapper.readTree(json);        //JSON -> Object
String _name = jsonNode.get("name").asText();
int _age = jsonNode.get("age").asInt();
System.out.println("name : " + _name);
System.out.println("age : " + _age);

String _carList = jsonNode.get("cars").asText();    //null

JsonNode cars = jsonNode.get("cars");       // 객체에 접근할 때는 노드 객체로 불러와서
ArrayNode arrayNode = (ArrayNode)cars;      // ArrayNode 변환
List<Car> _cars = objectMapper.convertValue(arrayNode, new TypeReference<List<Car>>() {});      // object mapper 로 형변환
System.out.println(_cars);
//[Car{name='K5', carNumber='0161', type='SUV'}, Car{name='K7', carNumber='1111', type='SEDAN'}]

ObjectNode objectNode = (ObjectNode) jsonNode;
objectNode.put("name", "ghm");      //json 값 변경
objectNode.put("age", 37);
System.out.println(objectNode.toPrettyString());
/*
{
  "name" : "ghm",
  "age" : 37,
  "cars" : [ {
    "name" : "K5",
    "car_number" : "0161",
    "TYPE" : "SUV"
  }, {
    "name" : "K7",
    "car_number" : "1111",
    "TYPE" : "SEDAN"
  } ]
}
*/

get() 메서드

  • 존재하는 필드: 해당 JsonNode 반환
  • 존재하지 않는 필드: null 반환
  • null이 반환될 수 있기 때문에 NullPointerException을 방지하려면 직접 null 체크가 필요
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonExample {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        String json = "{ \"name\": \"Alice\", \"age\": 25 }";
        JsonNode rootNode = mapper.readTree(json);

        JsonNode nameNode = rootNode.get("name"); // 존재하는 필드
        JsonNode missingNode = rootNode.get("nonExistentKey"); // 없는 필드

        System.out.println(nameNode.asText()); // 출력: Alice
        System.out.println(missingNode);       // 출력: null

        // 아래 코드는 NullPointerException 발생 가능
        // System.out.println(missingNode.asText());
    }
}

path() 메서드

  • 존재하는 필드: 해당 JsonNode 반환
  • 존재하지 않는 필드: MissingNode 반환 (null이 아님)
  • MissingNode는 안전하게 asText(), asLong() 같은 변환 메서드를 사용할 수 있음
  • null을 반환하지 않으므로 NullPointerException 위험 없음
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonExample {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        String json = "{ \"name\": \"Alice\", \"age\": 25 }";
        JsonNode rootNode = mapper.readTree(json);

        JsonNode nameNode = rootNode.path("name"); // 존재하는 필드
        JsonNode missingNode = rootNode.path("nonExistentKey"); // 없는 필드

        System.out.println(nameNode.asText());  // 출력: Alice
        System.out.println(missingNode.asText()); // 출력: "" (빈 문자열)

        // 안전하게 숫자로 변환 가능
        System.out.println(missingNode.asLong()); // 출력: 0
    }
}

setSerializationInclusion()

  • 직렬화 시에 null 값이 포함되는지 여부를 설정하는 데 사용
  • JsonInclude.Include 열거형은 Jackson에서 직렬화 시에 어떤 필드를 포함할지를 결정하는 데 사용
    • ALWAYS: 항상 필드를 포함합니다. 즉, null 값을 가진 필드도 포함됩니다.
    • NON_NULL: null 값을 가진 필드를 제외하고 나머지는 포함합니다.
    • NON_ABSENT: Optional과 같은 컨테이너 타입의 필드에서 null 값이 아닌 경우에만 포함합니다.
    • NON_EMPTY: null, 빈 문자열, 빈 컬렉션 등을 제외하고 나머지는 포함합니다.
    • NON_DEFAULT: 기본값과 같지 않은 필드만 포함합니다. (주로 기본값이 null인 경우에 유용합니다)
    • USE_DEFAULTS: 기본 설정을 따릅니다. (기본값)
ObjectMapper objectMapper2 = new ObjectMapper();
objectMapper2.setSerializationInclusion(JsonInclude.Include.NON_NULL);

Car car3 = new Car();
car3.setName("GV80");
car3.setCarNumber("");
System.out.println("car3 : " + car3);   //String carNumber = "", String type = null, int createdYear = 0

String car3Json = objectMapper2.writeValueAsString(car3);
System.out.println("car3Json : " + car3Json);
//car3Json : {"name":"GV80","createdYear":0,"car_number":""}

SerializationFeature

Jackson에서 직렬화 시의 동작을 설정하는 데 사용

  • FAIL_ON_EMPTY_BEANS: 빈 객체를 직렬화할 때 실패합니다.
  • FAIL_ON_SELF_REFERENCES: 객체에 대한 자기 참조를 발견하면 실패합니다.
  • INDENT_OUTPUT: 출력을 들여쓰기하여 가독성을 높입니다.
  • WRITE_NULL_MAP_VALUES: null 값을 가진 맵 필드를 포함합니다.
  • WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED: 단일 요소 배열을 배열이 아닌 단일 값으로 직렬화합니다.
  • WRITE_ENUMS_USING_TO_STRING: 열거형을 직렬화할 때 toString() 메서드를 사용합니다.
  • WRITE_ENUMS_USING_INDEX: 열거형을 직렬화할 때 인덱스 값을 사용합니다.

DeserializationFeature

Jackson에서 역직렬화 시의 동작을 설정하는 데 사용

  • ACCEPT_EMPTY_STRING_AS_NULL_OBJECT: 빈 문자열("")을 null 객체로 처리합니다.
  • ACCEPT_SINGLE_VALUE_AS_ARRAY: 단일 값을 배열로 처리합니다.
  • FAIL_ON_UNKNOWN_PROPERTIES: 알려지지 않은 속성이 있는 경우 역직렬화를 실패시킵니다.
  • FAIL_ON_NULL_FOR_PRIMITIVES: 원시(primitive) 타입 필드에 null 값을 만나면 역직렬화를 실패시킵니다.
  • UNWRAP_SINGLE_VALUE_ARRAYS: 단일 값을 포함하는 배열을 단일 값으로 처리합니다.
  • READ_ENUMS_USING_TO_STRING: 열거형을 직렬화할 때 toString() 메서드를 사용하여 읽습니다.
  • READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE: 알려지지 않은 열거형 값이 있을 때 기본값을 사용하여 역직렬화합니다.
objectMapper2.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);   //객체에 없는 Json 필드는 역직렬화 무시

String json2 = "{\"name\":\"GV80\",\"unknown\":\"9999\"}";
Car car3Deserialization = objectMapper2.readValue(json2, Car.class);
System.out.println("car3Deserialization : " + car3Deserialization);
//Car{name='GV80', carNumber='null', type='null', createdYear=0}

MissingNode.getInstance()

  • 존재하지 않는 필드를 나타냅니다.
  • JSON에서 해당 필드가 아예 존재하지 않을 때 사용됩니다.
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.MissingNode;

public class JacksonExample {
    public static void main(String[] args) {
        JsonNode missingNode = MissingNode.getInstance();
        System.out.println(missingNode); // 출력: 
        System.out.println(missingNode.isMissingNode()); // 출력: true
    }
}

MissingNode.path("anyKey")의 동작 원리

  • MissingNode.getInstance()는 Jackson에서 존재하지 않는 필드를 표현하는 객체입니다.
  • MissingNode에서 .path("key")를 호출하면 항상 새로운 MissingNode를 반환합니다.
  • 출력값은 비어 있는 값처럼 보이며, .isMissingNode()를 호출하면 true를 반환합니다.

NullNode.getInstance()

  • null 값을 나타내는 노드입니다.
  • JSON에서 {"key": null} 같은 경우에 해당합니다.
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.NullNode;

public class JacksonExample {
    public static void main(String[] args) {
        JsonNode nullNode = NullNode.getInstance();
        System.out.println(nullNode); // 출력: null
        System.out.println(nullNode.isNull()); // 출력: true
    }
}

ObjectNode에서 빈 객체 생성

  • JSON {}처럼 비어 있는 객체를 표현하고 싶다면 ObjectNode를 사용
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class JacksonExample {
    public static void main(String[] args) {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode emptyObject = mapper.createObjectNode();

        System.out.println(emptyObject); // 출력: {}
    }
}

 

https://github.com/FasterXML/jackson-docs

https://www.baeldung.com/jackson

https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-core/latest/index.html

https://itsallbinary.com/jackson-vs-gson-vs-json-b-vs-json-p-vs-org-json-vs-jsonpath-java-json-libraries-features-comparison/#jsonbind

 

 

 

728x90
반응형

'Java' 카테고리의 다른 글

동작 파라미터화 코드 전달하기  (0) 2023.06.21
Optional  (0) 2022.09.18
Primitive vs Wrapper Class  (0) 2022.03.20
Functional Programming  (0) 2022.03.14
Lambda Expression  (0) 2020.09.14
반응형
300x250