2016-09-01 9 views
5

나는했습니다 같은 DTO 클래스 : 내 프로젝트에서JSON 일반적인 수집 직렬화

public class AnswersDto { 
    private String uuid; 
    private Set<AnswerDto> answers; 
} 

public class AnswerDto<T> { 
    private String uuid; 
    private AnswerType type; 
    private T value; 
} 

class LocationAnswerDto extends AnswerDto<Location> { 
} 

class JobTitleAnswerDto extends AnswerDto<JobTitle> { 
} 

public enum AnswerType { 
    LOCATION, 
    JOB_TITLE, 
} 

class Location { 
    String text; 
    String placeId; 
} 

class JobTitle { 
    String id; 
    String name; 
} 

것은 직렬화 및 JSONs의 직렬화에 사용 잭슨 라이브러리가있다.

제대로 예를 들어, 몸에 AnswersDto로 요청을 역 직렬화 할 수 AnswersDto (특수 주석을 사용) 또는 AnswerDto (주석뿐만 아니라) 클래스를 구성하는 방법 :

{ 
    "uuid": "e82544ac-1cc7-4dbb-bd1d-bdbfe33dee73", 
    "answers": [ 
     { 
      "uuid": "e82544ac-1cc7-4dbb-bd1d-bdbfe33dee73", 
      "type": "LOCATION", 
      "value": { 
       "text": "Dublin", 
       "placeId": "121" 
      } 
     }, 
     { 
      "uuid": "e82544ac-1cc7-4dbb-bd1d-bdbfe33dee73", 
      "type": "JOB_TITLE", 
      "value": { 
       "id": "1", 
       "name": "Developer" 
      } 
     } 
    ] 
} 

불행하게도 잭슨의 기본 맵 값으로 AnswerDto 개체는 Location 또는 JobTitle 클래스 유형의 개체 대신 LinkedHashMap에 있습니다. 사용자 정의 JsonDeserializer<AnswerDto>을 쓰거나 @JsonTypeInfo@JsonSubTypes을 사용하여 구성하면 충분합니까?

제대로 내가 사용하고

{ 
    "uuid": "e82544ac-1cc7-4dbb-bd1d-bdbfe33dee73", 
    "type": "LOCATION", 
    "value": { 
     "text": "Dublin", 
     "placeId": "121" 
    } 
} 

의 형태로 한 AnswerDto으로 요청을 직렬화하려면

AnswerDto<Location> answerDto = objectMapper.readValue(jsonRequest, new TypeReference<AnswerDto<Location>>() { 
}); 

을 다른 사용자 정의 구성없이.

+0

당신은 aswer 개체의 컬렉션을 가지고 있지만 하나의 응답 객체 직렬화하는? AnswersDto answers = objectMapper.readValue (jsonRequest, new TypeReference () {})를 사용하면 어떨까요? – reos

+0

모든 객체를'answers' 노드에서'Set '컬렉션으로 매핑하고 싶습니다. 불행히도이'TypeReference '과 함께'objectMapper'를 사용할 때 콜렉션의 모든 AnswerDto의'value' 속성이'LinkedHashMap'에 매핑됩니다. – Bananan

답변

5

나는 @JsonTypeInfo@JsonSubTypes을 잭슨의 사용자 정의 주석을 사용하여 문제를 해결했습니다

public class AnswerDto<T> { 

    private String uuid; 

    private AnswerType type; 

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type") 
    @JsonSubTypes({ 
      @JsonSubTypes.Type(value = Location.class, name = AnswerType.Types.LOCATION), 
      @JsonSubTypes.Type(value = JobTitle.class, name = AnswerType.Types.JOB_TITLE) 
    }) 
    private T value; 
} 
1

내 제안은 가능한 답변 값에 대해 별도의 인터페이스를 만들고 그것에 @JsonTypeInfo을 사용하는 것입니다. type 필드를 AnswerDto, AnswerType 열거 형 및 기타 *AnswerDto 클래스로 놓을 수도 있습니다. becuse jackson이 입력 정보를 추가합니다. 이

public class AnswerDto<T extends AnswerValue> { 
    private String uuid; 
    private T value; 
} 

@JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY) 
interface AnswerValue {} 

class Location implements AnswerValue { /*..*/ } 
class JobTitle implements AnswerValue { /*..*/ } 

결과 JSON의 의지

AnswersDto answersDto = objectMapper.readValue(json, AnswersDto.class); 

를 사용하여 구문 분석됩니다이

{ 
    "uuid": "e82544ac-1cc7-4dbb-bd1d-bdbfe33dee73", 
    "answers": [ 
    { 
     "uuid": "e82544ac-1cc7-4dbb-bd1d-bdbfe33dee73", 
     "value": { 
     "@class": "com.demo.Location", 
     "text": "Dublin", 
     "placeId": "121" 
     } 
    }, 
    { 
     "uuid": "e82544ac-1cc7-4dbb-bd1d-bdbfe33dee73", 
     "value": { 
     "@class": "com.demo.JobTitle", 
     "id": "1", 
     "name": "Developer" 
     } 
    } 
    ] 
} 

처럼 보이는하지만 JSON 데이터의 프로듀서 경우이 솔루션은 경우에만 적용 좋아하고 역 호환성에 대해 생각할 필요가 없습니다.

다른 경우에는 AnswersDto 클래스의 맞춤형 데시 타이 저를 만들어야합니다.