Java, Jackson ObjectMapper serialize/deserialize
    
      2020-06-23
    
    
    
  
  
	
	
	
	
  
  Spring 쓸 떄랑 왜 다른거야……………………..
아무튼 정리 시작..
대상이 될 json
{
  id: "22",
  name: "herdin",
  level: "45",
  desc: "rekt-developer",
  timestamp: "20200623111213"
}
java code 로 표현하면 이렇다.
String jsonStr = "{ id: \"22\", name: \"herdin\", level: \"45\", desc: \"rekt-developer\", timestamp: \"20200623111213\" }";
아무 생각 없이 deserialize 하면
ObjectMapper objectMapper = new ObjectMapper();
Champion champion = objectMapper.readValue(jsonStr, Champion.class);
@Data
public static class Champion {
    Integer id;
    String name;
    Long level;
    String desc;
}
아래와 같은 오류가 난다.
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('i' (code 105)): was expecting double-quote to start field name
쌍따옴표로 json object 의 키값이 쌓여져있지 않다는 건데, 설정을 해주면 된다.
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
다시한번 하면, 아래와 같은 오류가 난다.
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "timestamp" (class com.harm.unit.data.json.JacksonStudy001$Champion), not marked as ignorable (4 known properties: "desc", "id", "level", "name"])
일부러 deserialize class 에 timestamp 를 만들지 않았다. class field 에 없는 json field 는 무시하고 싶으면 두가지 방법이 있다.
ObjectMapper 에 설정을 추가하는 방법
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
deserialize class 에 annotation 을 추가하는 방법
@JsonIgnoreProperties(ignoreUnknown = true)
@Data
public static class Champion {
    Integer id;
    String name;
    Long level;
    String desc;
}
이번엔 만들지 않았던 timestamp 변수도 추가했다.
@Data
public static class Champion {
    Integer id;
    String name;
    Long level;
    String desc;
    private LocalDateTime timestamp;
}
그래도 오류가 나는데,
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.time.LocalDateTime` (no Creators, like default construct, exist): no String-argument constructor/factory method to deserialize from String value ('20200623111213')
뭐라는지 보면, LocalDateTime 을 생성할 수 없는데 String 타입을 받는 생성자/팩토리 가 없다고한다.
LocalDateTime 을 뒤져보면 정말 없다. 이거 스프링은 어떻게 해주는거야..??
아래와 같은 Deserializer 를 만들고,
public static class CustomLocalDateTimeDeserializer extends StdDeserializer<LocalDateTime> {
    private static DateTimeFormatter formatter =
            DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
    public CustomLocalDateTimeDeserializer() {
        this(null);
    }
    @Override
    public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        String date = p.getText();
        return LocalDateTime.parse(date, formatter);
    }
    public CustomLocalDateTimeDeserializer(Class<LocalDateTime> t) {
        super(t);
    }
}
deserialize class field 에 annotation 으로 알려주면 되는데, 뭔가 이상하다.. 이렇게 안해도 될것같은데..
@Data
public static class Champion {
    Integer id;
    String name;
    Long level;
    String desc;
    @JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
    private LocalDateTime timestamp;
}
