2016-09-01 18 views
5

Tôi đã lớp DTO như viết bằng Java:JSON bộ sưu tập chung deserialization

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

Trong dự án của tôi có thư viện Jackson sử dụng cho serialization và deserialization của JSONs.

Làm thế nào để cấu hình AnswersDto (sử dụng chú thích đặc biệt) hoặc AnswerDto (chú thích cũng) các lớp học để có thể deserialize đúng yêu cầu với AnswersDto trong cơ thể của nó, ví dụ:

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

Thật không may Jackson theo giá trị bản đồ mặc định của AnswerDto đối tượng để LinkedHashMap thay vì đối tượng thích hợp (Location hoặc JobTitle) loại lớp. Tôi có nên viết tùy chỉnh JsonDeserializer<AnswerDto> hoặc cấu hình bằng cách sử dụng @JsonTypeInfo@JsonSubTypes có thể là đủ?

Để deserialize đúng yêu cầu chỉ với một cú AnswerDto dưới hình thức

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

Tôi đang sử dụng:

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

mà không cần bất kỳ cấu hình tùy chỉnh khác.

+0

Bạn có một bộ sưu tập của các đối tượng aswer nhưng bạn muốn deserialize để chỉ một đối tượng câu trả lời? Điều gì về việc sử dụng AnswersDto answers = objectMapper.readValue (jsonRequest, TypeReference mới () {}); – reos

+0

Tôi muốn ánh xạ tất cả các đối tượng từ nút 'câu trả lời' đến bộ sưu tập' Set '. Khi tôi sử dụng 'objectMapper' với 'TypeReference ' này hơn là thuộc tính' value' của 'AnswerDto' từ bộ sưu tập được ánh xạ tới' LinkedHashMap'. – Bananan

Trả lời

5

Tôi đã giải quyết vấn đề bằng cách sử dụng các chú thích tùy chỉnh Jackson @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

Đề xuất của tôi là tạo giao diện riêng cho các giá trị câu trả lời có thể và sử dụng @JsonTypeInfo trên đó. Bạn cũng có thể thả trường type từ AnswerDto, AnswerType enum và thêm *AnswerDto lớp becuse jackson sẽ thêm thông tin loại cho bạn. Như thế này

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

Kết quả json sẽ trông như thế này

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

nào sẽ được phân tích sử dụng

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

Nhưng giải pháp này chỉ áp dụng trong trường hợp khi bạn là một nhà sản xuất của dữ liệu json và bạn không phải suy nghĩ về khả năng tương thích ngược.

Trong các trường hợp khác, bạn sẽ phải tạo bộ tùy chỉnh desetializer cho lớp AnswersDto.

Các vấn đề liên quan