티스토리 뷰
개발시 발생한 문제를 개인적으로 다시 반복하지 않기 위해 정리함.
<개요>
매번 HTTP 요청을 통해 받는 JSON String 을 Jackson 의 ObjectMapper 를 통해 Map 의 Key-Value 형태로 변환하여 사용하였다.
그러다 Object Mapping을 좀 더 자동화하고 필드를 Getter 형태로 편리하게 사용할 수 없을까 고민하다가 사용하게 된 것이
JSON Serialization, Deserialization 이다.
<문제 상황>
가뜩이나 영어 실력도 부족해서 영문서 번역이 오래걸리는데, 일정까지 촉박하여 마음이 급했다. 그래서
여기저기 다른 블로그나 문서들을 참조하여 이렇게 해보고 저렇게 해보고 대충 끼워맞추기식으로 코딩을 하다보니
다음과 같은 오류가 발생했다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class net.****.***.svc.**.http.json.model.Time and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: net.****.***.svc.**.http.json.RetrieveTimerInfoResponse["timerlist"]->java.util.ArrayList[0]->net.****.***.svc.**.http.json.model.DeviceTimerSet["timer"]->java.util.ArrayList[0]->net.****.***.svc.**.http.json.model.Timer["time"]) at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:59) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:26) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:569) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:597) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:142) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:100) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:21) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:186) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:569) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:597) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:142) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:100) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:21) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:186) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:569) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:597) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:142) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:118) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:2718) ~[jackson-databind-2.2.3.jar:na] at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:2210) ~[jackson-databind-2.2.3.jar:na] | cs |
<문제 분석>
가장 윗줄만 봐도 알 수 있는 오류였다..
No serializer found for class net.****.***.svc.**.http.json.model.Time and no properties discovered to create BeanSerializer
Time 클래스에서 Serializer 를 찾을 수 없고, BeanSerializer 를 생성하기 위한 프로퍼티를 찾을 수 없었다는 말이다.
Time 클래스는 직접 만든 엔티티클래스인데, 만들 때 ObjectMapper 가 직렬화할 때 필요한 무언가의 설정을 안해줬다는 것이다.
기본적으로 Jackson 2.x 에서 public 필드 또는 getter 메소드가 존재하는 필드에만 동작하게 되어있다.
즉, 저 오류는 필드에 private 걸어놓고 getter 안만들어 놓았다는 소리와 비슷하다. (다른 설정방법도 존재하므로 비슷하다고 표현함)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import com.fasterxml.jackson.annotation.JsonProperty; public class Time { private String week; private String time; public Time( @JsonProperty("week") String week, @JsonProperty("time") String time) { this.week = week; this.time = time; } //Getter Omitted } | cs |
1 2 3 4 | ObjectMapper jsonMapper = new ObjectMapper(); jsonMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY); String jsonString = jsonMapper.writeValueAsString(new SomeObjectWithoutGetter()); | cs |
2. Class 차원에서 ObjectMapper가 필드를 감지할 수 있도록 세팅해주기.
: Class 에 @JsonAutoDetect annotation 을 통해 Visibility 를 아래와 같이 설정해준다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; @JsonAutoDetect(fieldVisibility = Visibility.ANY) public class Time { private String week; private String time; public Time( @JsonProperty("week") String week, @JsonProperty("time") String time) { this.week = week; this.time = time; } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class Time { private String week; private String time; public Time( @JsonProperty("week") String week, @JsonProperty("time") String time) { this.week = week; this.time = time; } public String getWeek() { return week; } public String getTime() { return time; } } | cs |
<결론>
내부적으로 Jackson 이 Object를 Mapping 하면서 각 필드에 대해 Getter 를 활용하는 것으로 보인다.
이는 3과 같이 Getter 메서드를 클래스에서 지원하거나,
그렇지 않을 경우, ObjectMapper 가 필드들을 잘 탐지할 수 있도록
1, 2 와 같은 방법을 통해 설정해주어야 정상적으로 Mapping이 작동한다는 것이다.
<참조>
Baeldung - Do JSON right with Jackson : 바로가기
Stackoverflow - Serializing with Jackson (JSON) - getting “No serializer found”? : 바로가기
'프로그래밍 > Java' 카테고리의 다른 글
String equals(): difference between variable.equals("xx") and "xx".equals(variable). (0) | 2017.06.09 |
---|---|
Directory 만들기 (0) | 2014.10.21 |
- Total
- Today
- Yesterday
- json
- "
- 붙여넣기
- 기한
- shapeshifter
- commit
- equals
- 클립보드
- 백그라운드
- gcutil
- serialization
- 멀티프로세싱
- github
- Eclipse
- 페이스북
- variable
- 생산자
- directory
- 당신 없는 회사에 가고 싶다
- java
- Jackson
- NullPointerException
- jstat
- 대학의 정석
- 팀플
- migrate
- 페북
- 디렉토리
- 템플릿 메소드
- Template Method
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |