Java 如何为映射使用Jackson自定义值序列化程序<;字符串,对象>;?
我有一个来自DB的结果集,其形式为Java 如何为映射使用Jackson自定义值序列化程序<;字符串,对象>;?,java,jackson,Java,Jackson,我有一个来自DB的结果集,其形式为Map,我应该从REST服务返回json。映射中的值可以是各种类型,包括PGObject、String、Integer和Date 我还为类型为“jsonb”的org.postgresql.util.PGObject类编写了一个自定义序列化程序,它在列表中运行良好,但在映射中则不行 当Jackson在Map中序列化这个PGObject值时,我会得到json值,如下所示: "reason": { "type": "jsonb", "value":
Map
,我应该从REST服务返回json
。映射中的值可以是各种类型,包括PGObject
、String
、Integer
和Date
我还为类型为“jsonb”的org.postgresql.util.PGObject
类编写了一个自定义序列化程序,它在列表
中运行良好,但在映射
中则不行
当Jackson在Map
中序列化这个PGObject
值时,我会得到json
值,如下所示:
"reason": {
"type": "jsonb",
"value": "[{\"id\": 6, \"name\": \"Foo\"}, {\"id\": 7, \"name\": \"Bar\"}, {\"id\": 8, \"name\": \"Baz\"}]"
}
我需要的是:
"reason": [
{
"id": 6,
"name": "Foo"
},
{
"id": 7,
"name": "Bar"
},
{
"id": 8,
"name": "Baz"
},
],
我已尝试将模块添加到ObjectMapper
中,并将自定义MapType
添加到ObjectWriter
中,如下所示:
当在
映射的序列化过程中发现PGObject作为值时,如何在Jackson中启用我的PGObjectSerializer
?一个解决方法是为对象添加序列化程序
然后在序列化程序本身中,您可以检查对象是否是PGobject
的实例
在myMapType中,您可以指定对象.class
:
JavaType myMapType = mapper.getTypeFactory().
constructMapType(HashMap.class, String.class, Object.class);
序列化程序将是:
class PgObjectSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object object, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (object instanceof PGobject) {
PGobject pgObject = (PGobject) object;
switch (pgObject.getType()) {
case "json":
case "jsonb":
gen.writeRawValue(pgObject.getType());
break;
default:
gen.writeString(pgObject.getType());
}
}else{
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(gen, object);
}
}
}
类PgObjectSerializer扩展JsonSerializer{
@凌驾
public void serialize(对象对象、JsonGenerator gen、SerializerProvider序列化程序)引发IOException{
if(PGobject的对象实例){
PGobject PGobject=(PGobject)对象;
开关(pgObject.getType()){
案例“json”:
案例“jsonb”:
gen.writeRawValue(pgObject.getType());
打破
违约:
gen.writeString(pgObject.getType());
}
}否则{
ObjectMapper mapper=新的ObjectMapper();
mapper.writeValue(gen,object);
}
}
}
此解决方法需要将所有其他类类型的序列化委托给其他“基”或“泛型”序列化程序。我没有找到这样一个。您可以使用obejct映射器来实现这一点,请参阅我更新的PGObjectSerializeRun。幸运的是,else
部分导致字符串键序列化期间出现异常:由以下原因引起:com.fasterxml.jackson.core.jsongGenerationException:无法写入字符串,需要字段名(上下文:Object)
。我尝试了serializers.defaultSerializeValue(value,gen)
和gen.writeString(value.toString())
但得到了相同的错误。尝试mapper.writeValue(gen,object)在@oleg.cherednik的评论中对模块
进行了一个小的修复之后,我也在answer中更新了code>。谢谢尝试使用module.addSerializer()而不是addKeySerializer。我认为密钥序列化程序只适用于密钥。@oleg.cherednik,感谢您指出这一点,这就是原因!我已经改为addSerializer
,现在我的代码运行得非常好。
@Service
@Transactional
public class MyClass {
private final ObjectWriter writer;
private final MyRepo repository;
@Autowired
public MyClass(MyRepo repository) {
this.repository = repository;
SimpleModule module = new SimpleModule();
module.addKeySerializer(PGobject.class, new PgObjectSerializer());
ObjectMapper mapper = new ObjectMapper();
JavaType myMapType = mapper.getTypeFactory().
constructMapType(HashMap.class, String.class, PGobject.class);
writer = mapper.registerModule(module).writerFor(myMapType);
}
...
private String toJsonString(Map<String, Object> map) {
try {
return writer.writeValueAsString(map);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}
[Test worker] ERROR
com.fasterxml.jackson.databind.JsonMappingException: object is not an instance of declaring class (through reference chain: java.util.HashMap["end_date"]->java.lang.String["type"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:388)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:348)
at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:343)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:698)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFieldsUsing(MapSerializer.java:736)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:534)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:30)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:416)
at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1425)
at com.fasterxml.jackson.databind.ObjectWriter._configAndWriteValue(ObjectWriter.java:1158)
at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString(ObjectWriter.java:1031)
JavaType myMapType = mapper.getTypeFactory().
constructMapType(HashMap.class, String.class, Object.class);
class PgObjectSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object object, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (object instanceof PGobject) {
PGobject pgObject = (PGobject) object;
switch (pgObject.getType()) {
case "json":
case "jsonb":
gen.writeRawValue(pgObject.getType());
break;
default:
gen.writeString(pgObject.getType());
}
}else{
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(gen, object);
}
}
}