2013-10-18 27 views
5

W mojej aplikacji Java zdefiniowałem dwie klasy o nazwie A i B, gdzie B jest wewnętrzną klasą A. Oba są zdefiniowane jako serializableGSON nie deserializuje odwołania do zewnętrznej klasy

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 
     } 

    } 
} 

Przed szeregowania ten obiekt z GSON, getSomeCalculationValue działa dobrze. Ale po serializowanie i deserializowanie, getSomeCalculationValue kończy się niepowodzeniem z NullPointerException.

Dzieje się tak, ponieważ wewnętrzna klasa B nie ma już odniesienia do klasy zewnętrznej A, a więc A.this zawodzi.

Czy ktoś wie, jak rozwiązać ten problem, czyli przywracając wewnętrzny do zewnętrznego odniesienia podczas deserializacji tego obiektu?

+0

Proszę pokazać proces serializacji i deserializacji, a także przykładowy gson. Nie rozumiem, dlaczego potrzebujesz "Serializable" tutaj. –

Odpowiedz

6

jako dokumentacja Gson mówi:

Gson może serializacji statycznych klas zagnieżdżonych dość łatwo.

Gson może również deserializować statyczne klasy zagnieżdżone. Jednakże, Gson może nie automatycznie deserializować czystych klas wewnętrznych, ponieważ ich konstruktor no-args potrzebuje również odniesienia do obiektu zawierającego obiekt , który nie jest dostępny w czasie deserializacji. Możesz rozwiązać ten problem przez uczynienie wewnętrznej klasy statyczną lub przez dostarczenie niestandardowego InstanceCreatora.

Zmiana B do statycznego klasy wewnętrznej nie jest możliwe, ponieważ metoda wymaga odniesienia do zewnętrznej klasy w getSomeCalculationValue, więc starałem się rozwiązać problemu z InstanceCreator ale rozwiązanie było trochę brzydki, więc Proponuję użyć niestandardowego deserialized. Zmieniłem trochę klasę A, upubliczniając elementy, aby ułatwić tworzenie przykładu, który ci pokazałem.

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

} 

I to jak go używać:

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

    } 

} 

A to moja wykonanie:

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 

Dwa końcowe uwagi:

  1. Nie trzeba implementuj interfejs Serializable, JSON nie ma nic wspólnego z Ja serializacja va
  2. W moim deserializatorze brakuje zarządzania przypadkami pustymi, powinieneś wypełnić puste pola JSON lub puste.
+0

"Statyczny wewnętrzny" to sprzeczność w terminach. – EJP

Powiązane problemy