Android - JSON stored list contains objects that revert to superclass when app is exited, reopened

StackOverflow https://stackoverflow.com/questions/15733747

Question

I have an ArrayList <GeneralTemplate> items

Throughout my program, I am adding Routines which are subclasses of GeneralTemplate i.e items.add(new Routine("Test")); and all is well.

Most importantly, I can do the following.. Routine myRoutine = items.get(position);

I am saving this big list of items in a special data object in JSON using Google's GSON library. I believe this may be the problem.

This data object contains the ArrayList <GeneralTemplate> items. During my program, I can see that the routines stored in the items list are indeed Routine objects. I then save it using the code below. I have followed this process with the debugger and when I setRoutineList, the Routine objects are maintained without problem.

// Global save String method
public static void save()
{
    Editor editor = sharedPreferences.edit();

    RoutineData tempSaveObject = new RoutineData();
    tempSaveObject.setRoutineList(routineList);

    String routineListInJSON = gson.toJson(tempSaveObject);

    editor.putString(ROUTINE_LIST, routineListInJSON).commit();
}

The problem occurs when I restart the app and retreive the data. All of the items in the list revert to GeneralTemplate objects and cannot be cast back to Routine via Routine routine = (Routine) items.get(position) -> ClassCastException (Code for loading below)

    // Get a global sharedPreferences object that can be used amongst Activities
    sharedPreferences = this.getSharedPreferences(SHARED_PREFS, Context.MODE_PRIVATE);

    if (sharedPreferences.contains(ROUTINE_LIST))
    {
        String routineListJSON = sharedPreferences.getString(ROUTINE_LIST, null);
        routineDataObject = gson.fromJson(routineListJSON, RoutineData.class);

        routineList = routineDataObject.getRoutineList();
    }
    else
    {
        routineList = new ArrayList<GeneralTemplate>();     
    }

Therefore, I can't access specific methods and variables because I cant regain the subclass context. There are several other instances of this problem, so if there is any good solution to this that you good folks knowledge, it would help a lot.

Thanks!

SORTED:

Genson JSON library.

https://code.google.com/p/genson/downloads/detail?name=genson-0.94.jar&can=2&q=

Made things so much easier, no need for custom serializers/deserializers. Took care of all the in depth polymorphism stuff by default.

Implemented as shown in Eugen's answer

Était-ce utile?

La solution

This is due to the fact that you have a list of GeneralTemplate, while serializing Gson knows the concrete type of each element in the list but during deserialization Gson doesn't know into which type to deserialize (as it is a list of GeneralTemplate).

I am not sure but it looks like they have some contrib (not part of Gson) that allows to add type information in the serialized stream, this allows Gson to deserialize back into the right type.

You could also try out Genson library, handling polymorphic types is supported out of the box. It has the features provided by Gson and some others too. Here is how you can achieve it:

// first configure your Genson instance to enable polymorphic types support and  
// serialization based on concrete types
Genson genson = new Genson.Builder()
                            .setWithClassMetadata(true)
                            .setUseRuntimeTypeForSerialization(true)
                            .create();

// and now just use it to serialize/deser
String json = genson.serialize(routineData);
RoutineData data = genson.deserialize(json, RoutineData.class);

EDIT Problem solved. The Routine class had no default constructor. Putting @JsonProperty("name") on the ctr parameter and using gensons previous configuration solved the problem.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top