我是一名热爱 Android 技术的程序员,平时爱造轮子,人送外号轮子哥 。
我的理想是让这个世界没有难开发的安卓项目,消灭一切难维护的代码。
Gson 解析容错框架,愿从此再无 Json 解析报错
License: Apache License 2.0
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)`
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 请求成功,请看日志");
}
});
是
28
Android12 虚拟机
Android12
自己遇到的
全部
是
否
是
否
是
是
No response
No response
No response
框架版本【必填】:6.2
问题描述【必填】:gson 2.9.1版本构造方法变更
复现步骤【必填】:XXX(注意:目前不受理没有复现步骤的 Bug 单)
是否必现【必填】:是
出现问题的手机信息【必填】:请填写出现问题的品牌和机型
出现问题的安卓版本【必填】:请填写出现问题的 Android 版本
是部分机型还是所有机型都会出现【必答】:部分/全部(例如:某为,某 Android 版本会出现)
框架最新的版本是否存在这个问题【必答】:是/否(如果用的是旧版本的话,建议升级看问题是否还存在)
是否已经查阅框架文档还未能解决的【必答】:是/否(文档会提供最常见的问题解答,可以看看是否有自己想要的)
issue 是否有人曾提过类似的问题【必答】:是/否(看看曾经有人提过类似的问题,先参考一下别人是怎么解决的)
使用原生的 Gson 是否也会出现该问题【必答】:是/否(排查一下是不是 GsonFactory 的代码存在问题导致的)
提供报错堆栈(如果有报错的话必填,注意不要拿被混淆过的代码堆栈上来)
提供截图或视频(根据需要提供,此项不强制)
提供解决方案(如果已经解决了的话,此项不强制)
按照文档
// 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
否
是
否
是
v9.3
9.0升级9.3后 解析报错无法解析
未选择
23
小米青春11
13
No response
跟机型没关系
未选择
未选择
未选择
未选择
未选择
未选择
{"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}}}
No response
集合类型和后端不匹配的情况下即使申明了默认值也会直接返回[null]?
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】方法
这样我的控制台会很乱,会和有用的信息混在一起
是
否
是
这块警告没有实质性的作用可以去掉
框架版本: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的问题
如题
建议容错库遇到类型匹配但解析错误的时候,也可以返回默认值
例子复现如下:
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解析,如果因为解析其中一个字段就整体抛错的话,也会让程序停止进行不下去,这一点是否可以优化
否
否
是
No response
issue 是否有人曾提过类似的问题?【必答】否
框架文档是否有提及到此问题?【必答】:是
hello,轮子哥,很感谢能开源这么多项目。我在使用容错项目前看到了项目简介容错支持bean。或者说是不兼容的类型直接不解析。我遇见的问题是这样的:retrofit请求使用的gson解析,baseresponse中泛型data对象有时候在接口校验失败之后,后台原先返回的data就会变成空字符串,这时候就会有问题因为baseresponse里面的泛型data通常是传一个bean进去,导致了解析异常报错。使用本框架还是没有容错,请问轮子哥这个场景在不在本框架的容错范围之内。
在Gson反序列化的时候,它会使用无参构造函数来创建对象
data class User(val name: String = "张三", val age: Int = 18)
比如这个类,在编译后,这个类会有两个构造函数:一个是无参构造函数,另一个是有参构造函数。无参构造函数会使用默认值也就是null来初始化属性,有参构造函数会使用传入的参数来初始化属性。
是
否
否
是
issue 是否有人曾提过类似的问题?【必答】否
你觉得框架有什么不足之处?【必答】 后台返回的错误数据结构与实体类不一致,如果使用了该lib,那么就会被容错了,获取到的对象是空的,比如后台返回的正确的是{"code":200,
"result":{"banner":"1"} }而错误的是{"code":500,
"result":"网络出现了异常"},我需要吐司出来这个result数据,那么使用该lib 我获取到的result就是空的
你觉得该怎么去完善会比较好?【非必答】
是否可以提交一个接口让开发者单独对其做出处理?
Class Test { String name; String age; }
您好,请问下这么一个例子,服务端只有返回name 这个字段数据,导致age为null,(反序列化时,类中有但Json中没有的字段将设值为null。)我想对age进行不为null处理,应该怎么做呢
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)
无
否
31
Galaxy A02
7
其他渠道
全部
是
否
否
否
是
否
No response
No response
如题,发现数组没有容错,“[ ]” 这种情况,
看文档,array只容错如下这几种:
{}、""、false、0
大佬,我能在整个解析过程中,获取到一个在JavaBean中未定义的属性值吗?比如后端返回的结构体中统一增加了一个tr的字段,但是我所有的Java Bean (Data Class)都没有定义这个字段,按照Gson的解析流程会将未定义的字段都过滤掉,但是我这时想要拿到这个tr字段,应该如何做呢?
否
否
否
是
大佬您好:
在阅读源码时,偶然发现在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 是否有人曾提过类似的问题?【必答】 没有
框架文档是否有提及到此问题?【必答】:否
这框架的转义有一点问题,详情见
https://blog.csdn.net/ifengfan/article/details/88553819
否
否
是
路过这个 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,就需要看情况来定了。
当然,我也待过那种前端弱势,后端强势的公司,说什么都不改,问就是改不了,不好改;
这个时候我觉得应该跑路了,这种垃圾公司待着也没什么用
空对象本来应该返回null或者{ }的,但是PHP后台返回成了[ ],如何容错?
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时必现
是
33
红米K30Pro
12
自己遇到的
全部
是
否
是
否
是
是
No response
No response
No response
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);
}
}
{"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
否
是
否
否
大佬,我能在整个解析过程中,获取到一个在Java Bean中未定义的属性值吗?
比如由于业务需要,后端在返回的结构体最外层统一新增加了一个tr的字段,但是我所有的Java Bean (Data Class)都未定义这个字段,按照Gson的解析流程会将未定义的字段都过滤掉,但是我这时想要拿到这个tr字段,并将这个字段添加给每一层级的Java Bean。
大致流程如下,原始Json是这样的
{
"tr":"tr_map_value",
"data": {
"noticeMsgNum": "208",
"order":{
"orderId":"10086"
}
}
}
但我想得到这样Json解析出来的结果
{
"tr":"tr_map_value",
"data": {
"tr":"tr_map_value",
"noticeMsgNum": "208",
"order":{
"tr":"tr_map_value",
"orderId":"10086"
}
}
}
想了半天,如果想要统一处理,好像只能在解析这一步做操作了。但搞了半天一点头绪都没有,所以想问问大佬您能给些建议吗
否
是
否
是
9.6
开启混淆后,Kotlin的data class 内部类解析失败。
创建一个kotlin 文件
在其中定义多个data class ,并且相互有所引用,使用@SerializedName方法进行注解。
开启混淆,解析对应代码。
是
33
全部
全部
自己遇到的
全部
是
否
是
否
是
否
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库,有空后排查一下这里。
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'
是否必现:是
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
}
报错信息如下
是
33
小米mix2、逍遥模拟器(android 9版本)
Android 9
自己遇到的
目前仅测试小米mix2、逍遥模拟器(android 9版本)
是
否
是
是
是
是
No response
No response
No response
我们登录接口后台应该返回实体对象类型,在code码错误时,后台返回的字符串,导致我这一直报错,在网上找了好多都解决不了,用了轮子哥这个直接帮我解决了,轮子哥太强大了!!
在使用此框架的容错机制时,现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.6
开启混淆后,Kotlin的data class 内部类解析失败。
创建一个kotlin 文件
在其中定义多个data class ,并且相互有所引用,使用@SerializedName方法进行注解。
开启混淆,解析对应代码。
是
33
全部
全部
No response
全部
是
否
否
否
是
否
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
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?
)
是
33
小米mix2、逍遥模拟器(android 9版本)
Android 9
自己遇到的
目前仅测试小米mix2、逍遥模拟器(android 9版本)
是
否
是
否
是
是
No response
No response
No response
Map map=new HashMap<>();
map.put("a",1);
map.put("b",2);
String json=mGson.toJson(map);
Map result=mGson.fromJson(json,Map.class);
result中的a值为1.0,b为2.0
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 的人务必严格遵守,否则我不会受理,直接关闭 issue。
如上标题
我分别使用GsonFactory.getSingletonGson().fromJson(str,type)和Gson().fromJson(str,type)来解析文件大小为 300kb 的 json 字符串,前者耗时 700-800 毫秒,后者100 毫秒不到。是我使用的方式不对吗?还是因为框架为了适配做了很多处理的缘故。
版本 9.2
否
是
否
是
或者说大佬你已经做了我没发现用法?
我测试好像目前都是遇到null字段都会跳过解析
我的json:
{"code":1,"msg":"","data":{"order":{"id":1863,"number":"2024070618060434152","customer_id":null,"produce_cate_code":10000,"product_id":2295,"state":4,"pay_status":null,"store_name":"测试组织三","customer_name":null,"product_name":"测试123456789","linkman":null,"mobile":null,"contacts":null,"contacts_mobile":null,"run":null,"order_type":1,"agency_name":"测试三组","agency_admin_name":null,"agency_owner_name":"测试三组","agency_owner_admin_name":"测试管理员","money":"25.00","start_time":"2024-07-06","end_time":"2026-07-05","create_time":"2024-07-06","address":"测试11111111111111111111111111","unit":"月","peer_price":"0.10","order_state_name":"作废","pay_state_name":"待处理"},"auth":[]}}
No
Yes
No
Yes
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);
8.0
https://jitpack.io/com/github/getActivity/GsonFactory/8.0/build.log
3月25的打包失败,无法引用依赖
直接依赖8.0版本错误
是
33
无
无
自己遇到的
所有
否
否
否
否
是
否
No response
No response
No response
issue 是否有人曾提过类似的问题?【必答】否
框架文档是否有提及到此问题?【必答】:否
问题描述:同样的代码,在测试版一切正常,但是 打包成正式版之后 解析就出问题了。我用的技术中台的模板项目,把相关的网络请求代码加进去测试的 代码和测试结果如下
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 +
'}';
}
}
}
测试结果:
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找的我脑瓜子嗡嗡的 说的有点啰嗦了 希望大佬能看下
v9.3
所有接口都解析不了 9.0正常
是
23
小米
13
No response
跟机型没关系
未选择
未选择
未选择
未选择
未选择
未选择
![image](https://github.com/getActivity/GsonFactory/assets/41047773/b4e30b58-0dfc-4268-bd31-ebe4ee8ce4a9)
addConverterFactory(GsonConverterFactory.create(GsonBuilder().create())),GsonBuilder().create() 这个更换成类库里的Gson实例,可以处理容错么?比如int的字段,但是后台返回的小数!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.