소개

  • Jackson은 자바에서 JSON(Javascript Objet Notation)을 사용하기 위해 사용하는 라이브러리 중 하나입니다.
  • 직렬화(serialization)는 데이터를 전송하거나 저장하기 위해 데이터를 적절한 포맷으로 변환하는 과정입니다. 프로그래밍 언어나 플랫폼에 독립적이고 표준화된 포맷이 직렬화에 많이 쓰이는데, JSON은 이런 포맷 중 하나입니다.
  • 프로젝트 내 Jackson Library 사용 중 LocalDateTime 포맷 직렬화 중 발생한 에러 조치 방법을 공유하고자 합니다.
  • Jackson 라이브러리 관련 내용은 아래 링크를 참조 바랍니다.
https://github.com/FasterXML/jackson

 

 

이 글의 간략한 PROCESS

  1. 자바8부터 지원하는 LocalDateTime, LocalDate를 제외한 다른 데이터 타입 필드를 가지는 객체 생성
  2. Serialize → Deserialize 작동 여부 확인
  3. LocalDateTime과 LocalDate를 객체에 추가
  4. Serialize → Deserialize 작동 여부 확인(오류 발생 확인)
  5. 해결 방법 공유

Jackson 사용방법

라이브러리는 Maven Repository를 통해 받을 수 있습니다.

https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.3</version>
</dependency>


다양한 데이터 타입이 정상 작동하는지 여부를 확인하기 위해 다양한 타입의 필드를 가진 SampleObject 클래스와 테스트를 위한 간단한 메인 클래스를 만들었습니다.

package mech2cs;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class SampleObject {

    public int int_ = 0;
    public Integer integerWrapper_ = Integer.valueOf(0);

    public String string_ = "testString";

    public double double_ = 0.0;
    public Double doubleWrapper_ = Double.valueOf(0.0);

    public float float_ = 0l;
    public Float floatWrapper_ = Float.valueOf(0l);

    public char char_ = 'a';
    public Character characterWrapper_ = Character.valueOf('a');

    public List<String> list_ = Arrays.asList("a", "b", "c");;
    public Map<String, String> map_ = Map.of("key1","value1","key2","value2");;
    public Set<String> set_ = Set.of("a","b");;

}

 

package mech2cs;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) {

        // 다양한 데이터 필드를 가진 객체 생성
        SampleObject sampleObject = new SampleObject();

        // Jackson Library를 활용한 {JAVA 객체} -> {JSON} 변환
        ObjectMapper objectMapper = new ObjectMapper();
        String serializedStr = null;
        try {
            serializedStr = objectMapper.writeValueAsString(sampleObject);
            System.out.println(serializedStr);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        // Jackson Library를 활용한 {JSON} -> {JAVA 객체} 변환
        try {
            SampleObject resultObject = objectMapper.readValue(serializedStr, SampleObject.class);
        } catch (JsonProcessingException e) {
            System.out.println("Deserialize Failed");
            e.printStackTrace();
        }
    }
}


클래스 실행 결과는 아래와 같으며, 모든 데이터 타입들이 Json 형태로 잘 저장되는 것을 알 수 있습니다.

// 보기 편하게 줄바꿈
{
	"int_":0,
	"integerWrapper_":0,
	"string_":"sampleString",
	"double_":0.0,
	"doubleWrapper_":0.0,
	"float_":0.0,
	"floatWrapper_":0.0,
	"char_":"a",
	"characterWrapper_":"a",
	"list_":["a","b","c"],
	"map_":{"key2":"value2","key1":"value1"},
	"set_":["a","b"]
}


하지만 아래와 같이 SampleObject에 LocalDateTime과 LocalDate를 추가한 후 Main 메서드를 실행하게 되면 com.fasterxml.jackson.databind.exc.InvalidDefinitionException 에러가 발생하게 됩니다.

package mech2cs;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class SampleObject {

    public int int_ = 0;
    public Integer integerWrapper_ = Integer.valueOf(0);

    public String string_ = "testString";

    public double double_ = 0.0;
    public Double doubleWrapper_ = Double.valueOf(0.0);

    public float float_ = 0l;
    public Float floatWrapper_ = Float.valueOf(0l);

    public char char_ = 'a';
    public Character characterWrapper_ = Character.valueOf('a');

    public List<String> list_ = Arrays.asList("a", "b", "c");;
    public Map<String, String> map_ = Map.of("key1","value1","key2","value2");;
    public Set<String> set_ = Set.of("a","b");;

    // 새롭게 추가된 필드
    public LocalDateTime localDateTime_ = LocalDateTime.now();
    public LocalDate localDate_ = LocalDate.now();

}

해결방법

Jackson은 자바 8부터 추가된 LocalDateTime과 LocalDate 타입을 지원하기 위해 몇가지 모듈을 추가하였습니다 (아래 링크 참조). 모듈을 사용하기 위해 추가로 maven dependecies를 추가해야 합니다.

https://github.com/FasterXML/jackson-modules-java8
<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-parameter-names</artifactId>
    <version>2.12.3</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jdk8</artifactId>
    <version>2.12.3</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.12.3</version>
</dependency>


위 링크에서 추천하는 방법을 통해 ObjectMapper에 모듈을 추가하는 코드를 넣고 실행하면 정상 결과를 출력하는 것을 볼 수 있습니다. (모듈 추가 방법1과 방법2 중 선택 가능합니다)

package mech2cs;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;

public class Main {
    public static void main(String[] args) {

        // 다양한 데이터 필드를 가진 객체 생성
        SampleObject sampleObject = new SampleObject();

        // Jackson Library를 활용한 {JAVA 객체} -> {JSON} 변환
        
        // 모듈 추가 방법 1
        ObjectMapper objectMapper = JsonMapper.builder()
                .addModule(new ParameterNamesModule())
                .addModule(new Jdk8Module())
                .addModule(new JavaTimeModule())
                .build(); // 모듈 추가
        // 모듈 추가 방법 2
        // ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();

        String serializedStr = null;
        try {
            serializedStr = objectMapper.writeValueAsString(sampleObject);
            System.out.println(serializedStr);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        // Jackson Library를 활용한 {JSON} -> {JAVA 객체} 변환
        try {
            SampleObject resultObject = objectMapper.readValue(serializedStr, SampleObject.class);
        } catch (JsonProcessingException e) {
            System.out.println("Deserialize Failed");
            e.printStackTrace();
        }
    }
}
{
	...
	"localDateTime_":[2021,5,31,1,24,50,401107591],
	"localDate_":[2021,5,31]
}

+ Recent posts