GSON不反序列化对外部类的引用 [英] GSON does not deserialize reference to outer class
问题描述
在我的Java应用程序中,我定义了两个类,分别称为 A
和 B
,其中 B
是 A
的内部类。两者都被定义为可序列化的
public class A implements Serializable {
int attrParent;
列表< B> items = new ArrayList< B>();
public void setAttrParent(int attrParent){
this.attrParent = attrParent;
}
public int getAttrParent(){
return attrParent;
}
public class B实现了Serializable {
private int attr;
public void setAttr(int attr){
this.attr = attr;
}
public int getAttr(){
return attr;
}
public int getSomeCalculationValue(){
return this.attr * A.this.attrParent; //出现问题
}
}
}
在使用GSON序列化此对象之前, getSomeCalculationValue
可以正常工作。但是,在序列化和反序列化之后, getSomeCalculationValue
会因 NullPointerException
而失败。
发生这种情况是因为内部类 B
没有引用外部类 A
了,所以 A.this
失败。
有谁知道怎么可能我解决了这个问题,那就是在反序列化这个对象时恢复内部到外部的引用吗?
正如Gson文档所说: >
Gson可以很容易地序列化静态嵌套类。
Gson还可以反序列化静态嵌套类。然而, Gson可以
不会自动反序列化纯内部类,因为它们的
no-args构造函数也需要对包含在反序列化时不可用的对象
的引用即可。您可以通过使内部类为静态或
为其提供自定义InstanceCreator来解决此问题。
将B更改为静态内部类是不可能的,因为您的方法需要对 getSomeCalculationValue
中的外部类的引用,所以,我尝试用 InstanceCreator
但解决方案有点难看,所以我建议您使用自定义的反序列化。我稍微改变了你的 A
类,使公开的项目更容易创建我展示给你的例子。
public class ADeserializer实现了JsonDeserializer< A> {
public反序列化(JsonElement json,类型typeOfT,
JsonDeserializationContext上下文)抛出JsonParseException {
A a = new A();
a.attrParent = json.getAsJsonObject()。get(attrParent)。getAsInt();
JsonArray ja = json.getAsJsonObject()。get(items)。getAsJsonArray();
for(JsonElement e:ja){
B b = a.new B();
b.setAttr(e.getAsJsonObject()。get(attr)。getAsInt());
.items.add(b);
}
return a;
}
}
这就是我使用它的方式:
public class Q19449761 {
public static void main(String [] args){
A a = new A();
a.setAttrParent(3);
B b = a.new B();
b.setAttr(10);
.items.add(b);
System.out.println(序列化之前:+ a.items.get(0).getSomeCalculationValue());
Gson g = new Gson();
字符串json = g.toJson(a,A.class);
System.out.println(JSON string:+ json);
test2 = g.fromJson(json,A.class);
尝试{
System.out.println(After standard deserialization:+ test2.items.get(0).getSomeCalculationValue());
} catch(Exception e){
e.printStackTrace();
}
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(A.class,new ADeserializer());
test3 = builder.create()。fromJson(json,A.class);
System.out.println(自定义反序列化之后:+ test3.items.get(0).getSomeCalculationValue());
}
}
这是我的执行:
序列化前:30
JSON字符串:{attrParent:3,items:[ {attr:10}]}
java.lang.NullPointerException
at stackoverflow.questions.q19449761.A $ B.getSomeCalculationValue(A.java:32)
at stackoverflow.questions。 q19449761.Q19449761.main(Q19449761.java:26)
自定义反序列化后:30
两个最后的注释:
- 您不需要实现
Serializable
接口,JSON有与Java序列化没有什么共同之处。
- 我的反序列化器缺少空案例管理,您应该填写空JSON或空字段 。
On my Java application, I defined two classes, called A
and B
where B
is inner class of A
. Both are defined as serializable
public class A implements Serializable {
int attrParent;
List<B> items = new ArrayList<B>();
public void setAttrParent(int attrParent) {
this.attrParent = attrParent;
}
public int getAttrParent() {
return attrParent;
}
public class B implements Serializable {
private int attr;
public void setAttr(int attr) {
this.attr = attr;
}
public int getAttr() {
return attr;
}
public int getSomeCalculationValue() {
return this.attr * A.this.attrParent; // Problems occurs here
}
}
}
Before serializing this object with GSON, getSomeCalculationValue
works fine. But, after serializing and deserializing, getSomeCalculationValue
fails with a NullPointerException
.
This happens because the inner class B
doesn´t have a reference to outer class A
anymore, so, A.this
fails.
Does anybody knows how could I solve this, that is restoring the inner to outer reference while deserializing this object?
As Gson documentation says:
Gson can serialize static nested classes quite easily.
Gson can also deserialize static nested classes. However, Gson can not automatically deserialize the pure inner classes since their no-args constructor also need a reference to the containing Object which is not available at the time of deserialization. You can address this problem by either making the inner class static or by providing a custom InstanceCreator for it.
Changing B to a static inner class is not possible since your method needs a reference to the outer class in getSomeCalculationValue
, so, I've tried to solve your problem with an InstanceCreator
but solution was a bit ugly, so I propose you to use a custom deserialized. I changed your A
class a little, making items public to make easier to create the example I show you.
public class ADeserializer implements JsonDeserializer<A> {
public A deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
A a = new A();
a.attrParent = json.getAsJsonObject().get("attrParent").getAsInt();
JsonArray ja = json.getAsJsonObject().get("items").getAsJsonArray();
for(JsonElement e: ja){
B b = a.new B();
b.setAttr(e.getAsJsonObject().get("attr").getAsInt());
a.items.add(b);
}
return a;
}
}
And this is how I use it:
public class Q19449761 {
public static void main(String[] args) {
A a = new A();
a.setAttrParent(3);
B b = a.new B();
b.setAttr(10);
a.items.add(b);
System.out.println("Before serializing: " + a.items.get(0).getSomeCalculationValue());
Gson g = new Gson();
String json = g.toJson(a, A.class);
System.out.println("JSON string: " + json);
A test2 = g.fromJson(json, A.class);
try {
System.out.println("After standard deserialization: " +test2.items.get(0).getSomeCalculationValue());
} catch (Exception e) {
e.printStackTrace();
}
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(A.class, new ADeserializer());
A test3 = builder.create().fromJson(json, A.class);
System.out.println("After custom deserialization: " + test3.items.get(0).getSomeCalculationValue());
}
}
And this is my execution:
Before serializing: 30
JSON string: {"attrParent":3,"items":[{"attr":10}]}
java.lang.NullPointerException
at stackoverflow.questions.q19449761.A$B.getSomeCalculationValue(A.java:32)
at stackoverflow.questions.q19449761.Q19449761.main(Q19449761.java:26)
After custom deserialization: 30
Two final notes:
- You do not need to implement
Serializable
interface, JSON has nothing in common with Java serialization - My deserializer lacks of null cases management, you should complete for null JSON or null fields.
这篇关于GSON不反序列化对外部类的引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!