我继承了一些代码,该代码使用Gson将应用程序状态保存为JSON,然后使用fromJson读取。
Gson gson = createGson();
gson.fromJson(objString, myClass);
要保存的字段之一是Location。不幸的是,由于保存的位置在其mExtras中包含一个mClassLoader,并且Gson库无法创建此错误的ClassLoader,因此有时无法解析该保存的数据:
RuntimeException:无法调用没有参数的受保护的java.lang.ClassLoader()
有人知道为什么将ClassLoader包含在我的Location的附加功能中,以及它是否应该以JSON表示形式结束?
[我假设我可以通过仅保存位置对象中的关键字段(例如,经度,纬度,高度,时间,准确性)来解决此问题,但如果可能的话,最好保存位置对象。
[我看到有一个ExclusionStrategy对象可以用来排除字段,但是我不确定是否可以/应该使用该对象来排除位置中的多余对象...
FYI,这是我的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
}
问题是您试图将系统提供的类(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,然后在Deserializer中创建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();
...
几乎应该照顾它。
考虑创建一个为您的GSON建模的自定义对象,解析每个对象的内容对象和每个字段的字段
类似
JSONObject lastKnownLocation = obj.getJSONObject("lastKnownLocation");
JSONArray mResults = lastKnownLocation.getJSONArray("mResults");
etc...
MyGSON mg=new MyGSON(lastKnownLocation, mResults etc....);
因此,您可以完全控制解析,并在关键的mExtra部分中添加try \ catch块,可以轻松地排除该块或根据需要管理异常。
我想有一种更简单的方法,但可能是错误的。
您可以通过以下方式删除有问题的附加功能:
myClass.loc。setExtras(null);
当我保存位置时它确实起作用:
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时。