Code Monkey home page Code Monkey logo

gsonfactory's Introduction

Gson 解析容错框架

集成步骤

  • 如果你的项目 Gradle 配置是在 7.0 以下,需要在 build.gradle 文件中加入
allprojects {
    repositories {
        // JitPack 远程仓库:https://jitpack.io
        maven { url 'https://jitpack.io' }
    }
}
  • 如果你的 Gradle 配置是 7.0 及以上,则需要在 settings.gradle 文件中加入
dependencyResolutionManagement {
    repositories {
        // JitPack 远程仓库:https://jitpack.io
        maven { url 'https://jitpack.io' }
    }
}
  • 配置完远程仓库后,在项目 app 模块下的 build.gradle 文件中加入远程依赖
android {
    // 支持 JDK 1.8
    compileOptions {
        targetCompatibility JavaVersion.VERSION_1_8
        sourceCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    // Gson 解析容错:https://github.com/getActivity/GsonFactory
    implementation 'com.github.getActivity:GsonFactory:9.6'
    // Json 解析框架:https://github.com/google/gson
    implementation 'com.google.code.gson:gson:2.10.1'
    // Kotlin 反射库:用于反射 Kotlin data class 类对象,1.5.10 请修改成当前项目 Kotlin 的版本号
    implementation 'org.jetbrains.kotlin:kotlin-reflect:1.5.10'
}
  • 需要注意两点:

    • 当前项目必须要有 Kotlin 环境,否则会编译不通过

    • Gson 框架必须使用 2.9.0 及以上版本,否则将会出现版本兼容问题

使用文档

  • 请使用框架返回的 Gson 对象来代替项目中的 Gson 对象
// 获取单例的 Gson 对象(已处理容错)
Gson gson = GsonFactory.getSingletonGson();
  • 因为框架中的 Gson 对象已经对解析规则进行了容错处理

其他 API

// 设置自定义的 Gson 对象
GsonFactory.setSingletonGson(Gson gson);

// 创建一个 Gson 构建器(已处理容错)
GsonBuilder gsonBuilder = GsonFactory.newGsonBuilder();

// 注册类型适配器
GsonFactory.registerTypeAdapterFactory(TypeAdapterFactory factory);

// 注册构造函数创建器
GsonFactory.registerInstanceCreator(Type type, InstanceCreator<?> creator);

// 添加反射访问过滤器
GsonFactory.addReflectionAccessFilter(ReflectionAccessFilter filter);

// 设置 Json 解析容错回调对象
GsonFactory.setParseExceptionCallback(ParseExceptionCallback callback);

框架混淆规则

  • 在混淆规则文件 proguard-rules.pro 中加入
-keep class com.hjq.gson.factory.** {*;}
  • 另外还需要注意不要混淆 kotlin class data 的 bean 类,否则会导致反射 kotlin data class 构造函数出现 ClassNotFoundException 异常,详情请看 issues/43

不同 Json 解析框架之间的对比

功能或细节 GsonFactory Gson moshi FastJson
对应版本 9.6 1.30.6 1.5.0 2.0.28
issues 数
框架体积 60 KB + 283 KB 283 KB 162 KB 188 KB
框架维护状态 维护中 维护中 维护中 停止维护
解析错误类型数据时是否能不报错
解析到错误类型数据时是否能往下解析其他字段
解析错误类型数据时是否能对数据进行智能转换
适配 kotlin data class 字段上的默认值
适配 kotlin data class 非空无默认值字段
是否有跳过解析 Json 中的 null 值(避免空指针)
是否支持解析 org.json.JSONObject 类型
是否支持解析 org.json.JSONArray 类型

数据类型容错介绍

  • 目前支持容错的数据类型有:

    • Bean 类

    • 数组集合

    • Map 集合

    • JSONArray

    • JSONObject

    • String(字符串)

    • boolean / Boolean(布尔值)

    • int / Integer(整数,属于数值类)

    • long / Long(长整数,属于数值类)

    • float / Float(单精度浮点数,属于数值类)

    • double / Double(双精度浮点数,属于数值类)

    • BigDecimal(精度更高的浮点数,属于数值类)

  • 基本涵盖 99.99% 的开发场景,可以运行 Demo 中的单元测试用例来查看效果:

数据类型 容错的范围 数据示例
bean 集合、字符串、布尔值、数值 []""false0
集合 bean、字符串、布尔值、数值 {}""false0
字符串 bean、集合、布尔值、数值 {}[]false0
布尔值 bean、集合、字符串、数值 {}[]""0
数值 bean、集合、字符串、布尔值 {}[]""false
  • 大家可能觉得 Gson 解析容错没什么,那是因为我们对 Gson 解析失败的场景没有了解过:

    • 惊吓不断:后台有数据时返回 JsonObject 类型,没数据返回 [],Gson 会直接抛出异常

    • 意想不到:如果客户端定义的是 boolean 类型,但是后台返回的是 0 或者 1,Gson 会直接抛出异常

    • 措手不及:如果客户端定义的是 int 或者 long 类型,但是后台返回的是 float 或者 double 类型,Gson 会直接抛出异常

  • 以上情况框架已经做了容错处理,具体处理的规则如下:

    • 如果后台返回的类型和客户端定义的类型不匹配,框架就跳过解析这个字段,不影响其他字段正常解析

    • 如果客户端定义的是 boolean 类型,但是后台返回整数,框架则将非 0 的数值则赋值为 true,否则为 false

    • 如果客户端定义的是 int 或者 long 类型,但后台返回浮点数,框架就对数值进行直接取整并赋值给字段

适配 kotlin 空值介绍

  • 如果你在 kotlin 中定义了以下内容的 Bean 类
class XxxBean {
    
    val age: Int = 18
}
  • 大家是不是以为在后台返回 { "age" : null }age 字段的值会等于 18 ?我帮大家测试过了,不会等于 18,会等于空。

  • 那么这到底是为什么呢?聊到这个就不得不先说一下 Gson 解析的机制,我们都知道 Gson 在解析一个 Bean 类的时候,会反射创建一个对象出来,但是大家不知道的是,Gson 会根据 Bean 类的字段名去解析 Json 串中对应的值,然后简单粗暴进行反射赋值,你没有听错,简单粗暴,如果后台返回这个 age 字段的值为空,那么 age 就会被赋值为空,但是你又在 Kotlin 中声明了 age 变量不为空,外层一调用,触发 NullPointerException 也是在预料之中。

  • 另外针对 ListMap 类型的对象,后台如果有返回 null 或者错误类型数据的时候,框架也会返回一个不为空但是集合大小为 0 的 List 对象或者 Map 对象,避免在 kotlin 字段上面自定义字段不为空,但是后台返回空的情况导致出现的空指针异常。

  • 框架目前的处理方案是,如果后台没有返回这个字段的值,又或者返回这个值为空,则不会赋值给类的字段,因为 Gson 那样做是不合理的,会导致我在 Kotlin 上面使用 Gson 是有问题,变量不定义成可空,每次用基本数据类型还得去做判空,定义成非空,一用还会触发 NullPointerException,前后夹击,腹背受敌。

适配 kotlin data class 默认值介绍

  • 如果你在 kotlin 中定义了以下内容的 Bean 类
data class DataClassBean(val name: String = "Hello")
  • 如果丢给原生 Gson 解析,最终会得到以下结果
name = null
  • name 字段为什么不等于 Hello ?为什么会等于 null 值呢?这是因为 Gson 默认只初始化了 DataClassBean 类的空参构造函数,框架的解决方案很简单粗暴,直接引入 kotlin 反射库,让它找到 kotlin data class 自动生成的主构造函数,然后反射创建 kotlin 类,这样得到的对象,字段上面的默认值都会被保留,这样就解决了 Gson 反射 kotlin data class 类出现字段默认值不生效的问题,目前框架内部已经处理了该问题,外部使用的人无需额外处理该问题,只需要调用框架进行解析即可。

适配 kotlin data class 非空无默认值字段介绍

  • 如果你在 Kotlin 中定义了以下内容的 Bean 类
data class DataClassBean(var name: String)
  • 如果丢给原生 Gson 解析,无论 Json 是什么值,最终会得到 name 的字段值是空的,而丢给 moshi 解析,则会抛出空指针异常,而 GsonFactory 却能正常解析成 "",为什么三个框架有三种不同的结果,这是因为三种框架反射 kotlin data class 类不同实现方式导致的,具体看下面的介绍

  • Gson:只会反射空参构造函数,即使某个类不存在空参构造函数,也不会反射失败,这是因为 Gson 内部采用了一种特殊的方式来实例化 Class(即使用 sun.misc.Unsafe 类的 allocateInstance(Class<?> clazz) 方法来创建对象,需要注意的是这个方法是被 native 修饰的),所以对象虽然勉强被创建成功了,但是类里面的字段并没有进行初始化,这是 Unsafe 类在创建对象的时候绕过了构造函数进行创建(具体它是怎么做到的,这个不是我们要研究的重点),所以为什么 kotlin data class 类型的字段会为空,原因就在这里。

  • moshi:而 moshi 用到的方案更加聪明了,它依赖了一个 kotlin 反射库,反射 kotlin data class 类的时候,它找到 kotlin data class 的主构造函数,然后进行反射创建,moshi 之所以这么做,是因为这样反射可以保留 kotlin data class 类字段上面的默认值,但是存在一个致命的问题,像 (var name: String) 这种字段是没有默认值的,但是它又没有被标记是可空的,会导致 kotlin 在编译 kotlin data class 类的时候,会对 name 字段例行非空检查(如果为空则抛出 NullPointerException 异常),所以使用此框架的人需要将代码写法修改成这样 (var name: String = ""),否则编译过程不报错,但是一使用 moshi 解析就会报错,我一直认为在 kotlin 类定义 (var name: String) 字段是错误的,你既然没有标记为可空的,那么就应该给它赋值,如果不给它赋值,则应该给它标记为可空的,即 (var name: String?),但是令人奇怪的是,明明这样的写法是错误的,kotlin 语法在检查的时候,还是让它编译通过了,希望 kotlin 官方后续能纠正这一个问题吧。

  • GsonFactory:在 moshi 框架的基础上进行了改良,即上面提到的一个问题,对一些被定义成非空并且没有被赋值的字段,GsonFactory 会给这些字段赋一个默认值,如果这个字段是基本数据类型,就直接赋值成基本数据类型的默认值,如果是对象类型,则反射创建对象,当然 kotlin data class 类型的字段也不例外,会反射创建一个 kotlin data class 类型的对象赋值到字段上面,这样不会出现一解析报 NullPointerException 异常了。

常见疑问解答

Retrofit 怎么替换 Gson?

Retrofit retrofit = new Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create(GsonFactory.getSingletonGson()))
        .build();

