Reputation: 2382
My set up is like so:
public enum AnimalType {
CAT(1),
DOG(2);
private final int value;
AnimalType(int value) {
this.value = value;
}
public int value() { return value; }
}
public class Dog {
AnimalType type = AnimalType.DOG;
String name;
int id;
//Other properties. Point is to distinguish it from a Cat object.
}
public class Cat {
AnimalType type = AnimalType.CAT;
String name;
String nickName;
int age;
}
public class Response {
ArrayList<Object> myResponseObject;
}
Here's an example of how a Response object might look:
ArrayList<Object> arr = new ArrayList<Object>();
Dog dog = new Dog("MyName",0);
Cat cat = new Cat("MyName","MyNickName",-1);
arr.add("I have a ");
arr.add(cat)
arr.add(" and a ");
arr.add(dog)
Response response = new Response(arr);
and I am serializing like so:
Gson gson = new Gson();
String serializedOutput = gson.toJson(response);
and hope to deserialize like so:
//the ArrayList<Object> should be populated correctly inside of it?
Response deserializedObject = gson.fromJson(serializedOutput);
However, on deserializing this list, I need the objects to map back to their respective types. I suspect I need to at least tag the class or type into my serialization of Dog or Cat. For now, I am adding a Type property (instead of interface) on Dog and Cat.
Without anything fancy, the Cat
and Dog
objects are by default treated as LinkedTreeMap<K,V>
when deserialized. I have to iterate through my arraylist, check if it is an instanceof LinkedTreeMap, call the "type" key to get the type, and then cast my object to Dog or Cat. This all just seems a bit hacky to me, and I'm wondering if there's a more elegant way to do this.
Should I be using a custom serializer/deserializer for my Cat/Dog objects or is the RuntimeTypeAdapterFactory the way to go? Any guidance would be appreciated.
Note, I'm also custom serializing/deserializing my enum by following the directions from Gson: How to change output of Enum. I'm not sure whether that affects anything.
Thanks
Upvotes: 3
Views: 3029
Reputation: 76898
This is covered in the users guide. You are attempting to deserialize a collection of arbitrary types
As noted there, you have 3 options:
Option 1: Use Gson's parser API (low-level streaming parser or the DOM parser JsonParser) to parse the array elements and then use Gson.fromJson() on each of the array elements.This is the preferred approach.
Option 2: Register a type adapter for Collection.class that looks at each of the array members and maps them to appropriate objects. The disadvantage of this approach is that it will screw up deserialization of other collection types in Gson.
Option 3: Register a type adapter for MyCollectionMemberType and use fromJson with Collection<MyCollectionMemberType> This approach is practical only if the array appears as a top-level element or if you can change the field type holding the collection to be of type Collection<MyCollectionMemberType>.
This is a difficult problem when talking about automatic deserialization. In addition, option 3 isn't possible in your case as you're using Object
rather than having Dog
and Cat
inherit from some base class (e.g. Animal
).
On top of that ... you're doing something very odd with that array of Objects, sticking String
s in it as well. Overall, if that's some response you yourself are generating ... I'd seriously rethink how you're approaching that.
Upvotes: 1