2016-02-05 2 views
4

В настоящее время десериализации с GSON и модифицированным с помощью модернизаций GsonConverterFactory:Попытка перенести пользовательский общую gson десериализатор Джексона

GsonBuilder gsonBuilder = new GsonBuilder(); 
gsonBuilder.registerTypeAdapter(new TypeToken<Map<Book, Collection<Author>>>(){}.getType(), new BooksDeserializer(context)); 
Gson gson = gsonBuilder.create(); 

Retrofit retrofit = new Retrofit.Builder() 
    .baseUrl(url) 
    .addConverterFactory(GsonConverterFactory.create(gson)) 
    .build(); 

BookService service = retrofit.create(BookService.class); 
Response<Map<Book, Collection<Author>>> response = service.getBooks().execute();  

Я хотел бы использовать JacksonConverterFactory, предоставленный дооснащения? Мне нужно было бы предоставить это картографу Джексона. Есть ли способ предоставить информацию о типе этому картографу, как это было с GSON?

SimpleModule simpleModule = new SimpleModule(); 
// TODO provide mapper with info needed to deserialize 
// Map<Book, Collection<Author>> 
mapper.registerModule(simpleModule); 

Retrofit retrofit = new Retrofit.Builder() 
    .baseUrl(url) 
    .addConverterFactory(JacksonConverterFactory.create(mapper)) 
    .build(); 

BookService service = retrofit.create(BookService.class); 
Response<Map<Book, Collection<Author>>> response = service.getBooks().execute(); 

Глядя конкретно на TODO, я могу рассказать картографу, чтобы использовать этот десериализатор?

public class BooksDeserializer extends JsonDeserializer<Map<Book, Collection<Author>>> { 

    @Override 
    public Map<Book, Collection<Author>> deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException { 
     // deserialize here 
    } 
} 

ответ

3

Согласно API, SimpleModule.addDeserializer(java.lang.Class, com.fasterxml.jackson.databind.JsonSerializer) requires an instance of JsonSerializer<T> whereby T is a supertype of the class you supply as an argument, т.е. десериализатор должен быть в состоянии десериализации объектов, которые представляют собой подкласс поставляемого класса; TypeReference<Map<Book, Collection<Author>>>не подтип Map<Book, Collection<Author>>.

Однако писать стирание для карт нелегко благодаря стиранию типа Java. Один из способов сделать это, чтобы написать класс-обертку для вашей карты, такие как

@XmlRootElement 
public class SerializableBookMapWrapper { 

    private Map<Book, Collection<Author>> wrapped; 

    public SerializableBookMapWrapper(final Map<Book, Collection<Author>> wrapped) { 
     this.wrapped = wrapped; 
    } 

    public Map<Book, Collection<Author>> getWrapped() { 
     return wrapped; 
    } 

    public void setWrapped(final Map<Book, Collection<Author>> wrapped) { 
     this.wrapped = wrapped; 
    } 
} 

С такого рода класс-оболочку, вы можете реализовать JsonDeserializer<SerializableBookMapWrapper> и использовать вместо. Однако, если вы не использовали Jackson annotations в определении Book и Author, вам также необходимо поставить custom deserializers for them.

Кроме того, вы также можете попробовать supplying this type information while actually using the ObjectMapper instance for deserialization.

+0

Обновлен вопрос, попытался быть более конкретным в отношении того, что я ищу. – lostintranslation

+0

* Глядя конкретно на TODO, могу ли я сказать картографу, чтобы использовать этот десериализатор? * Нет, мне очень жаль: Как указано в моем первоначальном ответе, во время выполнения недостаточно информации для сопоставления вашего десериализатора с чем-то вроде «Карта <Книга, сборник > ', потому что во время выполнения она неотличима от, например, 'Карта '. По этой причине вам необходимо предоставить эту информацию типа [во время компиляции] (http://wiki.fasterxml.com/JacksonInFiveMinutes#Data_Binding_with_Generics) или [программно] (http://stackoverflow.com/a/18014407/1391325) – errantlinguist

+0

Если это действительно так, дело не в том, что информации недостаточно, а в том, что Джексон этого не поддерживает. GSON просто отлично справляется с этим. Я думаю, что буду придерживаться GSON. – lostintranslation

0

Я думаю, что здесь есть недоразумение: вы НЕ реализуете JsonDeserializer только потому, что хотите привязать к некоторому типу. Это то, что делает сам Джексон. И если вам почему-то нужен настроенный десериализатор (или сериализатор), он будет обрабатывать только определенную часть вложенного типа; десериализатор для Book или Author или Map, но для вложенных типов Map делегат десериализатора для обработчиков ключей и значений. Он НЕ регистрируется для комбинации.

В любом случае: я вполне уверен, что пользовательский десериализатор не является ответом здесь, а способ обернуть базовое использование ObjectMapper для чтения JSON в качестве заданного типа. Но, не зная больше о Retrofit, я не знаю, что именно.