如何替换项目中已有的原生 Gson ?

// 替换调用
new Gson()
GsonFactory.getSingletonGson()
// 替换导包
import com.google.gson.Gson
import com.hjq.gson.factory.GsonFactory
// 再手动处理一些没有替换成功的
new GsonBuilder()

有没有必要处理 Json 解析容错?

  • 我觉得非常有必要,因为后台返回的数据结构是什么样我们把控不了,但是有一点是肯定的,我们都不希望它崩,因为一个接口的失败导致整个 App 崩溃退出实属不值得,但是 Gson 很敏感,动不动就崩。

我们后台用的是 Java,有必要处理容错吗?

  • 如果你们的后台用的是 PHP,那我十分推荐你使用这个框架,因为 PHP 返回的数据结构很乱,这块经历过的人都懂,说多了都是泪,没经历过的人怎么说都不懂。

  • 如果你们的后台用的是 Java,那么可以根据实际情况而定,可用可不用,但是最好用,作为一种兜底方案,这样就能防止后台突然某一天不讲码德,例如我现在的公司的后台全是用 Java 开发的,但是 Bugly 还是有上报关于 Gson 解析的异常,下面是通过 GsonFactory.setParseExceptionCallback 采集到的数据,大家可以参考参考:

  • 粗略估算了一下,总共上报了三千万多次错误,影响设备数三百多万,看到这里你还相信 Java 开发的后台不会有数据容错的问题么?事在人为,Java 只是一种开发语言,并不能担保不会有数据容错的问题,如果后续真的出现了这种问题,主要分为两种情况:

    • 如果 iOS 没有做数据容错,那么锅是后台的,这点是毫无疑问的,后台想甩也甩不开

    • 如果 iOS 做了数据容错,那么很可能的处理结果是,后台和 Android 两端的人要被拉出去各挨五十大板:

      • CTO:后台有问题,为什么 iOS 没事,就 Android 有事?

      • Android:iOS 那边做了容错,但是 Android 这边没有做。

      • CTO:你们为什么不做?这种兜底机制本来不应该就得有的吗?

      • Android:我们用了 Gson 框架,它的机制本身就是这样的。

      • CTO:我不管你们用了什么框架,在这点上崩溃了就是你们不对,后台返回错误的数据结构你们不解析就好了,你为什么还崩溃?同样的数据结构咋 iOS 就没有事呢?这个责任应该有你们 Android 一份子。

      • Android:。。。。。。(哑巴吃黄连,有苦说不出)

      • Ps:以上故事纯属虚构,大家看看就好,切勿太过当真。不过有一点是真的,若不想日后扯皮,最好还是要留一手。

使用了这个框架后,我如何知道出现了 Json 错误,从而保证问题不被掩盖?

  • 对于这个问题,解决方案也很简单,使用 GsonFactory.setParseExceptionCallback API,如果后台返回了错误的数据结构,在调试模式下,直接抛出异常即可,开发者可以第一时间得知;而到了线上模式,对这个问题进行上报即可,保证不漏掉任何一个问题(可上传到后台或者 Bugly 错误列表中),示例代码如下:
// 设置 Json 解析容错监听
GsonFactory.setParseExceptionCallback(new ParseExceptionCallback() {

    @Override
    public void onParseObjectException(TypeToken<?> typeToken, String fieldName, JsonToken jsonToken) {
        handlerGsonParseException("解析对象析异常:" + typeToken + "#" + fieldName + ",后台返回的类型为:" + jsonToken);
    }

    @Override
    public void onParseListItemException(TypeToken<?> typeToken, String fieldName, JsonToken listItemJsonToken) {
        handlerGsonParseException("解析 List 异常:" + typeToken + "#" + fieldName + ",后台返回的条目类型为:" + listItemJsonToken);
    }

    @Override
    public void onParseMapItemException(TypeToken<?> typeToken, String fieldName, String mapItemKey, JsonToken mapItemJsonToken) {
        handlerGsonParseException("解析 Map 异常:" + typeToken + "#" + fieldName + ",mapItemKey = " + mapItemKey + ",后台返回的条目类型为:" + mapItemJsonToken);
    }

    private void handlerGsonParseException(String message) {
        if (BuildConfig.DEBUG) {
            throw new IllegalArgumentException(message);
        } else {
            // 上报到 Bugly 错误列表中
            CrashReport.postCatchedException(new IllegalArgumentException(message));
        }
    }
});

作者的其他开源项目

微信公众号:Android轮子哥

Android 技术 Q 群:10047167

如果您觉得我的开源库帮你节省了大量的开发时间,请扫描下方的二维码随意打赏,要是能打赏个 10.24 🐵就太👍了。您的支持将鼓励我继续创作:octocat:点击查看捐赠列表

License

Copyright 2020 Huang JinQun

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

gsonfactory's People

Contributors

880634 avatar getactivity avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

gsonfactory's Issues

[Bug]:开启混淆后,Kotlin的data class 内部类解析失败。

框架版本【必填】

9.6

问题描述【必填】

开启混淆后,Kotlin的data class 内部类解析失败。

复现步骤【必填】

创建一个kotlin 文件
在其中定义多个data class ,并且相互有所引用,使用@SerializedName方法进行注解。
开启混淆,解析对应代码。

是否必现【必填】

项目 targetSdkVersion【必填】

33

出现问题的手机信息【必填】

全部

出现问题的安卓版本【必填】

全部

问题信息的来源渠道【必填】

No response

是部分机型还是所有机型都会出现【必答】

全部

框架最新的版本是否存在这个问题【必答】

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

是否可以通过 Demo 来复现该问题【必答】

提供报错堆栈

