Пользовательская десериализация RestEasy + Jackson 2

Я кодирую клиент для веб-службы, и ответ выглядит примерно так:

{
   "succeed": true,
   "code": 2000,
   "pagination": {
       "items": [
           {
             "id": 17694,
             ...
           },
           {
              "id": 17695,
             ...
           }
         ],
         "count": 2,
         "offset": 0
     },
     "message": "Petición satisfactoria."
 }

Ответ всегда возвращает список одного типа на запрос, моя проблема в том, что массив items может быть разных типов, например:

{
    "id", 1,
    "otherProperty" : "Foo",
    ...
}

or

{
    "id", 1,
    "anotherProperty" : "Foo",
     ...
}

Я попытался сопоставить этот ответ с классом Java примерно так:

public class WsResponse {
    private WsPagination<?> pagination;
    private boolean succeed;
    ...
}

Где WsPagination имеет:

public class WsPagination <T> {
    List<T> items;
    int count;
    int offset;
    ...
}

И это работает, но список элементов возвращается как java.util.LinkedHashMap, и я хочу, чтобы RestEasyClient сериализовался как правильный класс.

Пример:

public class Foo {
     Long id;
     String otherProperty;
}

И

public class Bar {
   Long id;
   String anotherProperty;
}

Я попытался зарегистрировать собственный JsonDeserializer для типа WsPagination, но он не вызывается, не знаю почему.

 Class<?> clazz = getRequestType();
 ObjectMapper mapper = new ObjectMapper();
    SimpleModule module = new SimpleModule("myModule",
            new Version(1, 0, 0, "", "", ""));

    module.addDeserializer(WsPagination.class, new WsPaginationDeserializer(clazz));
    mapper.registerModule(module);


    ResteasyClient client = new ResteasyClientBuilder()
            .register(module)
            .register(new ClientRequestFilter() {

                @Override
                public void filter(ClientRequestContext context)
                        throws IOException {
                    for (Map.Entry<String, String> entrySet : headers
                            .entrySet()) {
                        String key = entrySet.getKey();
                        String value = entrySet.getValue();
                        context.getHeaders().add(key, value);
                    }
                }
            }).build();

класс WsPaginationDeserializer:

 public class WsPaginationDeserializer extends JsonDeserializer<WsPagination> {

    Class<?> clazz;

    /**
     * Constructs a new instance of type FooTest.WsPaginationDeserializer
     */
    public WsPaginationDeserializer(Class<?> clazz) {
        this.clazz = clazz;
    }

    @Override
    public WsPagination deserialize(JsonParser arg0,
            DeserializationContext arg1)
            throws IOException, JsonProcessingException {
        // method not called
        throw new IOException("Deserialize here!!");
    }


}

Как я могу получить список элементов, заполненных правильным типом.

Спасибо.

РЕДАКТИРОВАТЬ 14.11.2017

В качестве рабочего решения получите эти java.util.LinkedHashMap и преобразуйте их в соответствующую модель:

if(path.equals("somePath")){
     if((result = resp.getResult()) != null){
           Object items = null;
           if((items = result.getItems()) != null){
           // here items are a list of java.util.LinkedHashMap, so then try to convert them to the model we need for the "somePath"
           List models = mapper.convertValue(items, new TypeReference<List<WsComprobante>>() {});
           // now re assing the list of WsComprobante again to the result list of items
           result.setItems(models);
     }
                    }
                }

Надеюсь, это поможет кому-то.


person ics_mauricio    schedule 08.11.2017    source источник


Ответы (1)


Ваша проблема в том, что Джексон не знает, какой класс он должен использовать при десериализации ваших элементов.

Один из способов предотвратить это — создать собственный класс WSResponse для каждого типа элемента:

public class WsResponse<T> {
    private WsPagination<T> pagination;
    private boolean succeed;
    ...
}

public class WsPagination <T> {
    List<T> items;
    int count;
    int offset;
    ...
}

public class FooResponse extends WsResponse<Foo>{}
public class BarResponse extends WSResponse<Bar>{}
person user2641570    schedule 10.11.2017
comment
Это классы, общие из другого проекта, и мне нужно их использовать. Что я сделал: if(path.equals(timbrado)){ if((result = resp.getResult()) != null){ Object items = null; if((items = result.getItems()) != null){ Модели списка = mapper.convertValue(items, new TypeReference‹List‹WsComprobante››() {}); результат.setItems(модели); } } } - person ics_mauricio; 15.11.2017