2013-10-18 6 views
5

In meiner Java-Anwendung habe ich zwei Klassen mit den Namen A und B definiert, wobei B die innere Klasse A ist. Beide sind definiert als serializableGSON deserialisiert den Verweis auf die äußere Klasse nicht

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 
     } 

    } 
} 

Bevor Serialisierung dieses Objekt mit Gson, getSomeCalculationValue gut funktioniert. Aber nach Serialisierung und Deserialisierung, schlägt getSomeCalculationValue mit einem NullPointerException.

Dies passiert, weil die innere Klasse B keinen Bezug mehr auf die äußere Klasse A hat, so dass A.this fehlschlägt.

Weiß jemand, wie könnte ich das lösen, das ist das Wiederherstellen der inneren zu äußeren Referenz beim Deserialisieren dieses Objekts?

+0

Bitte zeigen Sie Ihre Serialisierung und Deserialisierung sowie eine Probe gson. Ich verstehe nicht, warum du 'Serializable' hier brauchst. –

Antwort

6

Wie Gson Dokumentation sagt:

Gson statische verschachtelte Klassen ganz einfach serialisiert können.

Gson kann auch statische verschachtelte Klassen deserialisieren. Gson kann jedoch die reinen inneren Klassen nicht automatisch deserialisieren, da ihr -args-Konstruktor auch einen Verweis auf das enthaltende Objekt benötigt, das zum Zeitpunkt der Deserialisierung nicht verfügbar ist. Sie können dieses Problem beheben, indem Sie entweder die innere Klasse statisch machen oder einen benutzerdefinierten InstanceCreator dafür bereitstellen.

zu einer statischen inneren Klasse ändern B ist nicht möglich, da Ihre Methode einen Verweis auf die äußere Klasse in getSomeCalculationValue muss, so, ich habe versucht, das Problem mit einer InstanceCreator aber Lösung war ein bisschen hässlich zu lösen, so Ich schlage vor, Sie verwenden eine benutzerdefinierte deserialized. Ich habe die Klasse A ein wenig geändert und die Artikel veröffentlicht, um das Beispiel, das ich Ihnen zeige, einfacher zu erstellen.

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; 
    } 

} 

Und das ist, wie ich es verwenden:

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()); 

    } 

} 

Und das ist meine Ausführung:

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 

Zwei abschließende Bemerkungen:

  1. Sie brauchen nicht zu implementieren Serializable Schnittstelle, hat JSON nichts mit Ja zu tun va Serialisierung
  2. Mein Deserializer fehlt Null-Fälle-Verwaltung, sollten Sie für null JSON oder Null Felder ausfüllen.
+0

"statische innere" ist ein Widerspruch in Bezug auf. – EJP

Verwandte Themen