I am dealing with a situation where I have polymorphic classes that I need to deserialize.
Class Pen{
String name;
List<Animal> animals;
}
//Animal can be an interface or parent class: I am flexible
Class Animal{
AnimalType type;//enum
int legs;
}
enum AnimalType{
dog,cat,pig,chicken;
}
Class AnimalDog extends Animal{
//…
}
Class AnimalCat extends Animal{
//…
}
Class AnimalPig extends Animal{
//…
}
then I create my Gson instance with
public static Gson instanceUpperCamelCaseWithTypeAdapterFactory() {
if (null == sGsonUpperCamelCase) {
final RuntimeTypeAdapterFactory<Animal> typeFactory = RuntimeTypeAdapterFactory
.of(Animal.class, “type")
.registerSubtype(AnimalDog.class, “dog”)
.registerSubtype(AnimalCat.class, “cat”)
.registerSubtype(AnimalPig.class, “pig”);
sGsonUpperCamelCase = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
.registerTypeAdapterFactory(typeFactory).create();
}//the naming policy is because server sends me upper case fields whereas Java fields are lowercase.
return sGsonUpperCamelCase;
}
To get the animals from a json that contains a list of animals, I do
List<Animal> animals = gson.fromJson(json, new TypeToken<List<Animal>>() {}.getType());
I am completely a newbie to Gson. Completely. So without confusing me too much, how might I solve this problem?
Error trace:
com.google.gson.JsonParseException: cannot deserialize class com.company.appname.data.model.Animal because it does not define a field named type
com.company.appname.utils.RuntimeTypeAdapterFactory$1.read(RuntimeTypeAdapterFactory.java:204)
com.google.gson.TypeAdapter$1.read(TypeAdapter.java:199)
com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82)
com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:117)
com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:217)
com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82)
com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
com.google.gson.Gson.fromJson(Gson.java:861)
com.google.gson.Gson.fromJson(Gson.java:826)
com.google.gson.Gson.fromJson(Gson.java:775)
I run the json through an online validator, there is no problem with it. It has a number of items. Here I show two.
{“Animals”:[{
“id":9,
“type”:”dog”,
“name”:”maximus”
},
{
“id":10,
“type”:”cat”,
“name”:”meowy”,
“yarns”:5,
“nice”:true
}]}
type
toString
and provide the label to the super class – MisquotationAnimalType type;
toString type;
, and assign "dog" to it fromAnimalDog
(do the same for the other animals) – Misquotationtype
field? – Agrariananimal.getType()
and the value is null. And that's after changingtype
to String instead of using enum. – Agrariantype
is aString
. How should it be parsed in a Enum? Could you try changing the enum like:enum AnimalType{ @SerializedName("dog") dog, @SerializedName("cat") cat, @SerializedName("pig") pig, @SerializedName("chicken") chicken; }
– Misquotationtype
value still gets swallowed. In fact, if I remove the type field from the POJO it still works as long as the json from the server has the type field. So the field is thought to be for theRuntimeTypeAdapterFactory
and not for the object and so it is not serialized as part of the POJO. – Agrarian