Guruprasad J Rao
Guruprasad J Rao

Reputation: 29683

Unable to cast class data stored in SharedPreferences using Gson

I am having a generalized static function defined in AppController.java which implements Application class. This static function does a job of storing and retrieving serialized class data to and from shared preferences.

AppController.java

private static GsonBuilder gsonBuilder;
@Override
public void onCreate() {
    super.onCreate();
    gsonBuilder= new GsonBuilder();
}

public static void saveObjectToSharedPreferences(Context mContext,String key, Object value){
    if(mContext!=null){
        SharedPreferences mSharedPreferences=mContext.getSharedPreferences(SHARED_PREFS,MODE_PRIVATE);
        if(mSharedPreferences!=null) {
            Gson gson=gsonBuilder.excludeFieldsWithoutExposeAnnotation().create();
            String storableValue=gson.toJson(value,value.getClass());
            mSharedPreferences.edit().putString(key,storableValue).apply();
        }
    }
}

public static <T> Object readObjectFromSharedPreferences(Context mContext,String key, Class<T> converter ){
    if(mContext!=null){
        SharedPreferences mSharedPreferences = mContext.getSharedPreferences(SHARED_PREFS, MODE_PRIVATE);
        if(mSharedPreferences!=null){
            Gson gson=gsonBuilder.excludeFieldsWithoutExposeAnnotation().create();
            String retrievedValue=mSharedPreferences.getString(key,null);
            if(retrievedValue!=null){
                return gson.fromJson(retrievedValue,converter.getClass());
            }
        }
    }
    return null;
}

I used to call this static functions as below:

AppController.saveObjectToSharedPreferences(getContext(), String.valueOf("UserData"), userDetailsObj);

My UserDetails class is as below:

public class UserDetails implements Serializable{
    @Expose
    private String Name;
    @Expose
    private String UserGroup;

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }

    public String getUserGroup() {
        return UserGroup;
    }

    public void setUserGroup(String userGroup) {
        UserGroup = userGroup;
    }
}

saveObjectToSharedPreferences was successfully saving the userdetails object into SharedPreferences in the format {'Name':'somename','UserGroup':'somegroup'} but I was getting Attempted to deserialize java.lang.Class. Forgot to register a type adapter?, when I tried to retrieve it using readObjectFromSharedPreferences function in gson.fromJson line. When I searched for this issue throughout, I got to know that we need to specifically write our own TypeAdapter for class and with the help of this answer here I implemented the said Adapters and wrote gsonBuilder.registerTypeAdapterFactory(new ClassTypeAdapterFactory()); during onCreate of AppController class.

public class ClassTypeAdapterFactory implements TypeAdapterFactory {
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
        if(!Class.class.isAssignableFrom(typeToken.getRawType())) {
            return null;
        }
        return (TypeAdapter<T>) new ClassTypeAdapter();
    }
}

Now I've started getting Method threw 'com.google.gson.JsonSyntaxException' exception. and under detailed message java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 2 path $.

I am totally blank at this point of time. Could someone please guide me in the right path to make this work?

Upvotes: 1

Views: 115

Answers (1)

Egor Neliuba
Egor Neliuba

Reputation: 15064

In readObjectFromSharedPreferences you are passing Class<T> converter and when you are calling converter.getClass() it returns Class and not T. Just remove the getClass() call like this:

return gson.fromJson(retrievedValue, converter);

Also, a nice way to improve this method is to make it return T instead of Object. This way you won't have to cast anything:

public static <T> T readObjectFromSharedPreferences(...)

Upvotes: 2

Related Questions