Gson解析JSON中的RuntimeException:无法调用没有参数的受保护的java.lang.ClassLoader() [英] RuntimeException in Gson parsing JSON: Failed to invoke protected java.lang.ClassLoader() with no args

查看:350
本文介绍了Gson解析JSON中的RuntimeException:无法调用没有参数的受保护的java.lang.ClassLoader()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我继承了一些代码,该代码使用Gson将应用程序状态保存为JSON,然后使用

I've inherited some code that saves our application state as JSON using Gson, and then reads it using fromJson.

Gson gson = createGson();
gson.fromJson(objString, myClass);

要保存的字段之一是位置.不幸的是,由于保存的位置在其mExtras中包含一个mClassLoader,并且Gson库无法创建具有以下错误的ClassLoader,因此有时无法解析该保存的数据:

One of the fields being saved is a Location. Unfortunately, very occasionally the parsing of that saved data fails because my saved Location includes an mClassLoader in its mExtras, and the Gson library fails to create the ClassLoader with this error:

RuntimeException:无法调用没有参数的受保护的java.lang.ClassLoader()

RuntimeException: Failed to invoke protected java.lang.ClassLoader() with no args

有人知道为什么ClassLoader包含在我的Location的附加功能中吗,以及是否应该以JSON表示形式结束?

Does anybody know why a ClassLoader is being included in the extras for my Location, and whether it should be ending up in the JSON representation?

我假设我可以通过仅保存位置对象中的关键字段(例如,经度,纬度,高度,时间,准确性)来解决此问题,但如果可能的话,最好将位置对象保存下来.

I'm assuming I can fix this by just saving the key fields from the Location object individually (e.g. longitude, latitude, altitude, time, accuracy), but it would be nice to save out the Location object if possible.

我看到有一个 ExclusionStrategy 我可以用来排除字段的对象,但是我不确定是否可以/应该从我的位置中排除多余的对象...

I saw there is an ExclusionStrategy object I could use to exclude fields, but I wasn't sure if I could/should use that to exclude the the extras from inside my Location...

仅供参考,这是我的Location对象的JSON数据(经度和纬度已更改为隐藏我):

FYI, here's the JSON data for my Location object (with the longitude and latitude changed to hide me):

{
    <snip>
    "lastKnownLocation": {
        "mResults": [
            0,
            0
        ],
        "mProvider": "gps",
        "mExtras": {
            "mParcelledData": {
                "mOwnObject": 1,
                "mObject": 5525040
            },
            "mClassLoader": {
                "packages": {}
            },
            "mMap": {},
            "mHasFds": false,
            "mFdsKnown": true,
            "mAllowFds": true
        },
        "mDistance": 0,
        "mTime": 1354658984849,
        "mAltitude": 5.199999809265137,
        "mLongitude": -122.4376,
        "mLon2": 0,
        "mLon1": 0,
        "mLatitude": 37.7577,
        "mLat1": 0,
        "mLat2": 0,
        "mInitialBearing": 0,
        "mHasSpeed": true,
        "mHasBearing": false,
        "mHasAltitude": true,
        "mHasAccuracy": true,
        "mAccuracy": 16,
        "mSpeed": 0,
        "mBearing": 0
    },
    <snip>
}

下面是一个示例,当代码不崩溃时,mExtras包含的内容:

Here's an example what the mExtras contains when the code doesn't crash:

"mExtras": {
    "mParcelledData": {
        "mOwnsNativeParcelObject": true,
        "mNativePtr": 1544474480
    },
    "mHasFds": false,
    "mFdsKnown": true,
    "mAllowFds": true
}

推荐答案

问题是您试图将系统提供的类(Location)直接转换为JSON.而且,如您所见,序列化内部状态/特定于Java的东西时会遇到问题. JSON是一种传递信息的半通用方式.

The problem is you're attempting to just straight convert a system-provided class (Location) to JSON. And, as you see you run into problems with serializing internal state / Java specific things. JSON is meant as a semi-generic way to pass information around.

您不能轻易使用@Expose注释,因为它不是您的课程;这需要修改Location的源代码,或者通过相当广泛的过程在运行时使用 jassist (请参阅: http://ayoubelabbassi .blogspot.com/2011/01/how-to-add-annotations-at-runtime-to.html )

You can't use the @Expose annotation easily because it's not your class; that would require modifying the source code for Location or via a fairly extensive process of adding them at runtime using jassist (see: http://ayoubelabbassi.blogspot.com/2011/01/how-to-add-annotations-at-runtime-to.html)

看看Location类,我只需要创建一个自定义的Gson序列化器和反序列化器并完成它即可.您真正感兴趣的是GPS数据,而不是课程本身的内部数据.您只需使用getters在序列化器中构建包含所需信息的JSON,然后在Deserializer中创建Location的新实例,并使用公共setters用提供的JSON中的信息填充它.

Looking at the Location class, I'd simply create a custom Gson Serializer and Deserializer and be done with it. What you're actually interested in is the GPS data, not internals of the class itself. You just construct the JSON containing the information you need in the serializer using the getters, then in the Deserializer you create a new instance of Location and populate it with the information from the supplied JSON using the public setters.

class LocationSerializer implements JsonSerializer<Location>
{
    public JsonElement serialize(Location t, Type type, 
                                 JsonSerializationContext jsc)
    {
        JsonObject jo = new JsonObject();
        jo.addProperty("mProvider", t.getProvider());
        jo.addProperty("mAccuracy", t.getAccuracy());
        // etc for all the publicly available getters
        // for the information you're interested in
        // ...
        return jo;
    }

}

class LocationDeserializer implements JsonDeserializer<Location>
{
    public Location deserialize(JsonElement je, Type type, 
                                JsonDeserializationContext jdc)
                           throws JsonParseException
    {
        JsonObject jo = je.getAsJsonObject();
        Location l = new Location(jo.getAsJsonPrimitive("mProvider").getAsString());
        l.setAccuracy(jo.getAsJsonPrimitive("mAccuracy").getAsFloat());
        // etc, getting and setting all the data
        return l;
    }
}

现在在代码中使用GsonBuilder并注册类:

Now in your code you use GsonBuilder and register the classes:

...
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Location.class, new LocationDeserializer());
gsonBuilder.registerTypeAdapter(Location.class, new LocationSerializer());
Gson gson = gsonBuilder.create(); 
...

那应该好好照顾它.

这篇关于Gson解析JSON中的RuntimeException:无法调用没有参数的受保护的java.lang.ClassLoader()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