How to handle deserializing with polymorphism?

前端 未结 4 548
既然无缘
既然无缘 2020-11-27 17:04

I have a class like:

public class Barn {
    String type;
    Animal animal;
}

public class Horse extends Animal {
}

public class Cow extends Animal {
}
         


        
4条回答
  •  清酒与你
    2020-11-27 17:28

    In the Gson project code base is the RuntimeTypeAdapter, which reportedly works well for polymorphic serialization and deserialization. I don't think I've yet tried to use it. See http://code.google.com/p/google-gson/issues/detail?id=231 for more info. Note, it hasn't yet been included in any Gson releases.

    If use of it doesn't fit your needs, then custom deserialization processing is necessary. Following is one such approach, assuming you want to use the JSON structure demonstrated. (I'd take a somewhat different approach, if the JSON structure could be different.)

    import java.lang.reflect.Type;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    import com.google.gson.JsonDeserializationContext;
    import com.google.gson.JsonDeserializer;
    import com.google.gson.JsonElement;
    import com.google.gson.JsonObject;
    import com.google.gson.JsonParseException;
    import com.google.gson.reflect.TypeToken;
    
    public class App
    {
      public static void main(String[] args)
      {
        Barn[] barns = {new Barn(), new Barn()};
        barns[0].type = "horse";
        barns[0].animal = new Horse();
        barns[1].type = "cow";
        barns[1].animal = new Cow();
    
        String json = new Gson().toJson(barns);
        // [{"type":"horse","animal":{}},{"type":"cow","animal":{}}]
    
        BarnDeserializer deserializer = new BarnDeserializer("type");
        deserializer.registerBarnType("horse", Horse.class);
        deserializer.registerBarnType("cow", Cow.class);
        Gson gson = new GsonBuilder().registerTypeAdapter(Barn.class, deserializer).create();
    
        List barns2= gson.fromJson(json, new TypeToken>(){}.getType());
        for (Barn barn : barns2)
        {
          System.out.println(barn.animal.getClass());
        }
      }
    }
    
    class BarnDeserializer implements JsonDeserializer
    {
      String barnTypeElementName;
      Gson gson;
      Map> barnTypeRegistry;
    
      BarnDeserializer(String barnTypeElementName)
      {
        this.barnTypeElementName = barnTypeElementName;
        gson = new Gson();
        barnTypeRegistry = new HashMap<>(); // Java 7 required for this syntax.
      }
    
      void registerBarnType(String barnTypeName, Class animalType)
      {
        barnTypeRegistry.put(barnTypeName, animalType);
      }
    
      @Override
      public Barn deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 
          throws JsonParseException
      {
        JsonObject barnObject = json.getAsJsonObject();
        JsonElement animalTypeElement = barnObject.get(barnTypeElementName);
        Barn barn = new Barn();
        barn.type = animalTypeElement.getAsString(); 
        Class animalType = barnTypeRegistry.get(barn.type);
        barn.animal = gson.fromJson(barnObject.get("animal"), animalType);
        return barn;
      }
    }
    
    class Barn {String type; Animal animal;}
    class Animal {}
    class Horse extends Animal {}
    class Cow extends Animal {}
    

提交回复
热议问题