【问题标题】:google gson LinkedTreeMap class cast to myclass谷歌 gson LinkedTreeMap 类转换为 myclass
【发布时间】:2015-12-03 09:00:09
【问题描述】:

我知道以前有人问过这个问题。由于我在java和android方面的新手技能。我无法解决这个问题超过一个星期。

我和我的一个朋友正在开发一个 android 项目,是否有一些这样的事情。

这件事最奇怪的部分是,它只发生在我从 Google Play 商店下载并测试它时。不是来自本地 android studio 安装或调试模式。

这可能是什么问题,或者这个返回列表是完全错误的? 我的朋友说服该代码正确返回,但从 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 无法转换为 com.gaurage.dto.DoServiceDto 在 com.gaurage.user.User_Test_Main.promiseMethod(未知来源)

【问题讨论】:

  • 一个多星期以来的奇怪问题......它适用于本地安装而不是来自 Play 商店安装
  • @CodeSpy 顺便说一句,感谢您提供了很好的答案和方法,但建议使用 TypeToken 而不是手动按名称获取 LinkedMapTree 对象

标签: java android gson


【解决方案1】:

对泛型类型进行序列化和反序列化

当你调用 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

上述代码无法将 value 解释为类型 Bar,因为 Gson 调用 list.getClass() 来获取其类信息,但此方法返回一个原始类 Foo.class。这意味着 Gson 无法知道这是 Foo 类型的对象,而不仅仅是普通的 Foo。

您可以通过为泛型类型指定正确的参数化类型来解决此问题。您可以通过使用 TypeToken 类来做到这一点。

Type fooType = new TypeToken<Foo<Bar>>() {}.getType();    
gson.toJson(foo, fooType);
gson.fromJson(json, fooType);

我有 Parent 类,它是子类,其中一些包含 List 类型。像这个父类一样,我有 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 转换为 myclass。

我很难在本地测试中重现相同的结果(包括调试模式)。

【讨论】:

  • 使用proguard时重现(minifyEnabled true)
  • @Log.d 谢谢,这对我有用。我花了 6 个小时才意识到这个问题并看到了您的帖子。
  • @Saidolim 在您的回答中 object.get(DO_SERVICES) 是什么意思? JSONObject jsonObj = new JSONObject(object.get(DO_SERVICES).toString());
  • @Krishna 我不知道你指的是谁。但是 Do_service 是来自 rest api 的字符串。自从我转向休眠以来,这是一种旧方法。
【解决方案2】:

Source

在我的 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: 致命异常: main 进程:com.hsa.ffgp.hapdfgdfgoon,PID:25879 java.lang.ClassCastException:com.google.gson.internal.LinkedTreeMap 无法转换为 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;
    }
...
...

【讨论】:

    【解决方案3】:

    在我的情况下,从共享首选项中获取对象列表时发生错误。 通过添加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);
    }
    

    ....

    【讨论】:

      【解决方案4】:

      EngineSense 的回答是正确的。
      但是,如果您仍想使用泛型并且不想将具体的类类型作为参数传递,这里有一个 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()
      }
      

      【讨论】:

        【解决方案5】:
        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);
        

        【讨论】:

          猜你喜欢
          • 2016-10-29
          • 2015-03-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多