2016-09-01 45 views
5

mam takie zajęcia DTO napisane w Javie:JSON kolekcji generycznych deserializacjia

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; 
} 

W moim projekcie jest biblioteka Jackson wykorzystywane do serializacji i deserializacji JSONs.

Jak skonfigurować AnswersDto (stosować specjalne adnotacje) lub AnswerDto (adnotacji również) zajęcia, aby móc prawidłowo deserializowania wniosek z AnswersDto w swoim ciele, na przykład:

{ 
    "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" 
      } 
     } 
    ] 
} 

Niestety Jackson domyślnie wartości map AnswerDto obiekt do LinkedHashMap zamiast obiektu właściwego (Location lub JobTitle) typ klasy. Czy mogę napisać niestandardową JsonDeserializer<AnswerDto> lub konfigurację przy użyciu @JsonTypeInfo i @JsonSubTypes może wystarczyć?

Aby prawidłowo deserializowania wniosek z tylko jednym AnswerDto w postaci

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

Używam:

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

bez żadnej innej konfiguracji niestandardowej.

+0

Masz kolekcję obiektów aswer ale chcesz deserializowania się tylko jeden obiekt odpowiedź? A co z wykorzystaniem odpowiedzi AnswersDto = objectMapper.readValue (jsonRequest, new TypeReference () {}); – reos

+0

Chcę zmapować wszystkie obiekty z węzła 'response' do kolekcji' Set '. Kiedy używam 'objectMapper' z tym' TypeReference 'niż niestety własność' value' każdego 'AnswerDto' z kolekcji jest odwzorowana na' LinkedHashMap'. – Bananan

Odpowiedz

5

mam rozwiązany problem przy użyciu niestandardowych adnotacje Jacksona @JsonTypeInfo i @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

Moja sugestia to stworzenie oddzielnego interfejsu dla możliwych wartości odpowiedzi i użycie na nim @JsonTypeInfo. Możesz również zrezygnować z type z enum AnswerDto, AnswerType i dodatkowych klas *AnswerDto, ponieważ jackson doda Ci informacje o typie. Tak

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 { /*..*/ } 

Wynikające json wola wygląda to

{ 
    "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" 
     } 
    } 
    ] 
} 

który będzie analizowany za pomocą

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

Ale to rozwiązanie ma zastosowanie tylko w przypadku, gdy jesteś producentem danych JSON i nie musisz myśleć o kompatybilności wstecznej.

W innych przypadkach konieczne będzie wprowadzenie niestandardowego desetializera dla klasy AnswersDto.