我如何告诉jackson为每种Generic集合类型使用不同的序列化程序。 我有一个CustomProductsSerializer和一个CustomClientsSerializer
public class ProductsListSerializer extends JsonSerializer<List<Products>>{
// logic to insert __metadata , __count into json
public void serialize(List<Products> value, JsonGenerator jgen, SerializerProvider provider) {
.... .... ....
}
// always returns ArrayList.class
public Class<List<Instrument>> handledType() {
Class c = var.getClass();
return c;
}
}
public class CustomClientsSerializer extends JsonSerializer<List<Clients>>{
// logic to insert __metadata , __count into json
public void serialize(List<Clients> value, JsonGenerator jgen, SerializerProvider provider){
.... .... ....
}
.... .... ....
// always returns ArrayList.class
public Class<List<Clients>> handledType() {
Class c = var.getClass();
return c;
}
}
我已使用SimpleModule注册了两个序列化程序。 问题是,由于两种情况下的processedType都返回ArrayList.class,因此下面的客户端序列化失败并带有类强制转换异常。
List<Clients> clients;
// code to get clients from database.
String jsonString = mapper.writeValueAsString(clients);
问题是如何告诉jackson使用哪个序列化器?
我正在使用杰克逊作为json序列化器,并且重新安装。
- 编辑以响应@ HiJon89 我有一个返回'List'的业务对象和另一个返回List的业务对象。我需要的方式是当Busines对象返回一个'List'时,ProductsListSerializer应该用于整个List。当Business Object返回'List时,CustomClientsSerializer应该用于整个List。在我的用例中,我将附加元素附加到序列化的json'例如:__ count,__ metadata,__references'每个Collection只有一个__count。 Contentusing只能用于属性。有什么建议 ?
答案 0 :(得分:3)
您是否真的希望此类型的序列化/反序列化在集合内部时以不同方式处理?如果没有,您可以使用@JsonSerialize(using = ProductSerializer.class)
之类的内容注释Product
类,并且只要遇到Product
(包括内部集合),Jackson就会使用您的序列化程序。
如果你真的需要在集合内部进行不同的处理,你可以用类似@JsonSerialize(using = ProductSerializer.class, contentUsing = ProductInCollectionSerializer.class)
之类的东西来注释类。这将做与上面相同的事情,除了当Jackson遇到包含ProductInCollectionSerializer
的集合时,Product
将用于序列化。
根据评论编辑:
杰克逊会将一个集合序列化为一个JSON数组,因此没有地方可以放置这些额外的属性。听起来你好像你想让Jackson返回一个包含JSON数组的JSON对象以及一些额外的元数据。在这种情况下,最好的方法是将List<Product>
包装在一个对象中,例如:
public class ProductListWrapper {
private final List<Product> products;
public ProductListWrapper(List<Product> products) {
this.products = products;
}
public List<Product> getProducts() {
return products;
}
@JsonProperty("_count")
public int getCount() {
return getProducts() == null ? 0 : getProducts().size();
}
}
然后,杰克逊可以序列化这个对象而无需编写任何自定义序列化程序,并且会产生如下的JSON:
{
"products": [....]
"_count": 25
}
答案 1 :(得分:0)
可以通过扩展simplemodule或扩展com.fasterxml.jackson.databind.Module来实现。我采取了第二种方法。以下是变更摘要
添加了将JavaType作为参数的方法。
public <T> TypedModule addSerializer(JavaType type, JsonSerializer<T> ser)
{
if (_serializers == null) {
_serializers = new TypedSerializers();
}
_serializers.addSerializer(type, ser);
return this;
}
上述方法将新的序列化添加到
protected TypedSerializers _serializers = null;
类'TypedSerializers扩展Serializers.Base'将所有类型化的序列化器存储在HashMap中。
更改了TypedSerializers
中findSerializer方法的逻辑public JsonSerializer<?> findSerializer(SerializationConfig config,
JavaType type, BeanDescription beanDesc) {
Class<?> cls = type.getRawClass();
ClassKey key = new ClassKey(cls);
JsonSerializer<?> ser = null;
if (_javaTypeMappings != null) {
ser = _javaTypeMappings.get(type.toString());
if (ser != null) {
return ser;
}
}
..... process normal serilaizers ...
注册自定义序列化程序时需要进行以下更改
TypedModule simpleModule = new TypedModule("TypedModule", new Version(1, 0, 0, null));
JavaType productlist = this.getTypeFactory().constructCollectionType(List.class, Product.class);
JavaType clientlist = this.getTypeFactory().constructCollectionType(List.class, Client.class);
simpleModule.addSerializer(productlist, new prodctlistserializer());
simpleModule.addSerializer(clientlist, new clientlistserializer() );
this.registerModule(simpleModule);
结果行为是,当'Type of Product Product'传递给ObjectMapper时,它会尝试找到合适的serilaizer。我们在_javaTypeMappings的映射中维护通用序列化器。 Objecmapper执行findSerializer。 findSerializer首先在_javaTypeMappings中检查可用的序列化程序。在这种情况下,它返回prodctlistserializer。当传递“类型客户端列表”时,它返回clientlistserializer。
我已将com.fasterxml.jackson.databind.Module下的所有源代码下载到我的项目中的一个包中,并添加了上面的更改。