2024-04-09 19:18:54.732  6374-16483 System.err              com.wepie.wespy                      W  java.lang.ClassNotFoundException: Didn't find class "com.wepie.wespy.module.party.home.PartyShareData" on path: DexPathList[[zip file "/data/app/~~UzbQn9r_moNkE7-KSr4Snw==/com.wepie.wespy-PAPtm3RmfiEAj_iMkz4ovw==/base.apk"],nativeLibraryDirectories=[/data/app/~~UzbQn9r_moNkE7-KSr4Snw==/com.wepie.wespy-PAPtm3RmfiEAj_iMkz4ovw==/lib/arm64, /data/app/~~UzbQn9r_moNkE7-KSr4Snw==/com.wepie.wespy-PAPtm3RmfiEAj_iMkz4ovw==/base.apk!/lib/arm64-v8a, /system/lib64, /system_ext/lib64]]
2024-04-09 19:18:54.732  6374-6374  SurfaceControl          com.wepie.wespy                      I   setExtendedRangeBrightness sc=Surface(name=com.wepie.wespy/com.wepie.wespy.module.party.home.PartyHomeActivity)/@0x25d32fc,currentBufferRatio=1.0,desiredRatio=1.0
2024-04-09 19:18:54.732  6374-16483 System.err              com.wepie.wespy                      W  	at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:259)
2024-04-09 19:18:54.732  6374-16483 System.err              com.wepie.wespy                      W  	at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.parseType(KDeclarationContainerImpl.kt:266)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.loadParameterTypes(KDeclarationContainerImpl.kt:257)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.findConstructorBySignature(KDeclarationContainerImpl.kt:228)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:67)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:36)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.ReflectProperties$LazyVal.invoke(ReflectProperties.java:62)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:31)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.KFunctionImpl.getCaller(Unknown Source:7)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.ReflectJvmMapping.getJavaMethod(ReflectJvmMapping.kt:63)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.KCallablesJvm.setAccessible(KCallablesJvm.kt:82)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at com.hjq.gson.factory.constructor.KotlinDataClassDefaultValueConstructor.construct(KotlinDataClassDefaultValueConstructor.kt:29)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at com.hjq.gson.factory.constructor.l.construct(ReflectCreatorConstructor.java:29)
2024-04-09 19:18:54.733  6374-16662 BLASTBufferQueue        com.wepie.wespy                      D  [VRI[PartyHomeActivity]#15](f:0,a:1) acquireNextBufferLocked size=24x24 mFrameNumber=1 applyTransaction=true mTimestamp=108821324931038(auto) mPendingTransactions.size=0 graphicBufferId=27376121544767 transform=0
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at com.hjq.gson.factory.b.e.read(ReflectiveTypeAdapter.java:58)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.hjq.gson.factory.c.c$1.a(ReflectiveTypeUtils.java:110)
2024-04-09 19:18:54.734  6374-16662 VRI[PartyHomeActivity]  com.wepie.wespy                      D  Received frameCommittedCallback lastAttemptedDrawFrameNum=1 didProduceBuffer=true syncBuffer=false
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.hjq.gson.factory.b.e.read(ReflectiveTypeAdapter.java:71)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.hjq.gson.factory.c.c$1.a(ReflectiveTypeUtils.java:110)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.hjq.gson.factory.b.e.read(ReflectiveTypeAdapter.java:71)
2024-04-09 19:18:54.734  6374-6374  VRI[PartyHomeActivity]  com.wepie.wespy                      D  draw finished.
2024-04-09 19:18:54.734  6374-6374  VRI[PartyHomeActivity]  com.wepie.wespy                      D  reportDrawFinished
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.google.gson.Gson.fromJson(Gson.java:1227)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.google.gson.Gson.fromJson(Gson.java:1329)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.google.gson.Gson.fromJson(Gson.java:1300)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.three.http.callback.DataCallback.parseResponse(DataCallback.java:74)
2024-04-09 19:18:54.734  6374-6374  ViewRootImplExtImpl     com.wepie.wespy                      D  setMaxDequeuedBufferCount: 2
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.three.http.core.HttpUtil$3.onResponse(HttpUtil.java:288)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at okhttp3.RealCall$AsyncCall.execute(RealCall.java:174)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
2024-04-09 19:18:54.735  6374-16483 System.err              com.wepie.wespy                      W  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
2024-04-09 19:18:54.735  6374-16483 System.err              com.wepie.wespy                      W  	at java.lang.Thread.run(Thread.java:1012)

提供截图或视频

No response

提供解决方案

No response

Gson版本升级到2.9.1之后ConstructorConstructor构造方法需要三个参数,望兼容

【警告:请务必按照 issue 模板填写,不要抱有侥幸心理,一旦发现 issue 没有按照模板认真填写,一律直接关闭】

问题描述

  • 框架版本【必填】:6.2

  • 问题描述【必填】:gson 2.9.1版本构造方法变更

  • 复现步骤【必填】:XXX(注意:目前不受理没有复现步骤的 Bug 单)

  • 是否必现【必填】:是

  • 出现问题的手机信息【必填】:请填写出现问题的品牌和机型

  • 出现问题的安卓版本【必填】:请填写出现问题的 Android 版本

请回答

  • 是部分机型还是所有机型都会出现【必答】:部分/全部(例如:某为,某 Android 版本会出现)

  • 框架最新的版本是否存在这个问题【必答】:是/否(如果用的是旧版本的话,建议升级看问题是否还存在)

  • 是否已经查阅框架文档还未能解决的【必答】:是/否(文档会提供最常见的问题解答,可以看看是否有自己想要的)

  • issue 是否有人曾提过类似的问题【必答】:是/否(看看曾经有人提过类似的问题,先参考一下别人是怎么解决的)

  • 使用原生的 Gson 是否也会出现该问题【必答】:是/否(排查一下是不是 GsonFactory 的代码存在问题导致的)

其他

  • 提供报错堆栈(如果有报错的话必填,注意不要拿被混淆过的代码堆栈上来)

  • 提供截图或视频(根据需要提供,此项不强制)

  • 提供解决方案(如果已经解决了的话,此项不强制)

json名字中带特殊符表情比如😁(unicode)的数据是否有容错处理

【警告:请务必按照 issue 模板填写,不要抱有侥幸心理,一旦发现 issue 没有按照模板认真填写,一律直接关闭】

问题描述

  • json名字中带特殊符表情比如😁(unicode)的数据是否有容错处理

请回答

  • issue 是否有人曾提过类似的问题?【必答】否

  • 框架文档是否有提及到此问题?【必答】:否

9.0升级9.3[Bug]:

框架版本【必填】

v9.3

问题描述【必填】

9.0升级9.3后 解析报错无法解析

复现步骤【必填】

image
image

是否必现【必填】

未选择

项目 targetSdkVersion【必填】

23

出现问题的手机信息【必填】

小米青春11

出现问题的安卓版本【必填】

13

问题信息的来源渠道【必填】

No response

是部分机型还是所有机型都会出现【必答】

跟机型没关系

框架最新的版本是否存在这个问题【必答】

未选择

框架文档是否提及了该问题【必答】

未选择

是否已经查阅框架文档但还未能解决的【必答】

未选择

issue 列表中是否有人曾提过类似的问题【必答】

未选择

是否已经搜索过了 issue 列表但还未能解决的【必答】

未选择

是否可以通过 Demo 来复现该问题【必答】

未选择

提供报错堆栈

{"code":2000,"msg":"success","data":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwaHBlcjY2Ni9qd3QiLCJ1c2VyX2lkIjoiMTIiLCJqd3Rfc2NlbmUiOiJkZWZhdWx0IiwianRpIjoiZGVmYXVsdF82NTk0ZDgzMjAzZTY3Ni4xOTQyNzk5OCIsImlhdCI6MTcwNDI1MzQ5MCwibmJmIjoxNzA0MjUzNDkwLCJleHAiOjE3MzYzOTQyOTB9.DeUkeOJslxiraqmuw5tnXQj0Qknh7OH-05ZoUiWJRSo","user_info":{"user_id":"12","mobile":"817612703911","username":"Ocean1234567890","regdate":"","avatar":"https:\/\/sg-small.voopoo.com.cn\/voopoo-club\/portrait\/202311\/07\/4d03b89f443b0b4d48f06497e9ec882e1699340148943.jpg","recommender":"","last_login_time":1704253490,"created_at":1639551834,"updated_at":1704253490,"role_id":1,"invite_num":0,"fcm_token":"d-MA5kjATc-rFBPGp76YOt:APA91bFSs1lT5XuCIuuaLOjofXcMfu1jAbbSuVkzj08RtrSATvDWkGKAviZofqt71Znq2HWWCFxA4MZ1ZaRZmUAvLUPVpi94A-sQhtcNVVvzTqdHvD2LSs6mdxyO7zJVmkfNWycXV380","salt":"a31d43","posts":25,"followers":12,"birth_year":1990,"birth_month":1,"birth_day":1,"gender":2,"is_gray":0,"email":"","deleted_at":null,"password":"6f5bae4c240b5dfef0d71c9d357f1372","platform":"2","last_ip":"192.168.12.212","info_status":1,"source":1,"avatar_status":1,"reg_ip":"103.162.172.86","app_version":"2.0.4","last_visit_time":1704253476}}}

提供截图或视频

image

提供解决方案

No response

请问一下这样处理可以吗?

addConverterFactory(GsonConverterFactory.create(GsonBuilder().create())),GsonBuilder().create() 这个更换成类库里的Gson实例,可以处理容错么?比如int的字段,但是后台返回的小数!

[Bug]:解析出现报错

框架版本【必填】

9.5

问题描述【必填】

  • 我使用 com.github.getActivity:EasyHttp:12.8 框架,代码拷贝的是 EasyHttp 的模板代码,使用 com.github.getActivity:GsonFactory:9.5 解析的时候会报错,错误信息
No virtual method getModule()Ljava/lang/Module; in class Ljava/lang/Class; or its super classes (declaration of 'java.lang.Class' appears in /apex/com.android.art/javalib/core-oj.jar)
java.lang.NoSuchMethodError: No virtual method getModule()Ljava/lang/Module; in class Ljava/lang/Class; or its super classes (declaration of 'java.lang.Class' appears in /apex/com.android.art/javalib/core-oj.jar)
	at kotlin.reflect.jvm.internal.impl.serialization.deserialization.builtins.BuiltInsResourceLoader.loadResource(BuiltInsResourceLoader.java:26)
	at kotlin.reflect.jvm.internal.impl.descriptors.runtime.components.ReflectKotlinClassFinder.findBuiltInsData(ReflectKotlinClassFinder.kt:52)
	at kotlin.reflect.jvm.internal.impl.builtins.jvm.JvmBuiltInsPackageFragmentProvider.findPackage(JvmBuiltInsPackageFragmentProvider.kt:60)
	at kotlin.reflect.jvm.internal.impl.serialization.deserialization.AbstractDeserializedPackageFragmentProvider$fragments$1.invoke(AbstractDeserializedPackageFragmentProvider.kt:35)
	at kotlin.reflect.jvm.internal.impl.serialization.deserialization.AbstractDeserializedPackageFragmentProvider$fragments$1.invoke(AbstractDeserializedPackageFragmentProvider.kt:34)
	at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$MapBasedMemoizedFunction.invoke(LockBasedStorageManager.java:578)
	at kotlin.reflect.jvm.internal.impl.serialization.deserialization.AbstractDeserializedPackageFragmentProvider.collectPackageFragments(AbstractDeserializedPackageFragmentProvider.kt:43)
	at kotlin.reflect.jvm.internal.impl.descriptors.PackageFragmentProviderKt.collectPackageFragmentsOptimizedIfPossible(PackageFragmentProvider.kt:50)
	at kotlin.reflect.jvm.internal.impl.descriptors.impl.CompositePackageFragmentProvider.collectPackageFragments(CompositePackageFragmentProvider.kt:47)
	at kotlin.reflect.jvm.internal.impl.descriptors.PackageFragmentProviderKt.collectPackageFragmentsOptimizedIfPossible(PackageFragmentProvider.kt:50)
	at kotlin.reflect.jvm.internal.impl.descriptors.impl.CompositePackageFragmentProvider.collectPackageFragments(CompositePackageFragmentProvider.kt:47)
	at kotlin.reflect.jvm.internal.impl.descriptors.PackageFragmentProviderKt.collectPackageFragmentsOptimizedIfPossible(PackageFragmentProvider.kt:50)
	at kotlin.reflect.jvm.internal.impl.descriptors.PackageFragmentProviderKt.packageFragments(PackageFragmentProvider.kt:41)
	at kotlin.reflect.jvm.internal.impl.descriptors.impl.LazyPackageViewDescriptorImpl$fragments$2.invoke(LazyPackageViewDescriptorImpl.kt:38)
	at kotlin.reflect.jvm.internal.impl.descriptors.impl.LazyPackageViewDescriptorImpl$fragments$2.invoke(LazyPackageViewDescriptorImpl.kt:37)
	at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:408)
	at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:527)
	at kotlin.reflect.jvm.internal.impl.storage.StorageKt.getValue(storage.kt:42)
	at kotlin.reflect.jvm.internal.impl.descriptors.impl.LazyPackageViewDescriptorImpl.getFragments(LazyPackageViewDescriptorImpl.kt:37)
	at kotlin.reflect.jvm.internal.impl.descriptors.impl.LazyPackageViewDescriptorImpl$memberScope$1.invoke(LazyPackageViewDescriptorImpl.kt:42)
	at kotlin.reflect.jvm.internal.impl.descriptors.impl.LazyPackageViewDescriptorImpl$memberScope$1.invoke(LazyPackageViewDescriptorImpl.kt:41)
	at kotlin.reflect.jvm.internal.impl.resolve.scopes.LazyScopeAdapter$lazyScope$1.invoke(LazyScopeAdapter.kt:28)
	at kotlin.reflect.jvm.internal.impl.resolve.scopes.LazyScopeAdapter$lazyScope$1.invoke(LazyScopeAdapter.kt:27)
	at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:408)
	at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:527)
