문제
Cannot find a (Map) Key deserializer for type [simple type, com.example.GroupView]
Map의 키를 단순 String이 아닌 클래스로 했더니 Jackson의 역직렬화 중 에러 발생
키로 사용하는 코드는 아래와 같이 간단한 DTO 객체
public class GroupView {
public GroupView(String uuid, String name, String alias) {
this.uuid = uuid;
this.name = name;
this.alias = alias;
}
private final String uuid;
private final String name;
private final String alias;
}
원인
에러 메시지에 정확하게 나와 있듯, 해당 타입에 대한 deserializer가 구현되어있지 않기 때문. Serializable을 implements 한다고 해결되지는 않았다.
재밌는건 그 전에 Map의 key로 제법 여러가지 데이터를 담고 있는 enum을 넣었을 때는 아무런 문제가 없었는데, 객체가 들어가니 바로 문제가 생긴 것 이었다.
기본적으로 Jackson은 자바 Map을 JSON 객체로 직렬화 하기 때문에 Map의 key 또한 어떻게든 String으로 직렬화 되어야 한다. 그래서 기본적으로는 문자열, 숫자타입, enum 타입만을 제공하고 그 외의 타입은 오브젝트매퍼가 어찌할 바를 모르는 것 이다.
컴파일 타임에 문제가 되면 참 좋았겠지만, 직렬화를 할 때가 되어서야 비로소 에러가 발생한다.
해결
해결방법은 몇 가지가 있다.
일단 당연하게도 Map에 대한 serializer와 deserializer를 구현해주는 것이 근본적인 해결 방안이 되겠다.
SimpleModule을 상속한 모듈을 작성하여, KeyDeserializer를 등록 한다.
public class CustomJacksonModule extends SimpleModule {
public CustomJacksonModule() {
addKeyDeserializer(GroupView.class, new KeyDeserializer() {
@Override
public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException {
return null;
}
});
}
}
그러고 나서는 모듈을 등록한다.
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new CustomJacksonModule());
하다 보니 이렇게 까지 해야 하나 싶다.
심지어 모듈간 데이터를 주고 받아야하는데 맵의 키로 오브젝트를 줬더니 영 문제가 많다.
결론
Map의 key로 Object가 되어 있는데 그걸 JSON 직렬화 해야 하는 일이 생겼다면 뭔가 잘못 진행되고 있다는 신호로 생각하고 개선해보자. API스펙의 키값에 오브젝트가 들어가야 할 일은 드물 것이다.
References
'Development > Daily Error' 카테고리의 다른 글
Safari 에서만 localhost에 쿠키가 저장 안되는 문제 해결 (0) | 2023.02.19 |
---|---|
[일간에러] Different lower_case_table_names settings for server ('2') and data dictionary ('0'). (0) | 2023.01.07 |
[iRods] 데이터 오브젝트가 포함된 리소스 삭제하기 CAT_RESOURCE_NOT_EMPTY (0) | 2022.10.17 |
[Java Mail] Could not convert socket to TLS; 문제 해결 (0) | 2022.10.12 |
[POI] 엑셀의 숫자를 소수점으로 파싱하는 문제 해결하기 (0) | 2022.08.25 |