尝试将自定义通用gson反序列化器迁移到jackson

时间:2016-02-05 16:47:46

标签: java json jackson retrofit retrofit2

目前正在使用GSON进行反序列化并使用改造GsonConverterFactory进行改造:

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

2 个答案:

答案 0 :(得分:3)

根据APISimpleModule.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>并使用它。但是,如果您未在BookAuthor的定义中使用Jackson annotations,则还需要提供custom deserializers for them

或者,您也可以尝试supplying this type information while actually using the ObjectMapper instance for deserialization

答案 1 :(得分:0)

我认为这里存在误解:你没有实现JsonDeserializer只是因为你想要绑定到某种类型。这就是杰克逊本身所做的。 如果由于某种原因需要定制的反序列化器(或序列化器),它只会处理嵌套类型的特定部分; BookAuthorMap的反序列化程序,但对于嵌套类型Map,反序列化程序委托给键和值处理程序。它没有注册组合。

无论如何:我相当确定自定义反序列化器不是这里的答案,而是一种将ObjectMapper的基本用法包装为读取给定类型的JSON的方法。但是,如果不了解更多有关Retrofit的信息,我不知道究竟是什么。