Gson is crashing with Failed to invoke protected java.text.NumberFormat() with no args error

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

  •  26-06-2023
  •  | 
  •  

Question

I want to use gson to store and retrieve Event objects. Gson seems to handle converting to json correctly but it's crashing on the gson.fromJson() method. I am not sure how to proceed.

public static void putValue(Context ctx, Event event){
        //get preferences
        SharedPreferences prefs = PreferenceManager
                .getDefaultSharedPreferences(ctx);
        Gson gson = new Gson();
        String json = gson.toJson(event);       
        Log.i(TAG, "saving "+EVENT_KEY +Integer.toString(event.getId()));
        Editor editor = prefs.edit();
        editor.putString(EVENT_KEY + Integer.toString(event.getId()), json);
        editor.commit();
        //testing 
        String json2 = prefs.getString(EVENT_KEY + Integer.toString(event.getId()), null);
        Event savedEvent = gson.fromJson(json2, Event.class);
        if(savedEvent !=null){
            Log.i(TAG, "yup");
        }
        else{
            Log.i(TAG, "nope");
        }
    }

Event class: https://gist.github.com/Janek2004/9950294

Error:

04-03 02:58:54.597: E/AndroidRuntime(18793): FATAL EXCEPTION: main
04-03 02:58:54.597: E/AndroidRuntime(18793): Process: com.itenwired.itenconference, PID: 18793
04-03 02:58:54.597: E/AndroidRuntime(18793): java.lang.RuntimeException: Failed to invoke protected java.text.NumberFormat() with no args
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:107)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:162)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:93)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:172)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:93)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:172)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.google.gson.Gson.fromJson(Gson.java:803)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.google.gson.Gson.fromJson(Gson.java:768)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.google.gson.Gson.fromJson(Gson.java:717)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.google.gson.Gson.fromJson(Gson.java:689)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.itenwired.itenconference.model.MyEventManager.putValue(MyEventManager.java:37)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.itenwired.itenconference.adapter.AgendaAdapter$EventHolder$1.onClick(AgendaAdapter.java:88)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at android.view.View.performClick(View.java:4438)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at android.widget.CompoundButton.performClick(CompoundButton.java:100)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at android.view.View$PerformClick.run(View.java:18422)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at android.os.Handler.handleCallback(Handler.java:733)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at android.os.Handler.dispatchMessage(Handler.java:95)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at android.os.Looper.loop(Looper.java:136)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at android.app.ActivityThread.main(ActivityThread.java:5017)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at java.lang.reflect.Method.invokeNative(Native Method)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at java.lang.reflect.Method.invoke(Method.java:515)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at dalvik.system.NativeStart.main(Native Method)
04-03 02:58:54.597: E/AndroidRuntime(18793): Caused by: java.lang.InstantiationException: can't instantiate class java.text.NumberFormat
04-03 02:58:54.597: E/AndroidRuntime(18793):    at java.lang.reflect.Constructor.constructNative(Native Method)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
04-03 02:58:54.597: E/AndroidRuntime(18793):    at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:104)
04-03 02:58:54.597: E/AndroidRuntime(18793):    ... 23 more
Was it helpful?

Solution 2

As Accollativo and storm143 said, this is a problem with SimpleDateFormat. If you want to keep SimpleDateFormat as an instance variable, you can fix this by using an ExclusionStrategy.

public class GsonDeserializeExclusion implements ExclusionStrategy {

    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getDeclaredClass() == SimpleDateFormat.class;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return false;
    }

}

You can then create a Gson instance with this exclusion using the GsonBuilder.

Gson gson = new GsonBuilder()
        .addDeserializationExclusionStrategy(new GsonDeserializeExclusion())
        .create();

OTHER TIPS

It's a definitely a problem with SimpleDateFormat, as I had the same problem and followed Accollativo's adivce, and that fixed the bug for me. Very weird.

I realized I didn't actually need the SimpleDateFormat as a variable of the class, I instead just put it in the method where needed, so GSON didn't have to store the SimpleDateFormat object. Worked for me!

Another fix for this is to add the transient keyword to the NumberFormatter so gson doesn't try and convert it into the json string. Which is fine since you don't need to save any values just make a new one when the class gets recreated.

For example

private transient NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top