Câu hỏi Tham khảo kiểu Jackson và generic


Tôi muốn sử dụng thư viện jackson json cho một phương pháp chung như sau:

public MyRequest<T> tester(){
  TypeReference<MyWrapper<T>> typeRef = new TypeReference<MyWrapper<T>>();  
  MyWrapper<T> requestWrapper = (MyWrapper<T>) JsonConverter.fromJson(jsonRequest, typeRef);
  return requestWrapper.getRequest();
}
public class MyWrapper<T> {

    private MyRequest<T> request;

    public MyRequest<T> getRequest() {
        return request;
    }

    public void setRequest(MyRequest<T> request) {
        this.request = request;
    }
}


 public class MyRequest{
     private List<T> myobjects;

     public void setMyObjects(List<T> ets) {
         this.myobjects = ets;
     }

     @NotNull
     @JsonIgnore
     public T getMyObject() {
         return myobjects.get(0);
     }
}

Bây giờ vấn đề là khi tôi gọi getMyObject () bên trong đối tượng yêu cầu, jackson trả về đối tượng tùy chỉnh lồng nhau như là một LinkedHashMap. Có cách nào trong đó tôi xác định rằng đối tượng T cần phải được trả lại ?. Ví dụ: nếu tôi đã gửi đối tượng thuộc loại Khách hàng thì Khách hàng sẽ được trả về từ Danh sách đó ?.

Cảm ơn.


76
2017-07-27 14:39


gốc


Vui lòng thêm việc triển khai getT () - Jim Garrison
Câu hỏi này tương tự như stackoverflow.com/questions/6062011/… nhưng họ đã đề xuất chỉ định loại bằng cách sử dụng TypeFactory. Tuy nhiên tôi không biết loại lúc biên dịch ... - techzen
TypeFactory có các phương thức không cần lớp tĩnh; createCollectionType v.v. - StaxMan
Vui lòng chia sẻ mã hoàn chỉnh. Tôi cũng phải đối mặt với cùng một vấn đề. - AZ_


Các câu trả lời:


Đây là một vấn đề nổi tiếng với việc xóa kiểu Java: T chỉ là một biến kiểu, và bạn phải chỉ ra lớp thực tế, thường là đối số Lớp. Nếu không có thông tin như vậy, tốt nhất có thể được thực hiện là sử dụng giới hạn; và chữ T đơn giản giống như 'T mở rộng đối tượng'. Và sau đó Jackson sẽ liên kết các đối tượng JSON dưới dạng Bản đồ.

Trong trường hợp này, phương pháp thử nghiệm cần có quyền truy cập vào Lớp và bạn có thể xây dựng

JavaType type = mapper.getTypeFactory().
  constructCollectionType(List.class, Foo.class)

và sau đó

List<Foo> list = mapper.readValue(new File("input.json"), type);

139
2017-07-27 22:51



Nó hoạt động: Tôi đã làm như sau: JavaType topMost = mapper.getTypeFactory (). ConstructParametricType (MyWrapper.class, ActualClassRuntime.class); và sau đó đã làm readValue và nó cuối cùng đã làm việc :) - techzen
Có, điều đó không có tác dụng - cảm ơn vì đã chỉ ra phương pháp tạo loại chung loại trừ loại Bản đồ / Bộ sưu tập! - StaxMan
Chính xác những gì tôi cần, cảm ơn !! - gresdiplitude
@husayt vâng, về mặt kỹ thuật, bạn cùng lớp java là cấp trên. Nhưng việc tích hợp nó với Jackson thì hơi phức tạp chỉ vì sự trừu tượng kiểu của chính Jackson được tích hợp một phần của API. Về lâu dài, thật tuyệt vời khi tìm ra cách thích hợp để làm cho Jackson sử dụng mã bạn cùng lớp, hoặc được nhúng hoặc thông qua dep. - StaxMan
Tôi cảm thấy như Jackson không cần phải che đậy những gì cảm thấy như những khoảng trống trong generics, nhưng dù bằng cách nào, nó cũng rất tốt. - Adrian Baker


'JavaType' hoạt động !! Tôi đã cố gắng unmarshall (deserialize) một Danh sách trong chuỗi json để ArrayList java Objects và đã đấu tranh để tìm một giải pháp kể từ ngày.
Dưới đây là mã mà cuối cùng đã cho tôi giải pháp. Mã số:

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

6
2018-03-05 17:07



Làm thế nào để khởi tạo TargetClass? - AZ_
Thông qua constructor hoặc getter setter !!! - rushidesai1
Hãy cho tôi xem một ví dụ nhỏ. Tôi đang vượt qua lớp <?> Và sau đó lấy target.getClassName (). - AZ_
Thêm một hàm tạo như sau: JsonMarshallerUnmarshaller <T> {private Class <T> targetClass; JsonMarshallerUnmarshaller (Lớp <T> c) {targetClass = c; }} Thực hiện các thay đổi thích hợp ngay bây giờ đối với hàm 'unmarshal' để sử dụng lớp này thay vì thực hiện getClass ở mọi nơi. - rushidesai1
Vài lưu ý: mã có thể được đơn giản hóa rất nhiều bằng cách lưu ý rằng tất cả các ngoại lệ là các kiểu con của IOException (chỉ cần một lần đánh bắt) và rằng trình chú thích nội dung chú thích mặc định đã sẵn sàng JacksonAnnotationIntrospector- vì vậy không cần phải làm gì để ObjectMapper, chỉ cần xây dựng nó và nó hoạt động. - StaxMan