2015-06-03 7 views
10

В приведенном ниже примере показан класс (Club), который содержит коллекцию абстрактного класса (Member). Я смущен тем, нужен ли мне TypeAdapter или JsonDeserializer для правильной работы десериализации. Сериализация работает отлично, без какой-либо помощи, но десериализация бросает исключения. Для иллюстрации я построил следующий тест «клон». Если бы кто-нибудь мог показать рабочий пример, я был бы очень благодарен.Адаптер типа Gson и Custom Deseralizer

Первый клуб класса

package gson.test; 
import java.util.ArrayList; 

import com.google.gson.Gson; 

public class Club { 
    public static void main(String[] args) { 
     // Setup a Club with 2 members 
     Club myClub = new Club(); 
     myClub.addMember(new Silver()); 
     myClub.addMember(new Gold()); 

     // Serialize to JSON 
     Gson gson = new Gson(); 
     String myJsonClub = gson.toJson(myClub); 
     System.out.println(myJsonClub); 

     // De-Serialize to Club 
     Club myNewClub = gson.fromJson(myJsonClub, Club.class); 
     System.out.println(myClub.equals(myNewClub) ? "Cloned!" : "Failed"); 
    } 

    private String title = "MyClub"; 
    private ArrayList<Member> members = new ArrayList<Member>(); 

    public boolean equals(Club that) { 
     if (!this.title.equals(that.title)) return false; 
     for (int i=0; i<this.members.size(); i++) { 
      if (! this.getMember(i).equals(that.getMember(i))) return false; 
     } 
     return true; 
    } 
    public void addMember(Member newMember) { members.add(newMember); } 
    public Member getMember(int i) { return members.get(i); } 
} 

Теперь абстрактный базовый класс член

package gson.test; 
public abstract class Member { 
    private int type; 
    private String name = ""; 

    public int getType() { return type; } 
    public void setType(int type) { this.type = type; } 
    public boolean equals(Member that) {return this.name.equals(that.name);} 
} 

И два конкретных подклассы члена (золото и серебро)

package gson.test; 
public class Gold extends Member { 
    private String goldData = "SomeGoldData"; 
    public Gold() { 
     super(); 
     this.setType(2); 
    } 
    public boolean equals(Gold that) { 
     return (super.equals(that) && this.goldData.equals(that.goldData)); 
    } 
} 

package gson.test; 
public class Silver extends Member { 
    private String silverData = "SomeSilverData"; 
    public Silver() { 
     super(); 
     this.setType(1); 
    } 
    public boolean equals(Silver that) { 
     return (super.equals(that) && this.silverData.equals(that.silverData)); 
    } 
} 

И, наконец, выход

{"title":"MyClub","members":[{"silverData":"SomeSilverData","type":1,"name":""},{"goldData":"SomeGoldData","type":2,"name":""}]} 
    Exception in thread "main" java.lang.RuntimeException: Failed to invoke public gson.test.Member() with no args 
     at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:107) 
     at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:186) 
... 
+1

Метод equals() должен принимать тип параметра 'Object', а не' Club' –

+0

Спасибо, мне было бы немного поймать это. –

+0

Получил, спасибо, в следующий раз я буду голосовать. –

ответ

13

Вы можете сделать то и другое. Какой из них вы выбираете, действительно зависит от потенциального воздействия на производительность и сколько кода готовы писать.

Deserializers стоят дороже. Это связано с тем, что вход в десериализатор является деревом json, и GSon должен будет создать полное поддерево JsonElement свойства, которое соответствует вашему классу, прежде чем оно сможет передать его вашему десериализатору. Если у ваших классов много гнездования, эта стоимость увеличивается. Для простых объектов это будет незначительно.

Кажется, что вы будете знать, какой класс создать на основе значения type свойства, которое будет включено в целевой объект. Ваш десериализатор потребуется

  • взгляд на пройденный JsonElement объект, читать type свойства, определить тип
  • вызова context.deserialize() с классом и тот же элемент, который был передан вам
  • выдаст ошибку, если тип отсутствует или недействителен

Адаптер вашего типа должен быть более сложным. Входным адаптером типа является поток, а не элемент/поддерево. Вы можете загрузить следующее значение из потока, проанализировать его, а затем сделать именно то, что сделал десериализатор, что не имеет смысла, и вы можете просто использовать интерфейс десериализатора. Кроме того, вы можете прочитать поток, посмотреть, какие у него есть свойства, сохранить их в локальных переменных, пока не дойдете до свойства type (вы не можете предсказать его местоположение), затем закончите чтение оставшейся части свойств и создайте окончательный Gold/Silver объекты, основанные на типе, и все свойства считаются и сохраняются.

+0

Я проскочил через тестирование, моя сериализация не работает, как я и думал, так что похоже, мне также нужен специальный сериализатор, чтобы погрузиться в подтипы коллекции. Я продолжу тестирование и отправлю окончательный рабочий пример, когда у меня его будет. –

8

Хорошо, настоящий рабочий пример (на этот раз я уверен.).

Клуб

package gson.test; 
import java.util.ArrayList; 
import com.google.gson.Gson; 
import com.google.gson.GsonBuilder; 

