8

我继承了一些使用 Gson 将我们的应用程序状态保存为 JSON 的代码,然后使用fromJson读取它。

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

正在保存的字段之一是Location。不幸的是,由于我保存的位置在其 mExtras 中包含一个 mClassLoader,并且 Gson 库无法创建该 ClassLoader 并出现此错误,因此该保存数据的解析偶尔会失败:

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

有谁知道为什么 ClassLoader 被包含在我的位置的附加内容中,以及它是否应该以 JSON 表示形式结束?

我假设我可以通过单独保存 Location 对象中的关键字段(例如,经度、纬度、高度、时间、准确性)来解决此问题,但如果可能的话,最好保存 Location 对象。

我看到有一个ExclusionStrategy对象我可以用来排除字段,但我不确定我是否可以/应该使用它来排除我位置内部的额外内容......

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

{
    <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 包含的示例:

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

3 回答 3

23

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

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

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

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并注册类:

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

那应该很照顾它。

于 2012-12-21T22:19:33.630 回答
2

考虑创建一个自定义对象来模拟您的 GSON,解析每个对象的内容对象和每个字段的字段

就像是

JSONObject lastKnownLocation = obj.getJSONObject("lastKnownLocation");
JSONArray mResults = lastKnownLocation.getJSONArray("mResults");

etc...
MyGSON mg=new MyGSON(lastKnownLocation, mResults etc....);

因此,您可以获得对解析的完全控制,并在关键的 mExtra 部分添加 try\catch 块,您可以轻松地排除该块,或根据需要管理异常。

于 2012-12-23T01:27:22.877 回答
0

我想有更简单的方法,但可能是错误的。

您可以通过以下方式删除有问题的 Extras:

myClass.loc。setExtras(null) ;

  • 其中myClass.locLocation

当我保存位置时它确实有效:

initPrefs(); 
mPrefs.edit().putFloat(PARAM_DISTANCE, mOdometer.getDistance()).apply();
Location loc = mOdometer.getOrigLocation(); 
loc.setExtras(null); 
Gson gson = new Gson(); 
String json = gson.toJson(loc); 
mPrefs.edit().putString(PARAM_ORIG_LOCATION, json).apply();

没有它,我在阅读Location时遇到了与您相同的错误。

于 2020-01-30T19:20:10.327 回答