GSON不反序列化对外部类的引用 [英] GSON does not deserialize reference to outer class

查看:145
本文介绍了GSON不反序列化对外部类的引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的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

两个最后的注释:


  1. 您不需要实现 Serializable 接口,JSON有与Java序列化没有什么共同之处。
  2. 我的反序列化器缺少空案例管理,您应该填写空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:

  1. You do not need to implement Serializable interface, JSON has nothing in common with Java serialization
  2. My deserializer lacks of null cases management, you should complete for null JSON or null fields.

这篇关于GSON不反序列化对外部类的引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