Reputation: 31
I'm using Gson successfully to place json into an object. It works like a charm on devices with android 2.2 (emulator and real device), when I deploy to android 4.0 and above (emulator and device) I get this very weird exception.
I've confirmed that there is no problem with json string because the same code runs happily on older devices.
The exception is definitely being thrown here:
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
return gson.fromJson(jsonString, t);
in the fromJson method.
Any ideas?
Json String: (had to remove the http:// from the urls in the json)
{ "session_id" : "a89d8cd07e356", "shoutout_items" : [ { "attachment_url" : "xxxxxx.mobi/pic.php?id=478ba67a44d", "attachment_url_full_size" : "xxxxxx.mobi/pic.php?id=01810a5e9f6e7065cd4", "expires_at" : 1363264081, "have_attachment" : true, "message_text" : "Hi", "partner" : { "country_code" : "za", "gender" : "male", "nickname" : "nick", "profile_pic_full_size_url" : "xxxxxx.mobi/pic.php?id=810a5e9f6e7065cd43629f1", "profile_pic_url" : "xxxxxx.mobi/pic.php?id=23ca67a44d23", "profile_summary" : "20, DBN" }, "shoutout_id" : 31170, "type" : "shoutout" }, { "attachment_url" : null, "attachment_url_full_size" : null, "expires_at" : 1363264081, "have_attachment" : false, "message_text" : "hello", "partner" : { "country_code" : "za", "gender" : "male", "nickname" : "mark", "profile_pic_full_size_url" : "xxxxxx.mobi/pic.php?id=2db9e7f86b9bf7ca", "profile_pic_url" : "xxxxxx.mobi/pic.php?id=b110191f1afac", "profile_summary" : "40, DBN" }, "shoutout_id" : 31322, "type" : "shoutout" } ] }
Stacktrace:
03-14 14:56:02.200: E/AndroidRuntime(19588): FATAL EXCEPTION: main
03-14 14:56:02.200: E/AndroidRuntime(19588): java.lang.RuntimeException: Unable to start activity ComponentInfo{mobi.smiggle.android/mobi.smiggle.android.MainFragmentActivity}: java.lang.IllegalArgumentException: class android.text.BoringLayout declares multiple JSON fields named m_paint
03-14 14:56:02.200: E/AndroidRuntime(19588): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1968)
03-14 14:56:02.200: E/AndroidRuntime(19588): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1993)
03-14 14:56:02.200: E/AndroidRuntime(19588): at android.app.ActivityThread.access$600(ActivityThread.java:127)
03-14 14:56:02.200: E/AndroidRuntime(19588): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1159)
03-14 14:56:02.200: E/AndroidRuntime(19588): at android.os.Handler.dispatchMessage(Handler.java:99)
03-14 14:56:02.200: E/AndroidRuntime(19588): at android.os.Looper.loop(Looper.java:137)
03-14 14:56:02.200: E/AndroidRuntime(19588): at android.app.ActivityThread.main(ActivityThread.java:4507)
03-14 14:56:02.200: E/AndroidRuntime(19588): at java.lang.reflect.Method.invokeNative(Native Method)
03-14 14:56:02.200: E/AndroidRuntime(19588): at java.lang.reflect.Method.invoke(Method.java:511)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
03-14 14:56:02.200: E/AndroidRuntime(19588): at dalvik.system.NativeStart.main(Native Method)
03-14 14:56:02.200: E/AndroidRuntime(19588): Caused by: java.lang.IllegalArgumentException: class android.text.BoringLayout declares multiple JSON fields named m_paint
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:122)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:72)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.Gson.getAdapter(Gson.java:353)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:82)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:81)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:118)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:72)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.Gson.getAdapter(Gson.java:353)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:82)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:81)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:118)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:72)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.Gson.getAdapter(Gson.java:353)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:82)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:81)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:118)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:72)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.Gson.getAdapter(Gson.java:353)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:82)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:81)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:118)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:72)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.Gson.getAdapter(Gson.java:353)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:82)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:81)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:118)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:72)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.Gson.getAdapter(Gson.java:353)
03-14 14:56:02.200: E/AndroidRuntime(19588): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:
Upvotes: 3
Views: 1781
Reputation: 637
I've found, that if your instance t extends from any android view component(such as Button, for example) or has field of class, that extends from any android view component, you will get such exception
For some reason, this library can't serialize view components any more. So, you can add exclude strategy. For example, this strategy will exclude all fields, except fields with Annotation @SerializedName:
class Exclude implements ExclusionStrategy {
@Override
public boolean shouldSkipClass(Class<?> arg0) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean shouldSkipField(FieldAttributes field) {
SerializedName sn = field.getAnnotation(SerializedName.class);
if(sn != null)
return false;
return true;
}}
Suppose we have sample Json:
private final String jsonSample= "{ \"Sample\": { \"field1\":1, \"field2\":2}}";
here is sample code:
private void parseJson(){
Exclude ex = new Exclude();
Gson gson = new GsonBuilder().create();
GsonObject gObject = gson.fromJson(jsonSample, GsonObject.class);
}
class GsonObject{
@SerializedName("Sample")
public Smpl smpl;
// private Button btn; <-- Uncomment this line, and you will get your error!
class Smpl{
@SerializedName("field1")
int fl1;
@SerializedName("field2")
int fl2;
}
}
But after adding exclude strategy I've written above:
Exclude ex = new Exclude();
Gson gson = new GsonBuilder().addDeserializationExclusionStrategy(ex).addSerializationExclusionStrategy(ex).create();
All works correct.
Finally we has the following test app:
public class MainActivity extends Activity {
private final String jsonSample= "{ \"Sample\": { \"field1\":1, \"field2\":2}}";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
parseJson();
}
private void parseJson(){
Exclude ex = new Exclude();
// Gson gson = new GsonBuilder().create(); <-- without EX strategy it will try to serrialaze Button field in our GsonObject, and throws an exeption
Gson gson = new GsonBuilder().addDeserializationExclusionStrategy(ex).addSerializationExclusionStrategy(ex).create();
GsonObject gObject = gson.fromJson(jsonSample, GsonObject.class);
Toast.makeText(this, "Gson" + gObject.smpl.fl1 + " " + gObject.smpl.fl2, Toast.LENGTH_LONG).show();
}
class GsonObject{
@SerializedName("Sample")
public Smpl smpl;
private Button btn; // <-- this field is our reason of this strange exception on Gson serialization
class Smpl{
@SerializedName("field1")
int fl1;
@SerializedName("field2")
int fl2;
}
}
}
class Exclude implements ExclusionStrategy {
@Override
public boolean shouldSkipClass(Class<?> arg0) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean shouldSkipField(FieldAttributes field) {
SerializedName ns = field.getAnnotation(SerializedName.class);
if(ns != null)
return false;
return true;
}
}
p.s. Sorry for my English)
Upvotes: 2