google gson LinkedTreeMap class 投射到我的class
google gson LinkedTreeMap class cast to myclass
我知道以前有人问过这个问题。由于我在 java 和 android 方面的新手技能。我不能解决这个问题超过一个星期。
我和我的一个朋友正在开发一个 android 项目,其中有一些是这样的。
这件事最奇怪的部分是,只有当我从 Google Play 商店下载并测试它时才会发生。不是来自本地 android 工作室安装或调试模式。
这里可能有什么问题,或者这个返回列表完全错误?
我的朋友说服这个代码 returns 正确,但是从 Play 商店安装它总是一个错误。
请建议我应该在哪里继续挖掘?
@Override
public void promiseMethod(JSONObject object) {
if (object != null) {
if (object.has(DO_SERVICES)) {
vehicleDetails = new ArrayList < Object[] > (1);
List < String > vehicleNoList = new ArrayList < String > (1);
List < String > serviceList = new ArrayList < String > (1);
try {
Gson gson = new Gson();
JSONObject jsonObj = new JSONObject(object.get(DO_SERVICES)
.toString());
servDto = gson.fromJson(jsonObj.toString(),
ServiceDto.class);
if (servDto.getServiceDto() instanceof List) {
List < DoServiceDto > doServiceList = servDto.getServiceDto();
例外是
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.gaurage.dto.DoServiceDto
at com.gaurage.user.User_Test_Main.promiseMethod(Unknown Source)
序列化和反序列化泛型类型
当您调用 toJson(obj) 时,Gson 会调用 obj.getClass() 以获取有关要序列化的字段的信息。同样,您通常可以在 fromJson(json, MyClass.class) 方法中传递 MyClass.class 对象。如果对象是非泛型类型,这会很好地工作。但是,如果对象是泛型类型,则泛型类型信息会因 Java 类型擦除而丢失。这是一个说明这一点的例子:
class Foo<T> { T value;}
Gson gson = new Gson();
Foo<Bar> foo = new Foo<Bar>();
gson.toJson(foo); // May not serialize foo.value correctly
gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar
上面的代码无法将值解释为 Bar 类型,因为 Gson 调用 list.getClass() 来获取它的 class 信息,但是这个方法 returns 是一个原始的 class , Foo.class。这意味着 Gson 无法知道这是一个 Foo 类型的对象,而不仅仅是普通的 Foo。
您可以通过为泛型类型指定正确的参数化类型来解决此问题。您可以使用 TypeToken class 来完成此操作。
Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo, fooType);
gson.fromJson(json, fooType);
我有父 class 和它的子 class 其中一些有列表类型。像这位家长 class 我有 30 个文件。我是这样解决的。
Gson gson = new Gson();
JSONObject jsonObj = new JSONObject(object.get(DO_SERVICES).toString());
Type type = new TypeToken<MyDto>() {}.getType();
servDto = gson.fromJson(jsonObj.toString(),type);
最重要的是,我无法在Android studio 的本地测试中重现此错误。这个问题只会弹出,当我生成签名的 apk 并将应用程序发布到 PlayStore 时应用程序停止,并且报告说无法将 LinkedTreeMap 投射到我的 class.
我很难在本地测试(包括调试模式)中重现相同的结果。
在我的 ListView BaseAdapter 中面临同样的问题
JSON 格式 显示
{
results: [
{
id: "10",
phone: "+91783XXXX345",
name: "Mr Example",
email: "freaky@jolly.com"
},
{
id: "11",
phone: "+9178XXXX66",
name: "Mr Foo",
email: "freaky@jolly.com"
}],
statusCode: "1",
count: "2"
}
我遇到了这个问题
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.hsa.ffgp.hapdfgdfgoon, PID: 25879
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to
com.hsa.......
然后我使用 LinkedTreeMap 键值映射数据如下
...
...
@Override
public View getView(final int i, View view, ViewGroup viewGroup) {
if(view==null)
{
view= LayoutInflater.from(c).inflate(R.layout.listview_manage_clients,viewGroup,false);
}
TextView mUserName = (TextView) view.findViewById(R.id.userName);
TextView mUserPhone = (TextView) view.findViewById(R.id.userPhone);
Object getrow = this.users.get(i);
LinkedTreeMap<Object,Object> t = (LinkedTreeMap) getrow;
String name = t.get("name").toString();
mUserName.setText("Name is "+name);
mUserPhone.setText("Phone is "+phone);
return view;
}
...
...
在我的案例中,从共享首选项中获取对象列表时发生了错误。
通过添加 TypeToken 解决了错误,如下所示:
public static <GenericClass> GenericClass getListOfObjectsFromSharedPref(Context context,String preferenceFileName, String preferenceKey ){
SharedPreferences sharedPreferences =
context.getSharedPreferences(preferenceFileName, 0);
Type type = new TypeToken<ArrayList<Classname.class>>() {}.getType();
String json = sharedPreferences.getString(preferenceKey, "");
final Gson gson = new Gson();
return gson.fromJson(json, type);
}
.....
EngineSense 的回答是正确的。
但是,如果您仍想使用泛型并且不想将具体的 class 类型作为参数传递,这里有一个 Kotlin 变通方法示例。
(请注意,无法从 Java 调用具有具体化类型参数的内联方法).
可能不是完成任务的最有效方法,但确实有效。
以下在GsonUtil.kt
inline fun <reified T> fromJson(json: String): T? {
return gson.fromJson(json, object : TypeToken<T>() {}.type)
}
fun <T> mapToObject(map: Map<String, Any?>?, type: Class<T>): T? {
if (map == null) return null
val json = gson.toJson(map)
return gson.fromJson(json, type)
}
检索通用对象的轻量级列表的方法。
inline fun <reified T: MyBaseClass> getGenericList(): List<T> {
val json = ...
//Must use map here because the result is a list of LinkedTreeMaps
val list: ArrayList<Map<String, Any?>>? = GsonUtil.fromJson(json)
//handle type erasure
val result = list?.mapNotNull {
GsonUtil.mapToObject(it, T::class.java)
}
return result ?: listOf()
}
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
String json = new Gson().toJson("Your Value");
ArrayList<YourClassName> outputList = new Gson().fromJson("Receive Value", new TypeToken<ArrayList<YourClassName>>() {
}.getType());
Log.d("TAG", outputList.get(0).getName);
我知道以前有人问过这个问题。由于我在 java 和 android 方面的新手技能。我不能解决这个问题超过一个星期。
我和我的一个朋友正在开发一个 android 项目,其中有一些是这样的。
这件事最奇怪的部分是,只有当我从 Google Play 商店下载并测试它时才会发生。不是来自本地 android 工作室安装或调试模式。
这里可能有什么问题,或者这个返回列表完全错误? 我的朋友说服这个代码 returns 正确,但是从 Play 商店安装它总是一个错误。
请建议我应该在哪里继续挖掘?
@Override
public void promiseMethod(JSONObject object) {
if (object != null) {
if (object.has(DO_SERVICES)) {
vehicleDetails = new ArrayList < Object[] > (1);
List < String > vehicleNoList = new ArrayList < String > (1);
List < String > serviceList = new ArrayList < String > (1);
try {
Gson gson = new Gson();
JSONObject jsonObj = new JSONObject(object.get(DO_SERVICES)
.toString());
servDto = gson.fromJson(jsonObj.toString(),
ServiceDto.class);
if (servDto.getServiceDto() instanceof List) {
List < DoServiceDto > doServiceList = servDto.getServiceDto();
例外是
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.gaurage.dto.DoServiceDto at com.gaurage.user.User_Test_Main.promiseMethod(Unknown Source)
序列化和反序列化泛型类型
当您调用 toJson(obj) 时,Gson 会调用 obj.getClass() 以获取有关要序列化的字段的信息。同样,您通常可以在 fromJson(json, MyClass.class) 方法中传递 MyClass.class 对象。如果对象是非泛型类型,这会很好地工作。但是,如果对象是泛型类型,则泛型类型信息会因 Java 类型擦除而丢失。这是一个说明这一点的例子:
class Foo<T> { T value;}
Gson gson = new Gson();
Foo<Bar> foo = new Foo<Bar>();
gson.toJson(foo); // May not serialize foo.value correctly
gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar
上面的代码无法将值解释为 Bar 类型,因为 Gson 调用 list.getClass() 来获取它的 class 信息,但是这个方法 returns 是一个原始的 class , Foo.class。这意味着 Gson 无法知道这是一个 Foo 类型的对象,而不仅仅是普通的 Foo。
您可以通过为泛型类型指定正确的参数化类型来解决此问题。您可以使用 TypeToken class 来完成此操作。
Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo, fooType);
gson.fromJson(json, fooType);
我有父 class 和它的子 class 其中一些有列表类型。像这位家长 class 我有 30 个文件。我是这样解决的。
Gson gson = new Gson();
JSONObject jsonObj = new JSONObject(object.get(DO_SERVICES).toString());
Type type = new TypeToken<MyDto>() {}.getType();
servDto = gson.fromJson(jsonObj.toString(),type);
最重要的是,我无法在Android studio 的本地测试中重现此错误。这个问题只会弹出,当我生成签名的 apk 并将应用程序发布到 PlayStore 时应用程序停止,并且报告说无法将 LinkedTreeMap 投射到我的 class.
我很难在本地测试(包括调试模式)中重现相同的结果。
在我的 ListView BaseAdapter 中面临同样的问题
JSON 格式 显示
{
results: [
{
id: "10",
phone: "+91783XXXX345",
name: "Mr Example",
email: "freaky@jolly.com"
},
{
id: "11",
phone: "+9178XXXX66",
name: "Mr Foo",
email: "freaky@jolly.com"
}],
statusCode: "1",
count: "2"
}
我遇到了这个问题
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.hsa.ffgp.hapdfgdfgoon, PID: 25879 java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.hsa.......
然后我使用 LinkedTreeMap 键值映射数据如下
...
...
@Override
public View getView(final int i, View view, ViewGroup viewGroup) {
if(view==null)
{
view= LayoutInflater.from(c).inflate(R.layout.listview_manage_clients,viewGroup,false);
}
TextView mUserName = (TextView) view.findViewById(R.id.userName);
TextView mUserPhone = (TextView) view.findViewById(R.id.userPhone);
Object getrow = this.users.get(i);
LinkedTreeMap<Object,Object> t = (LinkedTreeMap) getrow;
String name = t.get("name").toString();
mUserName.setText("Name is "+name);
mUserPhone.setText("Phone is "+phone);
return view;
}
...
...
在我的案例中,从共享首选项中获取对象列表时发生了错误。 通过添加 TypeToken 解决了错误,如下所示:
public static <GenericClass> GenericClass getListOfObjectsFromSharedPref(Context context,String preferenceFileName, String preferenceKey ){
SharedPreferences sharedPreferences =
context.getSharedPreferences(preferenceFileName, 0);
Type type = new TypeToken<ArrayList<Classname.class>>() {}.getType();
String json = sharedPreferences.getString(preferenceKey, "");
final Gson gson = new Gson();
return gson.fromJson(json, type);
}
.....
EngineSense 的回答是正确的。
但是,如果您仍想使用泛型并且不想将具体的 class 类型作为参数传递,这里有一个 Kotlin 变通方法示例。
(请注意,无法从 Java 调用具有具体化类型参数的内联方法).
可能不是完成任务的最有效方法,但确实有效。
以下在GsonUtil.kt
inline fun <reified T> fromJson(json: String): T? {
return gson.fromJson(json, object : TypeToken<T>() {}.type)
}
fun <T> mapToObject(map: Map<String, Any?>?, type: Class<T>): T? {
if (map == null) return null
val json = gson.toJson(map)
return gson.fromJson(json, type)
}
检索通用对象的轻量级列表的方法。
inline fun <reified T: MyBaseClass> getGenericList(): List<T> {
val json = ...
//Must use map here because the result is a list of LinkedTreeMaps
val list: ArrayList<Map<String, Any?>>? = GsonUtil.fromJson(json)
//handle type erasure
val result = list?.mapNotNull {
GsonUtil.mapToObject(it, T::class.java)
}
return result ?: listOf()
}
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
String json = new Gson().toJson("Your Value");
ArrayList<YourClassName> outputList = new Gson().fromJson("Receive Value", new TypeToken<ArrayList<YourClassName>>() {
}.getType());
Log.d("TAG", outputList.get(0).getName);