2024-01-23 10:33:42.733 19935-19991 EasyHttp D...pi@c16eb70 cn.smart.hospital                    E  	at kotlin.reflect.jvm.internal.impl.resolve.scopes.LazyScopeAdapter.getWorkerScope(LazyScopeAdapter.kt:34)
	at kotlin.reflect.jvm.internal.impl.resolve.scopes.AbstractScopeAdapter.getContributedClassifier(AbstractScopeAdapter.kt:44)
	at kotlin.reflect.jvm.internal.impl.builtins.KotlinBuiltIns$3.invoke(KotlinBuiltIns.java:91)
	at kotlin.reflect.jvm.internal.impl.builtins.KotlinBuiltIns$3.invoke(KotlinBuiltIns.java:88)
	at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$MapBasedMemoizedFunction.invoke(LockBasedStorageManager.java:578)
	at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$MapBasedMemoizedFunctionToNotNull.invoke(LockBasedStorageManager.java:651)
	at kotlin.reflect.jvm.internal.impl.builtins.KotlinBuiltIns.getBuiltInClassByName(KotlinBuiltIns.java:223)
	at kotlin.reflect.jvm.internal.impl.builtins.KotlinBuiltIns.getAny(KotlinBuiltIns.java:228)
	at kotlin.reflect.jvm.internal.impl.builtins.KotlinBuiltIns.getAnyType(KotlinBuiltIns.java:498)
	at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaTypeParameterDescriptor.computeNotEnhancedBounds(LazyJavaTypeParameterDescriptor.kt:56)
	at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaTypeParameterDescriptor.resolveUpperBounds(LazyJavaTypeParameterDescriptor.kt:48)
	at kotlin.reflect.jvm.internal.impl.descriptors.impl.AbstractTypeParameterDescriptor$TypeParameterTypeConstructor.computeSupertypes(AbstractTypeParameterDescriptor.java:168)
	at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor$supertypes$1.invoke(AbstractTypeConstructor.kt:83)
	at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor$supertypes$1.invoke(AbstractTypeConstructor.kt:83)
	at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:408)
	at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValueWithPostCompute.invoke(LockBasedStorageManager.java:481)
	at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValueWithPostCompute.invoke(LockBasedStorageManager.java:512)
	at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor.getSupertypes(AbstractTypeConstructor.kt:30)
	at kotlin.reflect.jvm.internal.impl.descriptors.impl.AbstractTypeParameterDescriptor.getUpperBounds(AbstractTypeParameterDescriptor.java:119)
	at kotlin.reflect.jvm.internal.impl.load.java.typeEnhancement.SignatureEnhancement$SignatureParts.boundsNullability(signatureEnhancement.kt:445)
	at kotlin.reflect.jvm.internal.impl.load.java.typeEnhancement.SignatureEnhancement$SignatureParts.nullabilityInfoBoundsForTypeParameterUsage(signatureEnhancement.kt:428)
	at kotlin.reflect.jvm.internal.impl.load.java.typeEnhancement.SignatureEnhancement$SignatureParts.extractQualifiersFromAnnotations(signatureEnhancement.kt:358)
	at kotlin.reflect.jvm.internal.impl.load.java.typeEnhancement.SignatureEnhancement$SignatureParts.computeQualifiersForOverride(signatureEnhancement.kt:539)
	at kotlin.reflect.jvm.internal.impl.load.java.typeEnhancement.SignatureEnhancement$SignatureParts.computeIndexedQualifiersForOverride(signatureEnhancement.kt:479)
	at kotlin.reflect.jvm.internal.impl.load.java.typeEnhancement.SignatureEnhancement$SignatureParts.enhance(signatureEnhancement.kt:273)
	at kotlin.reflect.jvm.internal.impl.load.java.typeEnhancement.SignatureEnhancement.enhanceSignature(signatureEnhancement.kt:211)
	at kotlin.reflect.jvm.internal.impl.load.java.typeEnhancement.SignatureEnhancement.enhanceSignatures(signatureEnhancement.kt:151)
	at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaClassMemberScope$constructors$1.invoke(LazyJavaClassMemberScope.kt:101)
	at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaClassMemberScope$constructors$1.invoke(LazyJavaClassMemberScope.kt:83)
2024-01-23 10:33:42.736 19935-19991 EasyHttp D...pi@c16eb70 cn.smart.hospital                    E  	at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:408)
	at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:527)
	at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaClassDescriptor.getConstructors(LazyJavaClassDescriptor.kt:141)
	at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaClassDescriptor.getConstructors(LazyJavaClassDescriptor.kt:44)
	at kotlin.reflect.jvm.internal.KClassImpl.getConstructorDescriptors(KClassImpl.kt:203)
	at kotlin.reflect.jvm.internal.KClassImpl$Data$constructors$2.invoke(KClassImpl.kt:94)
	at kotlin.reflect.jvm.internal.KClassImpl$Data$constructors$2.invoke(KClassImpl.kt:47)
	at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:92)
	at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:31)
	at kotlin.reflect.jvm.internal.KClassImpl$Data.getConstructors(Unknown Source:7)
	at kotlin.reflect.jvm.internal.KClassImpl.getConstructors(KClassImpl.kt:238)
	at kotlin.reflect.full.KClasses.getPrimaryConstructor(KClasses.kt:40)
	at com.hjq.gson.factory.constructor.KotlinDataClassDefaultValueConstructor.construct(KotlinDataClassDefaultValueConstructor.kt:25)
	at com.hjq.gson.factory.constructor.ReflectCreatorConstructor.construct(ReflectCreatorConstructor.java:28)
	at com.hjq.gson.factory.element.ReflectiveTypeAdapter.read(ReflectiveTypeAdapter.java:57)
	at com.google.gson.Gson.fromJson(Gson.java:1227)
	at com.google.gson.Gson.fromJson(Gson.java:1137)
	at com.google.gson.Gson.fromJson(Gson.java:1047)
	at com.google.gson.Gson.fromJson(Gson.java:1014)
	at cn.smart.hospital.http.model.RequestHandler.requestSuccess(RequestHandler.java:108)
	at com.hjq.http.callback.NormalCallback.onHttpResponse(NormalCallback.java:106)
	at com.hjq.http.callback.BaseCallback.onResponse(BaseCallback.java:72)
	at okhttp3.RealCall$AsyncCall.execute(RealCall.java:203)
	at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
	at java.lang.Thread.run(Thread.java:920)