public class Club { 
    public static void main(String[] args) { 
     // Setup a Club with 2 members 
     Club myClub = new Club(); 
     myClub.addMember(new Silver("Jack")); 
     myClub.addMember(new Gold("Jill")); 
     myClub.addMember(new Silver("Mike")); 

     // Get the GSON Object and register Type Adapter 
     GsonBuilder builder = new GsonBuilder(); 
     builder.registerTypeAdapter(Member.class, new MemberDeserializer()); 
     builder.registerTypeAdapter(Member.class, new MemberSerializer()); 
     builder.setPrettyPrinting(); 
     Gson gson = builder.create(); 

     // Serialize Club to JSON 
     String myJsonClub = gson.toJson(myClub); 

     // De-Serialize to Club 
     Club myNewClub = gson.fromJson(myJsonClub, Club.class); 
     System.out.println(myClub.equals(myNewClub) ? "Cloned!" : "Failed"); 
     System.out.println(gson.toJson(myNewClub)); 
    } 

    private String title = "MyClub"; 
    private ArrayList<Member> members = new ArrayList<Member>(); 

    public boolean equals(Object club) { 
     Club that = (Club) club; 
     if (!this.title.equals(that.title)) return false; 
     for (int i=0; i<this.members.size(); i++) { 
      Member member1 = this.getMember(i); 
      Member member2 = that.getMember(i); 
      if (! member1.equals(member2)) return false; 
     } 
     return true; 
    } 
    public void addMember(Member newMember) { members.add(newMember); } 
    public Member getMember(int i) { return members.get(i); } 
} 

Член Абстрактный класс

package gson.test; 
public abstract class Member { 
    private String clsname = this.getClass().getName() ; 
    private int type; 
    private String name = "unknown"; 

    public Member() { } 
    public Member(String theName) {this.name = theName;} 
    public int getType() { return type; } 
    public void setType(int type) { this.type = type; } 
    public boolean equals(Object member) { 
     Member that = (Member) member; 
     return this.name.equals(that.name); 
    } 
} 

в бетоне подклассы Серебро и золото

package gson.test; 
public class Silver extends Member { 
    private String silverData = "SomeSilverData"; 
    public Silver() { 
     super(); 
     this.setType(1); 
    } 
    public Silver(String theName) { 
     super(theName); 
     this.setType(1); 
    } 
    public boolean equals(Object that) { 
     Silver silver = (Silver)that; 
     return (super.equals(that) && this.silverData.equals(silver.silverData)); 
    } 
} 

package gson.test; 
public class Gold extends Member { 
    private String goldData = "SomeGoldData"; 
    private String extraData = "Extra Gold Data"; 
    public Gold() { 
     super(); 
     this.setType(2); 
    } 
    public Gold(String theName) { 
     super(theName); 
     this.setType(2); 
    } 
    public boolean equals(Gold that) { 
     Gold gold = (Gold) that; 
     return (super.equals(that) && this.goldData.equals(gold.goldData)); 
    } 
} 

Обычай член Serailizer

package gson.test; 
import java.lang.reflect.Type; 
import com.google.gson.JsonElement; 
import com.google.gson.JsonSerializationContext; 
import com.google.gson.JsonSerializer; 

public class MemberSerializer implements JsonSerializer<Member> { 

    public JsonElement serialize(Member src, Type member, JsonSerializationContext context) { 
     switch (src.getType()) { 
      case 1: return context.serialize((Silver)src); 
      case 2: return context.serialize((Gold)src); 
      default: return null; 
     } 
    } 
} 

Обычай десериализатор

package gson.test; 
import java.lang.reflect.Type; 
import com.google.gson.JsonDeserializationContext; 
import com.google.gson.JsonDeserializer; 
import com.google.gson.JsonElement; 

public class MemberDeserializer implements JsonDeserializer<Member> { 
    @Override 
    public Member deserialize(JsonElement json, Type member, JsonDeserializationContext context) { 
     int myType = json.getAsJsonObject().get("type").getAsInt(); 
     switch (myType) { 
      case 1: return context.deserialize(json, Silver.class); 
      case 2: return context.deserialize(json, Gold.class); 
      default: return null; 
     } 
    } 
} 

И ... выход

Cloned! 
{ 
    "title": "MyClub", 
    "members": [ 
    { 
     "silverData": "SomeSilverData", 
     "clsname": "gson.test.Silver", 
     "type": 1, 
     "name": "Jack" 
    }, 
    { 
     "goldData": "SomeGoldData", 
     "extraData": "Extra Gold Data", 
     "clsname": "gson.test.Gold", 
     "type": 2, 
     "name": "Jill" 
    }, 
    { 
     "silverData": "SomeSilverData", 
     "clsname": "gson.test.Silver", 
     "type": 1, 
     "name": "Mike" 
    } 
    ] 
} 

Я хотел бы отметить, что мое реальное использование, случай один, где производительность не должна быть проблемой, я выгрузку кеш объектов из текстовых файлов jSon, поэтому частота выполнения этого кода делает производительность намного менее важной, чем ремонтопригодность.

Смежные вопросы