RuntimeException in Gson parsing JSON: Failed to invoke protected java.lang.ClassLoader() with no args

℡╲_俬逩灬. 提交于 2019-12-09 17:35:09

问题


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);

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: Failed to invoke protected java.lang.ClassLoader() with no args

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.

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...

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>
}

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
}

回答1:


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.

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)

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;
    }
}

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(); 
...

That should pretty much take care of it.




回答2:


Consider to create a custom Object that models your GSON, parsing the content Object per Object and field per field

something like

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

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

So you can obtain the full control of the parsing, and adding a try\catch block in the critical mExtra part you can exclude the block, or manage the exception as you want, easily.



来源:https://stackoverflow.com/questions/13944346/runtimeexception-in-gson-parsing-json-failed-to-invoke-protected-java-lang-clas

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!