2024-01-23 10:33:42.745 19935-19991 EasyHttp D...pi@c16eb70 cn.smart.hospital                    E  No virtual method getModule()Ljava/lang/Module; in class Ljava/lang/Class; or its super classes (declaration of 'java.lang.Class' appears in /apex/com.android.art/javalib/core-oj.jar)
com.hjq.http.exception.HttpException: No virtual method getModule()Ljava/lang/Module; in class Ljava/lang/Class; or its super classes (declaration of 'java.lang.Class' appears in /apex/com.android.art/javalib/core-oj.jar)
	at cn.smart.hospital.http.model.RequestHandler.requestFail(RequestHandler.java:155)
	at com.hjq.http.callback.NormalCallback.onHttpFailure(NormalCallback.java:145)
	at com.hjq.http.callback.BaseCallback.onResponse(BaseCallback.java:75)
	at okhttp3.RealCall$AsyncCall.execute(RealCall.java:203)
	at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)`
  • 降低 GsonFactory:9.5版本 9.3,9.2报一样的错误,9.0就能正常使用

复现步骤【必填】

  • 因为的项目没有办法升级到 EasyHttp demo 的最新 targetSdkVersion 31 的版本,直接跑 EasyHttp demo 是没有问题
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28

    defaultConfig {
        versionName "1.0.5"
        versionCode 105
        targetSdkVersion 28
        applicationId "cn.smart.hospital"
        minSdkVersion 21
        multiDexEnabled false
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    lintOptions {
        abortOnError false
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

repositories {
    flatDir {
        dirs 'libs'
    }
}

// 这个plugin需要放在android配置之后,因为需要读取android中的配置项
apply plugin: 'replugin-plugin-gradle'

repluginPluginConfig {
    appModule = ':app'
    pluginName = "cn.smart.hospital" // 内容为该插件包名
    hostApplicationId = "com.huawei.smarthome.extend"
    hostAppLauncherActivity = "com.huawei.smarthome.login.LauncherActivity"
}

dependencies {
    implementation "com.qihoo360.replugin:replugin-plugin-lib-androidx:2.3.4"
    implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
    provided files('libs/fragment.jar')//这个jar就是从Support-fragment中提取出来的并非特制包目的是为了骗过编译期
    provided files('libs/common-utils-lib-1.0.0.jar')//这个jar就是从Host的utils中编译生成的,其目的是为了骗过编译期
    implementation(name: 'plugin-library', ext: 'aar')//sample:compile aar
    // mqtt
    implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.2'
    implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
    // 网络请求框架:https://github.com/getActivity/EasyHttp
    implementation 'com.github.getActivity:EasyHttp:12.8'
    implementation 'com.squareup.okhttp3:okhttp:3.12.13'
    // Gson 解析容错:https://github.com/getActivity/GsonFactory
    implementation 'com.github.getActivity:GsonFactory:9.0'
    // Json 解析框架:https://github.com/google/gson
    implementation 'com.google.code.gson:gson:2.10.1'
    // Kotlin 反射库:用于反射 Kotlin data class 类对象
    implementation 'org.jetbrains.kotlin:kotlin-reflect:1.5.10'
    //基础工具库
    implementation 'com.github.tamsiree.RxTool:RxKit:2.6.3'

    implementation 'io.github.jeremyliao:live-event-bus-x:1.8.0'
}

public class DeviceTypeApi implements IRequestApi {
    @NonNull
    @Override
    public String getApi() {
        return "api/p-szkj-select-device-type";
    }

    private String sn;

    public DeviceTypeApi setSn(String sn) {
        this.sn = sn;
        return this;
    }
    public final static class Bean {
        private String sn; // 设备码
        private int type; // 类型
        private String no; // 编号

        public String getSn() {
            return sn;
        }

        public int getType() {
            return type;
        }

        public String getNo() {
            return no;
        }
    }
}
String sn = RxSPTool.getContent(RxTool.getContext(), Constant.KEY_DEVICE_SN_NAME);
EasyHttp.get(this)
        .api(new DeviceTypeApi()
                .setSn(sn))
        .request(new HttpCallbackProxy<HttpData<DeviceTypeApi.Bean>>(this) {
            @Override
            public void onHttpSuccess(HttpData<DeviceTypeApi.Bean> result) {
                RxToast.showToastShort("Get 请求成功,请看日志");
            }
        });

是否必现【必填】

项目 targetSdkVersion【必填】

28

出现问题的手机信息【必填】

Android12 虚拟机

出现问题的安卓版本【必填】

Android12

问题信息的来源渠道【必填】

自己遇到的

是部分机型还是所有机型都会出现【必答】

全部

框架最新的版本是否存在这个问题【必答】

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

是否可以通过 Demo 来复现该问题【必答】

提供报错堆栈

No response

提供截图或视频

No response

提供解决方案

No response

建议适配kotlin默认值

【警告:请务必按照 issue 模板填写,不要抱有侥幸心理,一旦发现 issue 没有按照模板认真填写,一律直接关闭】

建议收集

  • issue 是否有人曾提过类似的问题?【必答】 #4 有人提出过类似的疑问

  • 框架文档是否有提及到此问题?【必答】:否

  • 你觉得框架有什么不足之处?【必答】

框架的容错特性确实很不错 考虑到目前kotlin开发占比很高
而kotlin在定义data class时候给默认值是比较常规的做法
很大一部分人还是通过Gson来配合retrofit 但目前的Gson不完全支持默认值
核心代码:

Object fieldValue = typeAdapter.read(reader);
if (fieldValue != null || !isPrimitive) {
    field.set(value, fieldValue);
}

当为非基本类型时候 会强制赋值 导致默认值失效
如果可以适配kotlin的默认值情况 能解决 设置了默认值 还是非空类型 还要必须判空的情况

  • 你觉得该怎么去完善会比较好?【非必答】

建议:如果强制更改这一段赋值逻辑 可能就不是“原汁原味”的Gson了 改动有点大 不一定大家都能接受
所以在初始化的时候给一个配置 可以开启支持kotlin默认值 可能是比较好的做法
核心代码:

Object fieldValue = typeAdapter.read(reader);
if (fieldValue != null) {
    field.set(value, fieldValue);
} else if (!isPrimitive) {
    if (field.get(value) == null) {
        field.set(value, null);
    }
}

[疑惑]:<init> argument 4 has type int, got null,

问题描述【必填】

data class SumInfo(
        var columnistCount: Int = 0,
        var courseCount: Int = 0
    ) 

需求场景需要支持默认值为0;解析的时候会有警告信息

java.lang.IllegalArgumentException: method com.dop.data.user.User$SumInfo.<init> argument 4 has type int, got null

警告来自下面的代码

 Object[] parameterValue = new Object[parameterLength];
                // 这个参数是标记位,用于判断有没有设置默认值进去,会进行 & 位运算进行判断
                // 这里设置成 Integer.MAX_VALUE,Integer.MAX_VALUE & 大于 0 的值,都会等于那个值
                // 这样就能每次都能走到设置默认值那里
                // Github 地址:https://github.com/getActivity/GsonFactory/issues/27
                parameterValue[parameterLength - 2] = Integer.MAX_VALUE;
                // 这个参数 DefaultConstructorMarker 类型,用于标记构造函数是 Kotlin 语法自动生成的
                parameterValue[parameterLength - 1] = null;

                for (int i = 0; i < parameterTypes.length - 2; i++) {
                    Class<?> parameterType = parameterTypes[i];
                    parameterValue[i] = getTypeDefaultValue(parameterType);
                }

                instance = (T) constructor.newInstance(parameterValue);

请问要怎么正确的处理默认值0的情况呢?

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

请问此框架是不是不支持Map类型数据?

在使用此框架的容错机制时,现data数据中存在键名为extra,类型为LinkedTreeMap的值,实际返回数据可能是map类型,也可能是数组类型,这是解析会报错。

  • 框架版本:com.github.getActivity:GsonFactory:6.0

  • 问题描述:问题描述如上
    具体调用代码:GsonFactory.newGsonBuilder().create().fromJson(data, DataBean::class.java)
    DataBean是实际的数据bean对象

  • 复现步骤:使用'com.google.code.gson:gson:2.9.0'

  • 是否必现:是

  • 出现问题的手机信息:模拟器Pixel 4 API29

  • 出现问题的安卓版本:API29

json数据如下:
{
"code": 1,
"msg": "success",
"data": {
"name": "zhangsan",
"age": 10,
"sex": "male",
"score": 100,
"info": {
},
"friends": [
{
"name": "lisi",
"age": 11,
"sex": "female",
"friends": "",
"score": "80",
"info": {
"address": "2333",
"phone": "12345353"
},
"grade": [
100,
90,
89,
88
],
"extra": {
},
"data": {
"name": "lisi"
}
},
{
"name": "wangwu",
"age": 11,
"sex": "male",
"score": "90",
"info": "",
"grade": [
],
"data": [
{
"name": "lisi"
},
{
"name": "wangwu"
}
],
"extra": {
"111": "222"
},
"friends": [
{
"name": "zhaoliu",
"age": 12,
"sex": "male",
"score": 78,
"friends": [
],
"data": "data",
"extra": [
{
"33": "44"
}
],
"grade": "",
"info": [
{
"address": "123e4",
"phone": "123333"
}
]
},
{
"name": "laoba",
"age": 13,
"sex": "female",
"score": 88,
"friends": {
},
"extra": [
],
"grade": {
},
"info": null
}
]
}
]
}
}

[疑惑]:9.0升级9.2

问题描述【必填】

按照文档

// Gson 解析容错:https://github.com/getActivity/GsonFactory
implementation 'com.github.getActivity:GsonFactory:9.2'
// Json 解析框架:https://github.com/google/gson
implementation 'com.google.code.gson:gson:2.10.1'
// Kotlin 反射库:用于反射 Kotlin data class 类对象(新增依赖)
implementation 'org.jetbrains.kotlin:kotlin-reflect:1.5.10'

当我调用接口时返回错误:
ApiResponse#data,后台返回的条目类型为:BEGIN_OBJECT

这是我的代码:
login

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

打包成正式版解析有个BUG

问题描述:同样的代码,在测试版一切正常,但是 打包成正式版之后 解析就出问题了。我用的技术中台的模板项目,把相关的网络请求代码加进去测试的 代码和测试结果如下
public class HttpList2Data extends HttpData<HttpList2Data.ListBean> {

public static class ListBean<T> {

    /** 当前页码 */
    private int pageIndex;
    /** 页大小 */
    private int pageSize;
    /** 总数量 */
    private int totalNumber;
    /** 数据 */
    private List<T> rows;

    public List<T> getRows() {
        return rows;
    }

    /**
     * 判断是否是最后一页
     */
    public boolean isLastPage() {
        return Math.ceil((float) totalNumber / pageSize) <= pageIndex;
    }

    public int getTotalNumber() {
        return totalNumber;
    }

    public int getPageIndex() {
        return pageIndex;
    }

    public int getPageSize() {
        return pageSize;
    }

    @Override
    public @NotNull String toString() {
        return "ListBean{" +
                "pageIndex=" + pageIndex +
                ", pageSize=" + pageSize +
                ", totalNumber=" + totalNumber +
                ", rows=" + rows +
                '}';
    }
}

}
image
测试结果:
2021-10-29 11:11:23.587 18625-18773/com.hjq.demo I/EasyHttp:
{
"code" : "0",
"data" : {
"total" : 1,
"rows" : [
{
"address" : "",
"air_north_time" : "",
"condition" : "么有",
"create_date" : 1635316395600,
"create_user" : "admin",
"direction" : "",
"dynamic" : "3",
"dynamic_img" : "/upload//fjkcjs/202110/fjkcjs_1635316393452.jpeg",
"dynamic_time" : 1635316320609,
"enterprise_id" : "fjkcjs",
"id" : "02dbba90ebe848ccadabb1aed2b0b52f",
"latitude" : "0.006",
"longitude" : "0.0065",
"now_port" : "",
"remark" : "",
"ship_date_id" : "b27ec0bdaf3c4c11a661af88a337fa2a",
"ship_position" : "",
"update_date" : "",
"update_user" : ""
}
]
},"message" : "成功"
}
com.hjq.demo D/(:119): text==={"code":"0","data":{"total":1,"rows":[{"address":"","air_north_time":"","condition":"么有","create_date":1635316395600,"create_user":"admin","direction":"","dynamic":"3","dynamic_img":"/upload//fjkcjs/202110/fjkcjs_1635316393452.jpeg","dynamic_time":1635316320609,"enterprise_id":"fjkcjs","id":"02dbba90ebe848ccadabb1aed2b0b52f","latitude":"0.006","longitude":"0.0065","now_port":"","remark":"","ship_date_id":"b27ec0bdaf3c4c11a661af88a337fa2a","ship_position":"","update_date":"","update_user":""}]},"message":"成功"}

com.hjq.demo D/(:122): result===HttpData{code=0, msg='null', data=ListBean{pageIndex=0, pageSize=0, totalNumber=0, rows=[ShipDynamicListBean{air_north_time=null, create_date=null, create_user='null', condition='null', remark='null', direction='null', dynamic='null', dynamicName='null', dynamic_time=null, enterprise_id='null', id='null', now_port='null', ship_date_id='null', ship_position='null', update_date=null, update_user='null', dynamic_img='null'}]}}

从结果可以看出定位在这段代码
try {
result = GsonFactory.getSingletonGson().fromJson(text, type);
Timber.d("result===%s",result);
} catch (JsonSyntaxException e) {
// 返回结果读取异常
throw new DataException(mApplication.getString(R.string.http_data_explain_error), e);
}
我最奇怪的是 debug版运行 我在这里打断点查看 一点问题都没有 但是一打包成正式的 就解析不出来了 而且还没报错 找这个bug找的我脑瓜子嗡嗡的 说的有点啰嗦了 希望大佬能看下

[建议]:兼容类型不匹配的情况

你觉得框架有什么不足之处?【必答】

建议容错库遇到类型匹配但解析错误的时候,也可以返回默认值
例子复现如下:

public class JsonBean {
    private ArrayList<Double> dataValList = new ArrayList<>();
}
String json = "{\n" +
                    "        \"id\": \"1704391195266473986\",\n" +
                    "        \"dataValList\":\n" +
                    "        [\n" +
                    "            \"null\"\n" +
                    "        ],\n" +
                    "    }";
JsonBean bean = GsonFactory.getSingletonGson().fromJson(json, JsonBean.class);

执行以上代码 会直接抛出错误.
在真实场景中请求一个接口返回一段json解析,如果因为解析其中一个字段就整体抛错的话,也会让程序停止进行不下去,这一点是否可以优化

issue 是否有人曾提过类似的建议?【必答】

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

你觉得该怎么去完善会比较好?【非必答】

No response

[疑惑]:GsonFactory反序列化数据量大时速度有点慢

问题描述【必填】

我分别使用GsonFactory.getSingletonGson().fromJson(str,type)和Gson().fromJson(str,type)来解析文件大小为 300kb 的 json 字符串,前者耗时 700-800 毫秒,后者100 毫秒不到。是我使用的方式不对吗?还是因为框架为了适配做了很多处理的缘故。
版本 9.2

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

能否通过getDelegateAdapter方法给所有TypeAdapter都套层代理,出错时直接跳到下一个呢

【警告:请务必按照 issue 模板填写,不要抱有侥幸心理,一旦发现 issue 没有按照模板认真填写,一律直接关闭】

问题描述

大佬您好:
在阅读源码时,偶然发现在Gson.class下,跟getAdapter同级有一个getDelegateAdapter的方法,它的作用是可以给所有的TypeAdapter设置代理类,这样就可以拦截TypeAdapter出错时的动作,比如下面类似代码:

{
    val gson = GsonBuilder().registerTypeAdapterFactory(StrongTypeAdapterFactory()).create()
    class StrongTypeAdapterFactory : TypeAdapterFactory {
        override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T> {
            // 给每一个目标TypeAdapter都嵌套一个代理,可以主动拦截其结果
            val adapter: TypeAdapter<T> = gson.getDelegateAdapter(this, type)

            return object : TypeAdapter<T>() {
                @Throws(IOException::class)
                override fun write(out: JsonWriter, value: T?) {
                    adapter.write(out, value)
                }

                @Throws(IOException::class)
                override fun read(reader: JsonReader): T? {
                    return try {
                        // 原始目标adapter反序列化
                        adapter.read(reader)
                    } catch (e: Throwable) {
                        // 只要有报错的并且还有下一个就执行跳过操
                        if (reader.hasNext()) {
                            reader.skipValue()
                        }
                        null
                    }
                }
            }
        }
    }
}

这样是不是就能简单粗暴的搞定所有的容错呢。

请回答

  • issue 是否有人曾提过类似的问题?【必答】 没有

  • 框架文档是否有提及到此问题?【必答】:否

容错范围

【警告:请务必按照 issue 模板填写,不要抱有侥幸心理,一旦发现 issue 没有按照模板认真填写,一律直接关闭】

问题描述

  • 请描述一下你的疑惑【必填】:期待的是bean但是返回的是空字符串容错失败了。

请回答

  • issue 是否有人曾提过类似的问题?【必答】否

  • 框架文档是否有提及到此问题?【必答】:是
    hello,轮子哥,很感谢能开源这么多项目。我在使用容错项目前看到了项目简介容错支持bean。或者说是不兼容的类型直接不解析。我遇见的问题是这样的:retrofit请求使用的gson解析,baseresponse中泛型data对象有时候在接口校验失败之后,后台原先返回的data就会变成空字符串,这时候就会有问题因为baseresponse里面的泛型data通常是传一个bean进去,导致了解析异常报错。使用本框架还是没有容错,请问轮子哥这个场景在不在本框架的容错范围之内。

8.0版本 jitpack无法引用依赖

框架版本【必填】

8.0

问题描述【必填】

https://jitpack.io/com/github/getActivity/GsonFactory/8.0/build.log
3月25的打包失败,无法引用依赖

复现步骤【必填】

直接依赖8.0版本错误

是否必现【必填】

项目 targetSdkVersion【必填】

33

出现问题的手机信息【必填】

出现问题的安卓版本【必填】

问题信息的来源渠道【必填】

自己遇到的

是部分机型还是所有机型都会出现【必答】

所有

框架最新的版本是否存在这个问题【必答】

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

是否可以通过 Demo 来复现该问题【必答】

提供报错堆栈

No response

提供截图或视频

No response

提供解决方案

No response

关于JsonCallback关联功能的优化建以

建议收集

  • issue 是否有人曾提过类似的问题?(必答项,一旦出现重复提问我将不会再次解答)

  • 你觉得框架有什么不足之处?(必答项,你可以描述框架有什么令你不满意的地方)
    CollectionTypeAdapterFactory、ReflectiveTypeAdapterFactory 在 create 方法中,return TypeAdapter前未调用【setReflectiveType】方法,导致如果是整个类或者这个List转换错误的情况下,JsonCallback回调中前两个值都为null。
    举例:
    String value = "[{\"name\":\"张三\"}]"; IceVo iceVo = ...(转换代码)

    String value2 = "{\"name\":\"张三\"}"; List<IceVo> list = ...(转换代码)

    虽然应用到的可能性比较小,但是我觉得可以更完善一点吧。

  • 你觉得该怎么去完善会比较好?(非必答项,你可以提供一下自己的想法或者做法供作者参考)
    CollectionTypeAdapterFactory、ReflectiveTypeAdapterFactory 在 create 方法中,return TypeAdapter前调用【setReflectiveType】方法

[疑惑]:关于readme写的为什么gson解析后,kotlin默认值无效的问题不太对

问题描述【必填】

在Gson反序列化的时候,它会使用无参构造函数来创建对象

data class User(val name: String = "张三", val age: Int = 18)

比如这个类,在编译后,这个类会有两个构造函数:一个是无参构造函数,另一个是有参构造函数。无参构造函数会使用默认值也就是null来初始化属性,有参构造函数会使用传入的参数来初始化属性。

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

[Bug]:9.0升级9.2

框架版本【必填】

9.2

问题描述【必填】

当我调用接口时返回错误:
ApiResponse#data,后台返回的条目类型为:BEGIN_OBJECT

复现步骤【必填】

使用 Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(GsonFactory.getSingletonGson()))

调用接口:

suspend fun login(@Body request: LoginRequest): ApiResponse<String>

后台返回值:

{
    "code" : 0,
    "data" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUz",
    "extra" : null,
    "message" : "success",
    "path" : null,
    "timestamp" : 1702881400175
}

ApiResponse实体类:

data class ApiResponse<T>(
    val code: Int?,
    val data: T?,
    val extra: Extra?,
    val message: String?,
    val path: String?,
    val timestamp: Any?,
    val version: String?,
) : BaseResponse<T>() {

    override fun isSuccess(): Boolean = code == 0

    override fun getResponseCode(): Int = code ?: -1

    override fun getResponseData(): T? = data

    override fun getResponseExtra(): Extra? = extra

    override fun getResponseMessage(): String? = message

    override fun getResponsePath(): String? = path

    override fun getResponseTimestamp(): Any? = timestamp

    override fun getResponseVersion(): String? = version
}
abstract class BaseResponse<T> {
    abstract fun isSuccess(): Boolean

    abstract fun getResponseCode(): Int

    abstract fun getResponseData(): T?

    abstract fun getResponseExtra(): Extra?

    abstract fun getResponseMessage(): String?

    abstract fun getResponsePath(): String?

    abstract fun getResponseTimestamp(): Any?

    abstract fun getResponseVersion(): String?
}
data class Extra(
    val errorMsg: String?
)

是否必现【必填】

项目 targetSdkVersion【必填】

33

出现问题的手机信息【必填】

小米mix2、逍遥模拟器(android 9版本)

出现问题的安卓版本【必填】

Android 9

问题信息的来源渠道【必填】

自己遇到的

是部分机型还是所有机型都会出现【必答】

目前仅测试小米mix2、逍遥模拟器(android 9版本)

框架最新的版本是否存在这个问题【必答】

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

是否可以通过 Demo 来复现该问题【必答】

提供报错堆栈

No response

提供截图或视频

No response

提供解决方案

No response

[建议]:我想去掉这样的警告打印<init> argument 4 has type int, got null

你觉得框架有什么不足之处?【必答】

这样我的控制台会很乱,会和有用的信息混在一起

issue 是否有人曾提过类似的建议?【必答】

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

你觉得该怎么去完善会比较好?【非必答】

这块警告没有实质性的作用可以去掉

[Bug]:升级到 9.3 直接无法解析

框架版本【必填】

v9.3

问题描述【必填】

从v9.0升级v9.3直接无法解析了 炸了
image

复现步骤【必填】

所有接口都解析不了 9.0正常

是否必现【必填】

项目 targetSdkVersion【必填】

23

出现问题的手机信息【必填】

小米

出现问题的安卓版本【必填】

13

问题信息的来源渠道【必填】

No response

是部分机型还是所有机型都会出现【必答】

跟机型没关系

框架最新的版本是否存在这个问题【必答】

未选择

框架文档是否提及了该问题【必答】

未选择

是否已经查阅框架文档但还未能解决的【必答】

未选择

issue 列表中是否有人曾提过类似的问题【必答】

未选择

是否已经搜索过了 issue 列表但还未能解决的【必答】

未选择

是否可以通过 Demo 来复现该问题【必答】

未选择

提供报错堆栈

![image](https://github.com/getActivity/GsonFactory/assets/41047773/b4e30b58-0dfc-4268-bd31-ebe4ee8ce4a9)

提供截图或视频

image

提供解决方案

image

BigDecimalTypeAdapter 有BUG

String result = in.nextString();
if (result == null || "".equals(result)) {
return new BigDecimal(0);
}
return new BigDecimal(in.nextString());

return new BigDecimal(in.nextString());
应改为:
return new BigDecimal(result);

谢谢轮子哥解决了我的问题!!

我们登录接口后台应该返回实体对象类型,在code码错误时,后台返回的字符串,导致我这一直报错,在网上找了好多都解决不了,用了轮子哥这个直接帮我解决了,轮子哥太强大了!!

[Bug]:result返回为空时出现java.lang.ClassCastException异常,具体返回格式看描述

框架版本【必填】

9.6

问题描述【必填】

{"message":"操作成功","code":"A000","result":{"count":"15"}}

{"message":"操作成功","code":"A000","result":null}
java.lang.ClassCastException: java.lang.Object cannot be cast to com.xxxx.ben.xxxx

复现步骤【必填】

{"message":"操作成功","code":"A000","result":null} result为null时必现

是否必现【必填】

项目 targetSdkVersion【必填】

33

出现问题的手机信息【必填】

红米K30Pro

出现问题的安卓版本【必填】

12

问题信息的来源渠道【必填】

自己遇到的

是部分机型还是所有机型都会出现【必答】

全部

框架最新的版本是否存在这个问题【必答】

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

是否可以通过 Demo 来复现该问题【必答】

提供报错堆栈

No response

提供截图或视频

No response

提供解决方案

No response

后台成功与失败返回类型不一致的问题

【警告:请务必按照 issue 模板填写,不要抱有侥幸心理,一旦发现 issue 没有按照模板认真填写,一律直接关闭】

建议收集

  • issue 是否有人曾提过类似的问题?【必答】否

  • 你觉得框架有什么不足之处?【必答】 后台返回的错误数据结构与实体类不一致,如果使用了该lib,那么就会被容错了,获取到的对象是空的,比如后台返回的正确的是{"code":200,
    "result":{"banner":"1"} }而错误的是{"code":500,
    "result":"网络出现了异常"},我需要吐司出来这个result数据,那么使用该lib 我获取到的result就是空的

  • 你觉得该怎么去完善会比较好?【非必答】

  • 是否可以提交一个接口让开发者单独对其做出处理?

库非常不错,但问题不是个好问题

路过这个 repo 老多次,但是还是忍不住说一两句:

大佬的库非常不错,但是背景问题不是个好问题。

大家可能觉得 Gson 解析容错没什么,那是因为我们对 Gson 解析失败的场景没有了解过:
类型不对:后台有数据时返回 JsonObject,没数据返回 [],Gson 会直接抛出异常
措手不及:如果客户端定义的是整数,但是后台返回浮点数,Gson 会直接抛出异常
意想不到:如果客户端定义的是布尔值,但是后台返回的是 0 或者 1,Gson 会直接抛出异常

这种情况下的后端已经违背了最最基本的要求,即 按照 contract 输出结果
所以这里的责任首先在后端,而不是客户端;

从修改的容易程度和特点来说,也应该是后端来处理这种问题——
因为客户端的控制权在用户手里,新版一旦发出去,其改动就非常困难,用户可以拒绝新版的改动,使用旧版本;
但是后端可以随时上线,出现问题之后可以随时改动,随时发版,随时 hotfix(虽然这个随时不太人道,但是从根本上来说是可以做到的,而客户端要等待新版审核,修改生效的时间甚至要拉长到一周到两周)

有没有必要处理 Json 解析容错?
我觉得非常有必要,因为后台返回的数据结构是什么样我们把控不了,但是有一点是肯定的,我们都不希望它崩,因为一个接口的失败导致整个 App 崩溃退出实属不值得,但是 Gson 很敏感,动不动就崩。

当然,我们都不希望程序崩溃,但是一个 Gson 解析失败就会导致程序崩溃吗?或者说 Gson 崩溃就一定要导致 App 崩溃吗?
当然不是,我们应该对网络请求部分进行 try-catch,这样即使抛异常了,App 也不会崩溃,还可以根据异常显示一个用户友好的提示界面,然后把锅丢给后端去改。(毕竟这是后端的责任)
如果觉得到处写 try-catch 不容易,也可以统一设定 ExceptionHandler,不管是 RxJava 还是 Kotlin Coroutine 都有与之对应的方案。


Gson 采用的是 let-it-fail 的策略,本来这种 与 contract 不符 的情况就应该要 fail,只有 fail 了,才能让开发人员尽早发现,尽早解决问题;
但是大佬的库实际上是将问题隐藏了起来,同时也对后端返回的数据进行了修改

如果后台返回的类型和客户端定义的类型不匹配,框架就不解析这个字段
如果客户端定义的是整数,但后台返回浮点数,框架就对数值进行取整并赋值给字段
如果客户端定义布尔值,但是后台返回整数,框架则将非 0 的数值则赋值为 true,否则为 false

这样说实话如果不熟悉这个框架的新人接手这个项目,查问题的时候显然要走点弯路。

举个这么个场景:

如果客户端定义的是整数,但后台返回浮点数,框架就对数值进行取整并赋值给字段

浮点数的取整是有很多方法的,例如四舍五入取整,进一取整,抹除小数部分保留整数部分等等;
有些时候根据不同的情况需要对浮点数进行不同的取整方式

如果客户端定义布尔值,但是后台返回整数,框架则将非 0 的数值则赋值为 true,否则为 false

当然,后台正常的时候返回 0 和 1,但是这个字段对应的服务崩溃了,然后后台处理了一下反了一个 -1;
这个时候 -1 到底是 true 还是 false,就需要看情况来定了。


当然,我也待过那种前端弱势,后端强势的公司,说什么都不改,问就是改不了,不好改;
这个时候我觉得应该跑路了,这种垃圾公司待着也没什么用

服务端没有返回相应的字段数据

Class Test { String name; String age; }

您好,请问下这么一个例子,服务端只有返回name 这个字段数据,导致age为null,(反序列化时,类中有但Json中没有的字段将设值为null。)我想对age进行不为null处理,应该怎么做呢

[疑惑]:为啥fastjson解析的是正常的,本框架解析的不一样

问题描述【必填】

比如字段 attitude、collectTime

image
image
image
image
image

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

Gson 2.9.0兼容性问题

问题描述

Gson 2.9.0
ConstructorConstructor()构造多了一个参数
而GsonFactory用的是单构造的ConstructorConstructor(),要不要考虑兼容一下
Gson无法代码判断版本号,这个兼容只能用反射实现?判断这个构造方法是一个参数还是两个参数?
想不到什么更好的方案

  • 框架版本:com.github.getActivity:GsonFactory:5.2

  • 问题描述:
    ConstructorConstructor constructor = new ConstructorConstructor(INSTANCE_CREATORS);

  • 复现步骤:使用'com.google.code.gson:gson:2.9.0'

  • 是否必现:是

[Bug]:从 9.0 升级 9.3 出现崩溃

框架版本【必填】

9.3

问题描述【必填】

json解析问题

复现步骤【必填】

abstract class BaseResponse<T> {
    abstract fun isSuccess(): Boolean

    abstract fun getResponseCode(): Int

    abstract fun getResponseData(): T?

    abstract fun getResponseExtra(): Extra?

    abstract fun getResponseMessage(): String?

    abstract fun getResponsePath(): String?

    abstract fun getResponseTimestamp(): Any?

    abstract fun getResponseVersion(): String?
}
data class Extra(
    val errorMsg: String?
)
data class ApiResponse<T>(
    val code: Int?,
    val data: T?,
    val extra: Extra?,
    val message: String?,
    val path: String?,
    val timestamp: Any?,
    val version: String?,
) : BaseResponse<T>() {

    override fun isSuccess(): Boolean = code == 0

    override fun getResponseCode(): Int = code ?: -1

    override fun getResponseData(): T? = data

    override fun getResponseExtra(): Extra? = extra

    override fun getResponseMessage(): String? = message

    override fun getResponsePath(): String? = path

    override fun getResponseTimestamp(): Any? = timestamp

    override fun getResponseVersion(): String? = version
}

json如下

{
  "code": 0,
  "data": {
    "datas": [
      {
        "groupId": "1726920869317746689",
        "groupImg": "https://oss.bilinl.com/files/OSS_1607632797885739008/758500106313318471893a4e89.png",
        "groupName": "预警机器人的群",
        "groupNum": 16,
        "groupType": 0
      },
      {
        "groupId": "1724676352415760385",
        "groupImg": "https://oss.bilinl.com/files/OSS_1607632797885739008/467635091659571222b5249583.png",
        "groupName": "日报周报统计群",
        "groupNum": 93,
        "groupType": 0
      },
      {
        "groupId": "1722155428100882433",
        "groupImg": "https://oss.bilinl.com/files/OSS_1607632797885739008/28490015896166408679bad795.JPEG",
        "groupName": "呼呼和",
        "groupNum": 17,
        "groupType": 0
      },
      {
        "groupId": "1717475646627946497",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475641447981058",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475636247044097",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475631025135618",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475625782255617",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475620543569922",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475614512160770",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475609080537090",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475603145596930",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475597814636545",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475592550785025",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475587261767681",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475582031470594",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475576830533633",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475571650568193",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475566403493890",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      },
      {
        "groupId": "1717475561185779713",
        "groupImg": "https://oss.bilinl.com/files/2022/10/18/2268350967832576e8f3005bb8.png",
        "groupName": "测试群",
        "groupNum": 5,
        "groupType": 0
      }
    ],
    "empty": false,
    "total": 875
  },
  "extra": null,
  "message": "success",
  "path": null,
  "timestamp": 1704182713739
}

报错信息如下

1704183212596

是否必现【必填】

项目 targetSdkVersion【必填】

33

出现问题的手机信息【必填】

小米mix2、逍遥模拟器(android 9版本)

出现问题的安卓版本【必填】

Android 9

问题信息的来源渠道【必填】

自己遇到的

是部分机型还是所有机型都会出现【必答】

目前仅测试小米mix2、逍遥模拟器(android 9版本)

框架最新的版本是否存在这个问题【必答】

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

是否可以通过 Demo 来复现该问题【必答】

提供报错堆栈

No response

提供截图或视频

No response

提供解决方案

No response

请严格按照 issue 模板来提问题,否则一律不受理

最近发现有很多人给我提 issue 没有认真按照模板上面的来填写,导致了在排查问题的过程中浪费了作者许多不必要的时间和精力,所以请后面提 issue 的人务必严格遵守,否则我不会受理,直接关闭 issue。

解析json数据问题

问题描述

  • 框架版本:GsonFactory版本:6.0 gson版本:2.9.0

  • 问题描述:在解析期望类型是LinkedTreeMap<String, String>,实际返回数据可能是null,空字符串,数组等类型,则会报错,具体使用json在相关文件中

  • 复现步骤:集成框架后,解析测试json数据

  • 是否必现:是

  • 出现问题的手机信息:模拟器Pixel 4,小米MI-4C

  • 出现问题的安卓版本:API29

请回答

  • 是部分机型还是所有机型都会出现:测试的机型都出现报错

  • 框架最新的版本是否存在这个问题:是

  • 是否已经查阅框架文档还未能解决的:是

  • issue 是否有人曾提过类似的问题:否

  • 使用原生的 Gson 是否也会出现该问题:是

其他

  • 提供报错堆栈:

  • E/CustomActivityOnCrash: App has crashed, executing CustomActivityOnCrash's UncaughtExceptionHandler
    com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 1069 path $.data.friends[1].friends[0].extra[0]
    at com.hjq.gson.factory.element.ReflectiveTypeAdapter.read(ReflectiveTypeAdapter.java:73)
    at com.google.gson.Gson$FutureTypeAdapter.read(Gson.java:1079)
    at com.hjq.gson.factory.element.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:34)
    at com.hjq.gson.factory.element.CollectionTypeAdapter.read(CollectionTypeAdapter.java:62)
    at com.hjq.gson.factory.element.CollectionTypeAdapter.read(CollectionTypeAdapter.java:23)
    at com.hjq.gson.factory.element.ReflectiveTypeUtils$1.read(ReflectiveTypeUtils.java:111)
    at com.hjq.gson.factory.element.ReflectiveTypeAdapter.read(ReflectiveTypeAdapter.java:71)
    at com.google.gson.Gson$FutureTypeAdapter.read(Gson.java:1079)
    at com.hjq.gson.factory.element.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:34)
    at com.hjq.gson.factory.element.CollectionTypeAdapter.read(CollectionTypeAdapter.java:62)
    at com.hjq.gson.factory.element.CollectionTypeAdapter.read(CollectionTypeAdapter.java:23)
    at com.hjq.gson.factory.element.ReflectiveTypeUtils$1.read(ReflectiveTypeUtils.java:111)
    at com.hjq.gson.factory.element.ReflectiveTypeAdapter.read(ReflectiveTypeAdapter.java:71)
    at com.hjq.gson.factory.element.ReflectiveTypeUtils$1.read(ReflectiveTypeUtils.java:111)
    at com.hjq.gson.factory.element.ReflectiveTypeAdapter.read(ReflectiveTypeAdapter.java:71)
    at com.google.gson.Gson.fromJson(Gson.java:991)
    at com.google.gson.Gson.fromJson(Gson.java:956)
    at com.google.gson.Gson.fromJson(Gson.java:905)
    at com.google.gson.Gson.fromJson(Gson.java:876)

  • 提供截图或视频(根据需要提供,此项不强制)
    相关文件.zip

  • 提供解决方案(如果已经解决了的话,此项不强制):小白一枚,不知道具体解决思路,只知道可能是AdapterFactory的问题

[Bug]:开启混淆后,Kotlin的data class 内部类解析失败。

框架版本【必填】

9.6

问题描述【必填】

开启混淆后,Kotlin的data class 内部类解析失败。

复现步骤【必填】

创建一个kotlin 文件
在其中定义多个data class ,并且相互有所引用,使用@SerializedName方法进行注解。
开启混淆,解析对应代码。

是否必现【必填】

项目 targetSdkVersion【必填】

33

出现问题的手机信息【必填】

全部

出现问题的安卓版本【必填】

全部

问题信息的来源渠道【必填】

自己遇到的

是部分机型还是所有机型都会出现【必答】

全部

框架最新的版本是否存在这个问题【必答】

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

是否可以通过 Demo 来复现该问题【必答】

提供报错堆栈

2024-04-09 19:18:54.732  6374-16483 System.err              com.wepie.wespy                      W  java.lang.ClassNotFoundException: Didn't find class "com.wepie.wespy.module.party.home.PartyShareData" on path: DexPathList[[zip file "/data/app/~~UzbQn9r_moNkE7-KSr4Snw==/com.wepie.wespy-PAPtm3RmfiEAj_iMkz4ovw==/base.apk"],nativeLibraryDirectories=[/data/app/~~UzbQn9r_moNkE7-KSr4Snw==/com.wepie.wespy-PAPtm3RmfiEAj_iMkz4ovw==/lib/arm64, /data/app/~~UzbQn9r_moNkE7-KSr4Snw==/com.wepie.wespy-PAPtm3RmfiEAj_iMkz4ovw==/base.apk!/lib/arm64-v8a, /system/lib64, /system_ext/lib64]]
2024-04-09 19:18:54.732  6374-6374  SurfaceControl          com.wepie.wespy                      I   setExtendedRangeBrightness sc=Surface(name=com.wepie.wespy/com.wepie.wespy.module.party.home.PartyHomeActivity)/@0x25d32fc,currentBufferRatio=1.0,desiredRatio=1.0
2024-04-09 19:18:54.732  6374-16483 System.err              com.wepie.wespy                      W  	at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:259)
2024-04-09 19:18:54.732  6374-16483 System.err              com.wepie.wespy                      W  	at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.parseType(KDeclarationContainerImpl.kt:266)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.loadParameterTypes(KDeclarationContainerImpl.kt:257)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.findConstructorBySignature(KDeclarationContainerImpl.kt:228)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:67)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:36)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.ReflectProperties$LazyVal.invoke(ReflectProperties.java:62)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:31)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.internal.KFunctionImpl.getCaller(Unknown Source:7)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.ReflectJvmMapping.getJavaMethod(ReflectJvmMapping.kt:63)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at kotlin.reflect.jvm.KCallablesJvm.setAccessible(KCallablesJvm.kt:82)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at com.hjq.gson.factory.constructor.KotlinDataClassDefaultValueConstructor.construct(KotlinDataClassDefaultValueConstructor.kt:29)
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at com.hjq.gson.factory.constructor.l.construct(ReflectCreatorConstructor.java:29)
2024-04-09 19:18:54.733  6374-16662 BLASTBufferQueue        com.wepie.wespy                      D  [VRI[PartyHomeActivity]#15](f:0,a:1) acquireNextBufferLocked size=24x24 mFrameNumber=1 applyTransaction=true mTimestamp=108821324931038(auto) mPendingTransactions.size=0 graphicBufferId=27376121544767 transform=0
2024-04-09 19:18:54.733  6374-16483 System.err              com.wepie.wespy                      W  	at com.hjq.gson.factory.b.e.read(ReflectiveTypeAdapter.java:58)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.hjq.gson.factory.c.c$1.a(ReflectiveTypeUtils.java:110)
2024-04-09 19:18:54.734  6374-16662 VRI[PartyHomeActivity]  com.wepie.wespy                      D  Received frameCommittedCallback lastAttemptedDrawFrameNum=1 didProduceBuffer=true syncBuffer=false
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.hjq.gson.factory.b.e.read(ReflectiveTypeAdapter.java:71)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.hjq.gson.factory.c.c$1.a(ReflectiveTypeUtils.java:110)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.hjq.gson.factory.b.e.read(ReflectiveTypeAdapter.java:71)
2024-04-09 19:18:54.734  6374-6374  VRI[PartyHomeActivity]  com.wepie.wespy                      D  draw finished.
2024-04-09 19:18:54.734  6374-6374  VRI[PartyHomeActivity]  com.wepie.wespy                      D  reportDrawFinished
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.google.gson.Gson.fromJson(Gson.java:1227)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.google.gson.Gson.fromJson(Gson.java:1329)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.google.gson.Gson.fromJson(Gson.java:1300)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.three.http.callback.DataCallback.parseResponse(DataCallback.java:74)
2024-04-09 19:18:54.734  6374-6374  ViewRootImplExtImpl     com.wepie.wespy                      D  setMaxDequeuedBufferCount: 2
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at com.three.http.core.HttpUtil$3.onResponse(HttpUtil.java:288)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at okhttp3.RealCall$AsyncCall.execute(RealCall.java:174)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
2024-04-09 19:18:54.734  6374-16483 System.err              com.wepie.wespy                      W  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
2024-04-09 19:18:54.735  6374-16483 System.err              com.wepie.wespy                      W  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
2024-04-09 19:18:54.735  6374-16483 System.err              com.wepie.wespy                      W  	at java.lang.Thread.run(Thread.java:1012)

提供截图或视频

No response

提供解决方案

堆栈中的com.wepie.wespy.module.party.home.PartyShareData是原类名,但是被混淆了。通过反编译kotlin的字节码发现里面确实有一些反射代码,所以理论上keep一下就可以。

可以通过添加混淆规则解决,但是看堆栈还是报在了sdk这里,正常java类直接这样用没什么问题,还是想知道与根本原因.
目前使用8.0版本也无该问题。

根据demo差异,发现我们并未使用kotlin的kotlin-reflect库,有空后排查一下这里。

[Bug]:com.google.gson.internal.ConstructorConstructor$9.construct (ConstructorConstructor.java:262)

框架版本【必填】

6.5

问题描述【必填】

com.google.gson.internal.ConstructorConstructor$9.construct (ConstructorConstructor.java:262)
com.hjq.gson.factory.element.ReflectiveTypeAdapter.read (ReflectiveTypeAdapter.java:58)
com.hjq.gson.factory.element.ReflectiveTypeUtils$1.read (ReflectiveTypeUtils.java:111)
com.hjq.gson.factory.element.ReflectiveTypeAdapter.read (ReflectiveTypeAdapter.java:71)
com.hjq.gson.factory.element.TypeAdapterRuntimeTypeWrapper.read (TypeAdapterRuntimeTypeWrapper.java:35)
com.hjq.gson.factory.element.CollectionTypeAdapter.read (CollectionTypeAdapter.java:62)
com.hjq.gson.factory.element.CollectionTypeAdapter.read (CollectionTypeAdapter.java:23)
com.hjq.gson.factory.element.ReflectiveTypeUtils$1.read (ReflectiveTypeUtils.java:111)
com.hjq.gson.factory.element.ReflectiveTypeAdapter.read (ReflectiveTypeAdapter.java:71)
com.hjq.gson.factory.element.TypeAdapterRuntimeTypeWrapper.read (TypeAdapterRuntimeTypeWrapper.java:35)
com.hjq.gson.factory.element.CollectionTypeAdapter.read (CollectionTypeAdapter.java:62)
com.hjq.gson.factory.element.CollectionTypeAdapter.read (CollectionTypeAdapter.java:23)
com.google.gson.Gson$FutureTypeAdapter.read (Gson.java:1367)
com.hjq.gson.factory.element.ReflectiveTypeUtils$1.read (ReflectiveTypeUtils.java:111)
com.hjq.gson.factory.element.ReflectiveTypeAdapter.read (ReflectiveTypeAdapter.java:71)
com.hjq.gson.factory.element.TypeAdapterRuntimeTypeWrapper.read (TypeAdapterRuntimeTypeWrapper.java:35)
com.hjq.gson.factory.element.CollectionTypeAdapter.read (CollectionTypeAdapter.java:62)
com.hjq.gson.factory.element.CollectionTypeAdapter.read (CollectionTypeAdapter.java:23)
com.hjq.gson.factory.element.ReflectiveTypeUtils$1.read (ReflectiveTypeUtils.java:111)
com.hjq.gson.factory.element.ReflectiveTypeAdapter.read (ReflectiveTypeAdapter.java:71)
com.google.gson.Gson.fromJson (Gson.java:1227)
com.google.gson.Gson.fromJson (Gson.java:1137)
com.google.gson.Gson.fromJson (Gson.java:1047)
com.google.gson.Gson.fromJson (Gson.java:1014)

复现步骤【必填】

是否必现【必填】

项目 targetSdkVersion【必填】

31

出现问题的手机信息【必填】

Galaxy A02

出现问题的安卓版本【必填】

7

问题信息的来源渠道【必填】

其他渠道

是部分机型还是所有机型都会出现【必答】

全部

框架最新的版本是否存在这个问题【必答】

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

是否可以通过 Demo 来复现该问题【必答】

提供报错堆栈

No response

提供截图或视频

c2fd3726cc037bd23fad2f71f8b84796

提供解决方案

No response

[疑惑]:不知道怎么写标题,看描述吧

问题描述【必填】

{"message":"操作成功","code":"A000","result":{"count":"15"}}

{"message":"操作成功","code":"A000","result":null}

框架是否支持result为null的情况,我接入的测试的时候遇到接口返回result为null的抛出ClassCastException异常,其他接口result返回数据时没有问题
java.lang.ClassCastException: java.lang.Object cannot be cast to com.xxxx.ben.xxxx

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.