Hủy thiết lập JSON thành ArrayList <POJO> bằng cách sử dụng Jackson


97

Tôi có một lớp Java MyPojomà tôi quan tâm đến việc giải mã hóa từ JSON. Tôi đã định cấu hình một lớp MixIn đặc biệt MyPojoDeMixIn, để hỗ trợ tôi giải quyết vấn đề. MyPojochỉ có intStringcác biến phiên bản được kết hợp với getters và setters thích hợp. MyPojoDeMixIntrông giống như sau:

public abstract class MyPojoDeMixIn {
  MyPojoDeMixIn(
      @JsonProperty("JsonName1") int prop1,
      @JsonProperty("JsonName2") int prop2,
      @JsonProperty("JsonName3") String prop3) {}
}

Trong ứng dụng khách thử nghiệm của mình, tôi làm như sau, nhưng tất nhiên nó không hoạt động tại thời điểm biên dịch vì có JsonMappingExceptionliên quan đến kiểu không khớp.

ObjectMapper m = new ObjectMapper();
m.getDeserializationConfig().addMixInAnnotations(MyPojo.class,MyPojoDeMixIn.class);
try { ArrayList<MyPojo> arrayOfPojo = m.readValue(response, MyPojo.class); }
catch (Exception e) { System.out.println(e) }

Tôi biết rằng tôi có thể giảm bớt vấn đề này bằng cách tạo một đối tượng "Phản hồi" chỉ có một đối tượng ArrayList<MyPojo>trong đó, nhưng sau đó tôi sẽ phải tạo các đối tượng hơi vô dụng này cho mọi kiểu mà tôi muốn trả lại.

Tôi cũng đã xem trực tuyến JacksonInFiveMinutes nhưng đã có một khoảng thời gian khủng khiếp khi hiểu nội dung Map<A,B>và cách nó liên quan đến vấn đề của tôi. Nếu bạn không thể nói, tôi hoàn toàn mới đối với Java và đến từ nền tảng obj-C. Họ đề cập cụ thể:

Ngoài liên kết với POJO và các loại "đơn giản", có một biến thể bổ sung: biến thể liên kết với các vùng chứa chung chung (đã định). Trường hợp này yêu cầu xử lý đặc biệt do cái gọi là Type Erasure (được Java sử dụng để triển khai generic theo cách tương thích ngược), ngăn bạn sử dụng thứ gì đó như Collection.class (không biên dịch).

Vì vậy, nếu bạn muốn liên kết dữ liệu vào một Bản đồ, bạn sẽ cần sử dụng:

Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() { });

Làm cách nào để tôi có thể deserialize trực tiếp đến ArrayList?


Câu trả lời:


149

Bạn có thể giải kích thước trực tiếp vào danh sách bằng cách sử dụng TypeReferencetrình bao bọc. Một phương pháp ví dụ:

public static <T> T fromJSON(final TypeReference<T> type,
      final String jsonPacket) {
   T data = null;

   try {
      data = new ObjectMapper().readValue(jsonPacket, type);
   } catch (Exception e) {
      // Handle the problem
   }
   return data;
}

Và được sử dụng như vậy:

final String json = "";
Set<POJO> properties = fromJSON(new TypeReference<Set<POJO>>() {}, json);

TypeReference Javadoc


Câu trả lời của bạn có vẻ liên quan đến thông tin của họ về cách sử dụng hỗ trợ tích hợp cho TypeReference- Tôi chỉ không biết cách thực hiện ... Vui lòng xem bản chỉnh sửa của tôi ở trên để biết hướng dẫn về cách sử dụng thuốc chung.
tacos_tacos_tacos 22/03/12

Vâng, nó có liên quan. Nhưng đây là một đoạn mã từ mã làm việc trong sản xuất. Quên về mixin của bạn, chỉ cần sử dụng mã tôi đã hiển thị (nhưng thay thế POJO tất nhiên bằng tên của lớp bean thực tế của bạn).
Nhận thức

Mã của bạn đã được biên dịch, nhưng tôi nhận được một ngoại lệ về thời gian chạy khi cố gắng in ra arrayList.toString()khoảng a NullPointerException. Tôi đoán rằng điều này có thể là do của tôi POJOkhông tuân thủ các quy ước đặt tên phù hợp cho các thuộc tính của nó, nghĩa là, toàn bộ vấn đề là dịch vụ web trả về Prop1Membervà đối tượng của tôi có Prop1. Đây là lý do thực sự duy nhất mà tôi đang sử dụng mixin để bắt đầu, vì vậy tôi không phải đặt các khai báo cho @JsonPropertycác đối tượng thuần túy của mình.
tacos_tacos_tacos

