gson.toJson declares multiple JSON fields named XX

Viewed 5161

I have one single custom object of type A and an ArrayList containing custom objects of type B that I want to store in my Shared Preferences with gson. Object A worked without problems but when I try to store the list of object B or even just one instance of B, the following error message occurs:

2019-01-07 13:05:21.610 28295-28295/com.example.aev.quizzle E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.aev.quizzle, PID: 28295
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.aev.quizzle/com.example.aev.quizzle.activities.MapsActivity}: java.lang.IllegalArgumentException: class android.content.res.ColorStateList declares multiple JSON fields named mChangingConfigurations
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3194)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3302)
    at android.app.ActivityThread.-wrap12(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1891)
    at android.os.Handler.dispatchMessage(Handler.java:108)
    at android.os.Looper.loop(Looper.java:166)
    at android.app.ActivityThread.main(ActivityThread.java:7425)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)
 Caused by: java.lang.IllegalArgumentException: class android.content.res.ColorStateList declares multiple JSON fields named mChangingConfigurations
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:172)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
    at com.google.gson.Gson.getAdapter(Gson.java:458)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
    at com.google.gson.Gson.getAdapter(Gson.java:458)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
    at com.google.gson.Gson.getAdapter(Gson.java:458)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:56)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:97)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:61)
    at com.google.gson.Gson.toJson(Gson.java:704)
    at com.google.gson.Gson.toJson(Gson.java:683)
    at com.google.gson.Gson.toJson(Gson.java:638)
    at com.google.gson.Gson.toJson(Gson.java:618)
    at com.example.aev.quizzle.activities.MapsActivity.generateThemes(MapsActivity.java:592)
    at com.example.aev.quizzle.activities.MapsActivity.onCreate(MapsActivity.java:164)
    at android.app.Activity.performCreate(Activity.java:7383)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1218)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3147)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3302) 
    at android.app.ActivityThread.-wrap12(Unknown Source:0) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1891) 
    at android.os.Handler.dispatchMessage(Handler.java:108) 
    at android.os.Looper.loop(Looper.java:166) 
    at android.app.ActivityThread.main(ActivityThread.java:7425) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921) 

I store the Array List like this:

themes = new ArrayList<>();
themes.add(new Theme(0, this));
themes.add(new Theme(1, this));
themes.add(new Theme(2, this));

String jsonTheme = gson.toJson(themes);
prefsEditor.putString("themes", jsonTheme);
prefsEditor.commit();

And my class Theme looks like this:

public class Theme implements Parcelable {
    public ImageView icon;
    public int themeID;
    //public Question[] questions = new Question[14];
    public List<Question> questions = new ArrayList<>();
    boolean unlocked;
    Context context;

I have seen similar questions with problems with same variable names in superclasses and objects that should be stored, but in my case I do not extend another class in my Theme class. The error points to the line saying

String jsonTheme = gson.toJson(themes);

Am I treating the gson object wrong or did I miss anything?

1 Answers

Using @Transient is one way to solve this serializing problem. As you might have also noticed after deserializing you need to set these ImageView & Context to each deserialized Theme which might be a small issue.

You could also consider separating your data to be persisted from transient stuff like views & context. Having seen only a small portion of your code your structure could be something like:

Something like:

public class Theme {
    public ImageView icon;
    Context context;
    ThemeData themeData

    public Theme(Context contect, ImageView icon, ThemeData themeData) {
        this.context = context;
        this.icon = icon;
        themeData = themeData;
    }

    public void doSomethingWithThemeDataAndViewAndContext() {
        // whatever you need to do in Theme
    }
}

where ThemeData then contains all the non-transient fields and which you would then persist to SharedPreferences:

public class ThemeData {
    public int themeID;
    //public Question[] questions = new Question[14];
    public List<Question> questions = new ArrayList<>();
    boolean unlocked;
}

Note also: I think that if you serialize theme(s) with GSON and save it as a JSON String in SharedPreferences you do not need to implement Parcelable so I removed it.

Related