如何解决FasterXml - JsonSerializer HashMap
我正在使用 jackson-databind 版本 2.12.3 来序列化一个应该像这样返回的对象的返回:
{
"field1":"value1","field2":"value2","links":{
"field":{
"href":"/link"
},"test":{
"href":"/test"
}
}
}
我的课程是:
public class HrefType {
private String href = null;
...
}
public class Link extends HashMap<String,HrefType> {
private HrefType field = null;
...
}
public class MyObject {
private String field1 = null;
private String field2 = null;
private Link links = null;
...
}
返回的是myObject:
MyObject myObject = new MyObject();
myObject.setField1("value1");
myObject.setField2("value2");
Link link = new Link();
link.setField(new HrefType().href("/link"));
link.put("test",new HrefType().href("/test"));
myObject.setLinks(link);
然而,默认的 ObjectMapper 会忽略“link.setField”,返回的 json 是:
{
"field1":"value1","links":{
"test":{
"href":"/test"
}
}
}
我尝试使用 JsonSerializer 进行一些测试,但无法对所有扩展 HashMap 的类进行通用测试(这些类是从 BerlinGroup 的 PSD2 YAML 生成的,因此我不想更改生成的类)。
是否有通用的方法来实现,或者我应该为每个扩展 HashMap 的类创建一个序列化类?
解决方法
组成
首先,我建议您在这种特殊情况下使用 composition 而不是 inheritance。您的代码如下所示:
private class Link {
private final HrefType field;
private final HashMap<String,HrefType> test;
public Link(HrefType field) {
this.field = field;
}
public HrefType getField() {
return field;
}
public HashMap<String,HrefType> getTest() {
return test;
}
}
并且序列化将按预期正常工作。
序列化器
但万一,如果您无法更改原始代码,您可以编写自己的StdSerializer
。例如:
private class LinkSerializer extends StdSerializer<Link> {
public LinkSerializer() {
super(Link.class);
}
@Override
public void serialize(Link link,JsonGenerator jsonGenerator,SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
final HrefType field = link.getField();
jsonGenerator.writeObjectField("field",field);
jsonGenerator.writeObjectField("test",new HashMap<>(link));
jsonGenerator.writeEndObject();
}
}
并在您的 Link
类上声明它:
@JsonSerialize(using = LinkSerializer.class)
private static class Link extends HashMap<String,HrefType> {
private final HrefType field;
public Link(HrefType field) {
this.field = field;
}
public HrefType getField() {
return field;
}
}
,
基于 this answer,我开发了这种通用方法来制作扩展地图的所有对象:
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Map;
import org.springframework.util.ReflectionUtils;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
public class MyClassSerializer extends JsonSerializer<Object> {
private final JsonSerializer<Object> defaultSerializer;
public MyClassSerializer(JsonSerializer<Object> defaultSerializer) {
this.defaultSerializer = (defaultSerializer);
}
@SuppressWarnings({ "unchecked","rawtypes" })
@Override
public void serialize(Object src,JsonGenerator gen,SerializerProvider provider) throws IOException {
Field[] fields = src.getClass().getDeclaredFields();
for (Field field : fields) {
try {
boolean fieldAccessible = field.isAccessible();
field.setAccessible(true);
Object object = ReflectionUtils.getField(field,src);
if (object != null && object instanceof Map) {
Field[] fieldsMap = object.getClass().getDeclaredFields();
Map map = (Map) object;
for (Field fieldMap : fieldsMap) {
boolean fieldMapAccessible = fieldMap.isAccessible();
fieldMap.setAccessible(true);
Object fieldObject = ReflectionUtils.getField(fieldMap,object);
if (fieldObject != null) {
map.put(fieldMap.getName(),fieldObject);
}
fieldMap.setAccessible(fieldMapAccessible);
}
}
field.setAccessible(fieldAccessible);
} catch (Exception e) {
e.printStackTrace();
}
}
defaultSerializer.serialize(src,gen,provider);
}
@Override
public Class<Object> handledType() {
return Object.class;
}
}
遍历所有字段,当我找到一个从 Map 扩展的字段时,我遍历这个字段的所有字段并将其添加到 Map 忽略对象的字段,因此序列化程序可以完美运行。
编辑:正确地反序列化我这样做:
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Map;
import org.springframework.util.ReflectionUtils;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.ResolvableDeserializer;
@SuppressWarnings("rawtypes")
public class MyClassDeserializer extends JsonDeserializer implements ResolvableDeserializer {
private JsonDeserializer defaultDeserializer;
protected MyClassDeserializer(JsonDeserializer deserializer) {
this.defaultDeserializer = deserializer;
}
@SuppressWarnings("unchecked")
@Override
public Object deserialize(JsonParser p,DeserializationContext ctxt) throws IOException,JsonProcessingException {
Object obj = defaultDeserializer.deserialize(p,ctxt);
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
try {
boolean fieldAccessible = field.isAccessible();
field.setAccessible(true);
Object object = ReflectionUtils.getField(field,obj);
if (object != null && object instanceof Map) {
Field[] fieldsMap = object.getClass().getDeclaredFields();
Map map = (Map) object;
for (Object key : map.keySet()) {
for (Field fieldMap : fieldsMap) {
if (fieldMap.getName().equals((String) key)) {
if (fieldMap.getName().equalsIgnoreCase("serialVersionUID")) {
continue;
}
boolean fieldMapAccessible = fieldMap.isAccessible();
fieldMap.setAccessible(true);
Object fieldObject = ReflectionUtils.getField(fieldMap,object);
if (fieldObject == null) {
fieldMap.set(object,map.get(key));
map.replace(key,null);
}
fieldMap.setAccessible(fieldMapAccessible);
}
}
}
Object[] keys = map.keySet().toArray();
for (int i = 0; i < keys.length; i++) {
if(map.get(keys[i])==null) {
map.remove(keys[i]);
}
}
}
field.setAccessible(fieldAccessible);
} catch (Exception e) {
e.printStackTrace();
}
}
return obj;
}
@Override
public void resolve(DeserializationContext ctxt) throws JsonMappingException {
((ResolvableDeserializer) defaultDeserializer).resolve(ctxt);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。