1
Kiểm tra trực quan mảng của bạn để đảm bảo ít nhất bạn đã nhận lại được danh sách. Và nếu cần, hãy thêm mixin trở lại, công cụ này sẽ hoạt động cùng với TypeReference để mọi thứ được giải trí gọn gàng.
Cảm nhận

2
@JsonProperty không xấu xa như mọi người vẫn làm. Thật khó để thoát khỏi các chú thích cụ thể của nhà cung cấp những gì với trạng thái tiêu chuẩn hiện tại (tối thiểu) trong lĩnh vực này.
Perception

104

Một cách khác là sử dụng mảng làm kiểu, ví dụ:

ObjectMapper objectMapper = new ObjectMapper();
MyPojo[] pojos = objectMapper.readValue(json, MyPojo[].class);

Bằng cách này, bạn tránh được tất cả những rắc rối với đối tượng Type và nếu bạn thực sự cần một danh sách, bạn luôn có thể chuyển mảng thành danh sách bằng cách:

List<MyPojo> pojoList = Arrays.asList(pojos);

IMHO cái này dễ đọc hơn nhiều.

Và để làm cho nó trở thành một danh sách thực tế (có thể được sửa đổi, xem các giới hạn của Arrays.asList()) thì chỉ cần làm như sau:

List<MyPojo> mcList = new ArrayList<>(Arrays.asList(pojos));

1
Elegant chắc chắn, nhưng tôi không thể xác định nó vì lớp MyPojo []., Mà tôi không muốn chuyển vào dưới dạng tham số.
Adrian Redgers,

Tôi nghĩ việc sử dụng TypeFactorynhư được mô tả trong câu trả lời tiếp theo: stackoverflow.com/a/42458104/91497 là cách Jackson để chỉ định loại.
Jmini

32

Biến thể này trông đơn giản và thanh lịch hơn.

CollectionType typeReference =
    TypeFactory.defaultInstance().constructCollectionType(List.class, Dto.class);
List<Dto> resultDto = objectMapper.readValue(content, typeReference);

3

Tôi cũng đang gặp vấn đề tương tự. Tôi có một json sẽ được chuyển đổi thành ArrayList.

Tài khoản trông như thế này.

Account{
  Person p ;
  Related r ;

}

Person{
    String Name ;
    Address a ;
}

Tất cả các lớp trên đã được chú thích đúng. Tôi đã thử TypeReference> () {} nhưng không hoạt động.

Nó cung cấp cho tôi Arraylist nhưng ArrayList có một Bản đồ liên kết có chứa một số bản đồ băm được liên kết hơn có chứa các giá trị cuối cùng.

Mã của tôi là như sau:

public T unmarshal(String responseXML,String c)
{
    ObjectMapper mapper = new ObjectMapper();

    AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();

    mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);

    mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
    try
    {
      this.targetclass = (T) mapper.readValue(responseXML,  new TypeReference<ArrayList<T>>() {});
    }
    catch (JsonParseException e)
    {
      e.printStackTrace();
    }
    catch (JsonMappingException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }

    return this.targetclass;
}

Cuối cùng tôi đã giải quyết được vấn đề. Tôi có thể chuyển đổi Danh sách trong Json String trực tiếp thành ArrayList như sau:

JsonMarshallerUnmarshaller<T>{

     T targetClass ;

     public ArrayList<T> unmarshal(String jsonString)
     {
        ObjectMapper mapper = new ObjectMapper();

        AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();

        mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);

        mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
        JavaType type = mapper.getTypeFactory().
                    constructCollectionType(ArrayList.class, targetclass.getClass()) ;
        try
        {
        Class c1 = this.targetclass.getClass() ;
        Class c2 = this.targetclass1.getClass() ;
            ArrayList<T> temp = (ArrayList<T>) mapper.readValue(jsonString,  type);
        return temp ;
        }
       catch (JsonParseException e)
       {
        e.printStackTrace();
       }
       catch (JsonMappingException e) {
           e.printStackTrace();
       } catch (IOException e) {
          e.printStackTrace();
       }

     return null ;
    }  

}

2

Điều này làm việc cho tôi.

@Test
public void cloneTest() {
    List<Part> parts = new ArrayList<Part>();
    Part part1 = new Part(1);
    parts.add(part1);
    Part part2 = new Part(2);
    parts.add(part2);
    try {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(parts);

        List<Part> cloneParts = objectMapper.readValue(jsonStr, new TypeReference<ArrayList<Part>>() {});
    } catch (Exception e) {
        //fail("failed.");
        e.printStackTrace();
    }

    //TODO: Assert: compare both list values.
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.