我正在尝试反序列化JSON对象,例如
{
"name":"aaa",
"children": [
{"name":"bbb"}
]
}
Java子对象引用父对象的对象,例如:
public class Parent {
public String name;
public List<Child> children;
}
public class Child {
public String name;
public Parent parent;
}
// ...
new ObjectMapper().readValue(<JSON>, Parent.class);
像这样反序列化时,子对象#父对象不会指向父对象。我在做在线研究时读到了两种方法,但非似乎有效。
1.向UNICEF
类添加构造函数arg以设置父对象
public class Child {
public String name;
public Parent parent;
public Child(Parent parent) {
this.parent = parent;
}
}
执行此操作时,我得到错误:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
Cannot construct instance of `Child` (no Creators, like default construct, exist):
cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"name":"aaa","children":[{"name":"bbb"}]}"; line: 1, column: 27]
(through reference chain: Parent["children"]->java.util.ArrayList[0])
2.使用@JsonBack参考
和@JsonManaged参考
注释
public class Parent {
public String name;
@JsonBackReference
public List<Child> children;
}
public class Child {
public String name;
@JsonManagedReference
public Parent parent;
}
此操作失败:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
Cannot handle managed/back reference 'defaultReference':
back reference type (java.util.List) not compatible with managed type (Child)
at [Source: (String)"{"name":"aaa","children":[{"name":"bbb"}]}"; line: 1, column: 1]
JsonBackReference的JavaDoc说它不能应用于集合,所以它显然不起作用,但我想知道为什么在线上有这么多例子将它应用于集合。
问题:当对象图反序列化时,如何实现子对象get的其父/所有者对象的自动设置。实际上,我更愿意以某种方式让第一种方法发挥作用,因为它不需要使用特定于框架的注释来污染类。
关于第二种方法,您必须更改注释的一侧。
public class Parent {
public String name;
@JsonManagedReference
public List<Child> children;
}
public class Child {
public String name;
@JsonBackReference
public Parent parent;
}
我花了更多的时间深入研究了Jackson的源代码,我用一个定制的BeanDeserializer找到了一个通用的解决方案。自定义反序列化器检查要序列化的JSON节点的对应Java类是否具有单参数构造函数,该构造函数可以获取父对象并使用它实例化该对象。
import org.apache.commons.lang3.reflect.ConstructorUtils;
public static class CustomBeanDeserializer extends BeanDeserializer {
private static final long serialVersionUID = 1L;
public CustomBeanDeserializer(BeanDeserializerBase src) {
super(src);
}
@Override
protected Object deserializeFromObjectUsingNonDefault(JsonParser p, DeserializationContext ctxt) throws IOException {
Object parentObject = getParentObject(p);
if (parentObject != null) {
// determine constructor that takes parent object
Constructor<?> ctor = ConstructorUtils.getMatchingAccessibleConstructor(_beanType.getRawClass(), parentObject.getClass());
if (ctor != null) {
try {
// instantiate object
Object bean = ctor.newInstance(parentObject);
p.setCurrentValue(bean);
// deserialize fields
if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {
String propName = p.getCurrentName();
do {
p.nextToken();
SettableBeanProperty prop = _beanProperties.find(propName);
if (prop == null) {
handleUnknownVanilla(p, ctxt, bean, propName);
continue;
}
try {
prop.deserializeAndSet(p, ctxt, bean);
} catch (final Exception e) {
wrapAndThrow(e, bean, propName, ctxt);
}
} while ((propName = p.nextFieldName()) != null);
}
return bean;
} catch (ReflectiveOperationException ex) {
ex.printStackTrace();
}
}
}
return super.deserializeFromObjectUsingNonDefault(p, ctxt);
}
private Object getParentObject(JsonParser p) {
JsonStreamContext parentCtx = p.getParsingContext().getParent();
if (parentCtx == null)
return null;
Object parentObject = parentCtx.getCurrentValue();
if (parentObject == null)
return null;
if (parentObject instanceof Collection || parentObject instanceof Map || parentObject.getClass().isArray()) {
parentCtx = parentCtx.getParent();
if (parentCtx != null) {
parentObject = parentCtx.getCurrentValue();
}
}
return parentObject;
}
}
反序列化器的使用方式如下:
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule myModule = new SimpleModule();
myModule.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig cfg, BeanDescription beanDescr, JsonDeserializer<?> deserializer) {
if (deserializer instanceof BeanDeserializerBase)
return new CustomBeanDeserializer((BeanDeserializerBase) deserializer);
return deserializer;
}
});
objectMapper.registerModule(myModule);
objectMapper.readValue(<JSON>, Parent.class);
我仍然对需要更少自定义代码的更好的解决方案感兴趣。
您可能需要为此编写自己的简单反序列化程序。可能隐约是这样的:
public class FamilyDeserializer extends JsonDeserializer<Parent> {
private ObjectMapper mapper;
@Override
public Parent deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JsonNode node = p.getCodec().readTree(p);
Parent parent = mapper.readValue(p, new TypeReference<Parent>() {
});
Child child = mapper.readValue(node.get("children").toString(), new TypeReference<Child>() {
});
parent.setChild(child);
return parent;
}
我目前正在开发一个Java web应用程序,它使用Magento REST API公开的JSON数据。api返回的数据示例如下: 我的应用程序中有一个Java类,如下所示: 我想对数据进行反序列化,并将其转换为,但我总是得到以下错误: 这是我用来将JSON响应反序列化为ArrayList的语句行: 有人能分享一些见解吗?我看到一些例子,返回的JSON对象前面没有任何ID。那是因为我做错了什么吗?非
我试图获取我的Web请求JSON输出并解析它。这是输出 我为这些结果创建了公共课程 当我尝试反序列化Record类并选择名称时,我从RootObject类获得名称。这是我的密码
问题内容: 我的JSON有点弱,所以我需要一些帮助。 我正在尝试反序列化用户的JSON: 放入我用属性装饰的对象中: 我得到以下异常: Newtonsoft.Json.JsonSerializationException:在JSON中找不到必需的属性’user_id’。 这是因为JSON对象是一个数组吗?如果是这样,如何将其反序列化为一个User对象? 提前致谢! 问题答案: 正如Alexandr
问题内容: 我有一堂课POJO 我有一个像 我正在使用Jackson ObjectMapper进行反序列化。在不创建任何其他父类的情况下如何获得? 如果不可能,是否有可能获得仅包含json字符串的第一个元素的对象,即在这种情况下和? 问题答案: 您首先需要获取数组 打印(带有)
问题内容: 我正在尝试反序列化来自API的JSON响应。JSON如下所示(MAC地址和位置已更改): 问题在于措施措施。由于对象的名称正在更改,因此我不知道如何将其正确反序列化为C#对象。我在这里发现使用字典的解决方案存在类似问题,但是如果以这种方式尝试,我只会得到空目录。 这是我的反序列化方法: 这是APIResponse类: 有什么方法可以轻松地适当地反序列化这些措施吗? 问题答案: 看来您应
问题内容: 我对反序列化json对象几乎没有问题。我的json来自http网址: 我下载的JSON的屏幕 我不知道如何反序列化以动态创建按钮。我想出了如何用文本创建按钮,但是我不知道如何使用它们所具有的选项来创建按钮。我尝试在Windows Form应用程序中获取这些选项进行测试,但应用程序将崩溃。谢谢你的帮助。 问题答案: 您的课程应类似于: 然后,您应该可以使用Newtonsoft.Json反