From 2bc5aa5554b4ce4b42363c0dfd40488f46440bca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BD=AE=E5=AD=90=E5=93=A5?= Date: Sat, 13 Jan 2024 11:43:00 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20kotlin=20data=20class=20?= =?UTF-8?q?=E5=8F=AF=E7=A9=BA=E5=AD=97=E6=AE=B5=E6=90=BA=E5=B8=A6=E7=9A=84?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E5=80=BC=E6=B2=A1=E6=9C=89=E7=94=9F=E6=95=88?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20=E4=BF=AE=E5=A4=8D=20kotlin=20data=20class?= =?UTF-8?q?=20=E9=9D=9E=E7=A9=BA=E4=B8=94=E6=B2=A1=E6=9C=89=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E5=80=BC=E7=9A=84=E5=AD=97=E6=AE=B5=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E6=8A=A5=E9=94=99=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 56 +++++++++--------- app/build.gradle | 4 +- .../hjq/gson/factory/test/DataClassBean.kt | 15 +++-- .../gson/factory/test/DataClassChildBean.kt | 6 ++ .../hjq/gson/factory/test/JsonUnitTest.java | 3 +- library/build.gradle | 4 +- .../com/hjq/gson/factory/GsonFactory.java | 8 +-- .../KotlinDataClassDefaultValueConstructor.kt | 57 ++++++++++--------- .../factory/constructor/MainConstructor.java | 15 ++--- .../ReflectCreatorConstructor.java | 5 +- .../ReflectSafeCreatorConstructor.java | 5 +- .../element/CollectionTypeAdapterFactory.java | 6 +- .../element/MapTypeAdapterFactory.java | 2 +- .../element/ReflectiveTypeAdapterFactory.java | 6 +- .../factory/element/ReflectiveTypeUtils.java | 14 ++--- 15 files changed, 112 insertions(+), 94 deletions(-) create mode 100644 app/src/androidTest/java/com/hjq/gson/factory/test/DataClassChildBean.kt diff --git a/README.md b/README.md index 1991797..769d6a9 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ android { dependencies { // Gson 解析容错:https://github.com/getActivity/GsonFactory - implementation 'com.github.getActivity:GsonFactory:9.3' + implementation 'com.github.getActivity:GsonFactory:9.5' // Json 解析框架:https://github.com/google/gson implementation 'com.google.code.gson:gson:2.10.1' // Kotlin 反射库:用于反射 Kotlin data class 类对象 @@ -148,9 +148,9 @@ GsonFactory.setParseExceptionCallback(ParseExceptionCallback callback); * 如果客户端定义的是 **int** 或者 **long** 类型,但后台返回浮点数,框架就对数值进行**直接取整**并赋值给字段 -#### 适配 Kotlin 空值介绍 +#### 适配 kotlin 空值介绍 -* 如果你在 Kotlin 中定义了以下内容的 Bean 类 +* 如果你在 kotlin 中定义了以下内容的 Bean 类 ```kotlin class XxxBean { @@ -163,25 +163,41 @@ class XxxBean { * 那么这到底是为什么呢?聊到这个就不得不先说一下 Gson 解析的机制,我们都知道 Gson 在解析一个 Bean 类的时候,会反射创建一个对象出来,但是大家不知道的是,Gson 会根据 Bean 类的字段名去解析 Json 串中对应的值,然后简单粗暴进行反射赋值,你没有听错,简单粗暴,如果后台返回这个 `age` 字段的值为空,那么 `age` 就会被赋值为空,但是你又在 Kotlin 中声明了 `age` 变量不为空,外层一调用,触发 `NullPointerException` 也是在预料之中。 -* 另外针对 List 和 Map 类型的对象,后台如果有返回 null 或者错误类型数据的时候,框架也会返回一个不为空但是集合大小为 0 的 List 对象或者 Map 对象,避免在 Kotlin 字段上面自定义字段不为空,但是后台返回空的情况导致出现的空指针异常。 +* 另外针对 `List` 和 `Map` 类型的对象,后台如果有返回 null 或者错误类型数据的时候,框架也会返回一个不为空但是集合大小为 0 的 `List` 对象或者 Map 对象,避免在 kotlin 字段上面自定义字段不为空,但是后台返回空的情况导致出现的空指针异常。 * 框架目前的处理方案是,如果后台没有返回这个字段的值,又或者返回这个值为空,则不会赋值给类的字段,因为 Gson 那样做是不合理的,会导致我在 Kotlin 上面使用 Gson 是有问题,变量不定义成可空,每次用基本数据类型还得去做判空,定义成非空,一用还会触发 `NullPointerException`,前后夹击,腹背受敌。 -#### 适配 Kotlin 默认值介绍 +#### 适配 kotlin data class 默认值介绍 -* 如果你在 Kotlin 中定义了以下内容的 Bean 类 +* 如果你在 kotlin 中定义了以下内容的 Bean 类 ```kotlin data class DataClassBean(val name: String = "Hello") ``` -* 如果丢给 Gson 解析,最终会得到以下结果 +* 如果丢给原生 Gson 解析,最终会得到以下结果 ```text name = null ``` -* `name` 字段为什么不等于 `Hello` ?为什么会等于 `null` 值呢?这是因为 Gson 默认只初始化了 DataClassBean 类的空参构造函数,框架的解决方案很简单粗暴,直接引入 Kotlin 反射库,让它找到 Kotlin data class 自动生成的主构造函数,然后反射创建 Kotlin 类,这样得到的对象,非空字段的默认值都会被保留,这样就解决了 Gson 反射 Kotlin Data Class 类出现字段默认值不生效的问题,目前框架内部已经处理了该问题,外部使用的人无需额外处理该问题,只需要调用框架进行解析即可。 +* `name` 字段为什么不等于 `Hello` ?为什么会等于 `null` 值呢?这是因为 Gson 默认只初始化了 `DataClassBean` 类的空参构造函数,框架的解决方案很简单粗暴,直接引入 kotlin 反射库,让它找到 `kotlin data class` 自动生成的主构造函数,然后反射创建 kotlin 类,这样得到的对象,字段上面的默认值都会被保留,这样就解决了 Gson 反射 `kotlin data class` 类出现字段默认值不生效的问题,目前框架内部已经处理了该问题,外部使用的人无需额外处理该问题,只需要调用框架进行解析即可。 + +#### 适配 kotlin data class 非空无默认值字段介绍 + +* 如果你在 Kotlin 中定义了以下内容的 Bean 类 + +```kotlin +data class DataClassBean(var name: String) +``` + +* 如果丢给原生 [Gson](https://github.com/google/gson/) 解析,无论 Json 是什么值,最终会得到 name 的字段值是空的,而丢给 [moshi](https://github.com/square/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` 异常了。 ## 常见疑问解答 @@ -242,8 +258,6 @@ new GsonBuilder() * Android:。。。。。。(哑巴吃黄连,有苦说不出) - * CTO 内心 OS:整个后台都是我在管的,出现这种事情,后面可能会吃不了兜着走,现在幸好拉到一个做垫背的来分担一下事故的责任。 - * Ps:以上故事纯属虚构,大家看看就好,切勿太过当真。不过有一点是真的,若不想日后扯皮,最好还是要留一手。 #### 使用了这个框架后,我如何知道出现了 Json 错误,从而保证问题不被掩盖? @@ -260,20 +274,20 @@ GsonFactory.setParseExceptionCallback(new ParseExceptionCallback() { } @Override - public void onParseListException(TypeToken typeToken, String fieldName, JsonToken listItemJsonToken) { + public void onParseListItemException(TypeToken typeToken, String fieldName, JsonToken listItemJsonToken) { handlerGsonParseException("解析 List 异常:" + typeToken + "#" + fieldName + ",后台返回的条目类型为:" + listItemJsonToken); } @Override - public void onParseMapException(TypeToken typeToken, String fieldName, String mapItemKey, JsonToken mapItemJsonToken) { + public void onParseMapItemException(TypeToken typeToken, String fieldName, String mapItemKey, JsonToken mapItemJsonToken) { handlerGsonParseException("解析 Map 异常:" + typeToken + "#" + fieldName + ",mapItemKey = " + mapItemKey + ",后台返回的条目类型为:" + mapItemJsonToken); } - + private void handlerGsonParseException(String message) { - Log.e(TAG, message); if (BuildConfig.DEBUG) { throw new IllegalArgumentException(message); - } else { + } else { + // 上报到 Bugly 错误列表中 CrashReport.postCatchedException(new IllegalArgumentException(message)); } } @@ -334,18 +348,6 @@ GsonFactory.setParseExceptionCallback(new ParseExceptionCallback() { ![](https://raw.githubusercontent.com/getActivity/Donate/master/picture/pay_ali.png) ![](https://raw.githubusercontent.com/getActivity/Donate/master/picture/pay_wechat.png) -#### 广告区 - -* 我现在任腾讯云服务器推广大使,大家如果有购买服务器的需求,可以通过下面的链接购买 - -[![](https://upload-dianshi-1255598498.file.myqcloud.com/upload/nodir/345X200-9ae456f58874df499adf7c331c02cb0fed12b81d.jpg)](https://curl.qcloud.com/A6cYskvv) - -[【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中](https://curl.qcloud.com/A6cYskvv) - -[![](https://upload-dianshi-1255598498.file.myqcloud.com/345-200-b28f7dee9552f4241ea6a543f15a9798049701d4.jpg)](https://curl.qcloud.com/up4fQsdn) - -[【腾讯云】中小企业福利专场,多款刚需产品,满足企业通用场景需求](https://curl.qcloud.com/up4fQsdn) - ## License ```text diff --git a/app/build.gradle b/app/build.gradle index c09cb03..7e1700d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "com.hjq.gson.factory.demo" minSdkVersion 16 targetSdkVersion 31 - versionCode 930 - versionName "9.3" + versionCode 950 + versionName "9.5" testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } diff --git a/app/src/androidTest/java/com/hjq/gson/factory/test/DataClassBean.kt b/app/src/androidTest/java/com/hjq/gson/factory/test/DataClassBean.kt index b609220..28bd4a6 100644 --- a/app/src/androidTest/java/com/hjq/gson/factory/test/DataClassBean.kt +++ b/app/src/androidTest/java/com/hjq/gson/factory/test/DataClassBean.kt @@ -1,10 +1,13 @@ package com.hjq.gson.factory.test data class DataClassBean( - val name: String = "轮子哥", - val alias: String, - val address: String? = "", - val age: Int = 20, - val weight: Int, - val stature: Int? = 180, + var name: String = "轮子哥", + var alias: String, + var address: String? = "", + var company: String?, + var age: Int = 20, + var weight: Int, + var stature: Int? = 180, + var interest: List, + var child: DataClassChildBean ) \ No newline at end of file diff --git a/app/src/androidTest/java/com/hjq/gson/factory/test/DataClassChildBean.kt b/app/src/androidTest/java/com/hjq/gson/factory/test/DataClassChildBean.kt new file mode 100644 index 0000000..fe18f91 --- /dev/null +++ b/app/src/androidTest/java/com/hjq/gson/factory/test/DataClassChildBean.kt @@ -0,0 +1,6 @@ +package com.hjq.gson.factory.test + +data class DataClassChildBean( + val corporation: String?, + val unmarried: Boolean = true +) \ No newline at end of file diff --git a/app/src/androidTest/java/com/hjq/gson/factory/test/JsonUnitTest.java b/app/src/androidTest/java/com/hjq/gson/factory/test/JsonUnitTest.java index 59983e5..1220a45 100644 --- a/app/src/androidTest/java/com/hjq/gson/factory/test/JsonUnitTest.java +++ b/app/src/androidTest/java/com/hjq/gson/factory/test/JsonUnitTest.java @@ -58,7 +58,8 @@ private void handlerGsonParseException(String message) { /* if (BuildConfig.DEBUG) { throw new IllegalArgumentException(message); - } else { + } else { + // 上报到 Bugly 错误列表中 CrashReport.postCatchedException(new IllegalArgumentException(message)); } */ diff --git a/library/build.gradle b/library/build.gradle index 98f0cc0..512649f 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -6,8 +6,8 @@ android { defaultConfig { minSdkVersion 12 - versionCode 930 - versionName "9.3" + versionCode 950 + versionName "9.5" } // 使用 JDK 1.8 diff --git a/library/src/main/java/com/hjq/gson/factory/GsonFactory.java b/library/src/main/java/com/hjq/gson/factory/GsonFactory.java index a6684f1..b48ed4f 100644 --- a/library/src/main/java/com/hjq/gson/factory/GsonFactory.java +++ b/library/src/main/java/com/hjq/gson/factory/GsonFactory.java @@ -118,7 +118,7 @@ public void addReflectionAccessFilter(ReflectionAccessFilter filter) { */ public static GsonBuilder newGsonBuilder() { GsonBuilder gsonBuilder = new GsonBuilder(); - MainConstructor constructor = new MainConstructor(INSTANCE_CREATORS, true, REFLECTION_ACCESS_FILTERS); + MainConstructor mainConstructor = new MainConstructor(INSTANCE_CREATORS, true, REFLECTION_ACCESS_FILTERS); gsonBuilder.registerTypeAdapterFactory(TypeAdapters.newFactory(String.class, new StringTypeAdapter())) .registerTypeAdapterFactory(TypeAdapters.newFactory(boolean.class, Boolean.class, new BooleanTypeAdapter())) .registerTypeAdapterFactory(TypeAdapters.newFactory(int.class, Integer.class, new IntegerTypeAdapter())) @@ -126,9 +126,9 @@ public static GsonBuilder newGsonBuilder() { .registerTypeAdapterFactory(TypeAdapters.newFactory(float.class, Float.class, new FloatTypeAdapter())) .registerTypeAdapterFactory(TypeAdapters.newFactory(double.class, Double.class, new DoubleTypeAdapter())) .registerTypeAdapterFactory(TypeAdapters.newFactory(BigDecimal.class, new BigDecimalTypeAdapter())) - .registerTypeAdapterFactory(new CollectionTypeAdapterFactory(constructor)) - .registerTypeAdapterFactory(new ReflectiveTypeAdapterFactory(constructor, FieldNamingPolicy.IDENTITY, Excluder.DEFAULT)) - .registerTypeAdapterFactory(new MapTypeAdapterFactory(constructor, false)) + .registerTypeAdapterFactory(new CollectionTypeAdapterFactory(mainConstructor)) + .registerTypeAdapterFactory(new ReflectiveTypeAdapterFactory(mainConstructor, FieldNamingPolicy.IDENTITY, Excluder.DEFAULT)) + .registerTypeAdapterFactory(new MapTypeAdapterFactory(mainConstructor, false)) .registerTypeAdapterFactory(TypeAdapters.newFactory(JSONObject.class, new JSONObjectTypeAdapter())) .registerTypeAdapterFactory(TypeAdapters.newFactory(JSONArray.class, new JSONArrayTypeAdapter())); // 添加到自定义的类型解析适配器,因为在 GsonBuilder.create 方法中会对 List 进行反转,所以这里需要放到最后的位置上,这样就会优先解析 diff --git a/library/src/main/java/com/hjq/gson/factory/constructor/KotlinDataClassDefaultValueConstructor.kt b/library/src/main/java/com/hjq/gson/factory/constructor/KotlinDataClassDefaultValueConstructor.kt index 7451444..c840438 100644 --- a/library/src/main/java/com/hjq/gson/factory/constructor/KotlinDataClassDefaultValueConstructor.kt +++ b/library/src/main/java/com/hjq/gson/factory/constructor/KotlinDataClassDefaultValueConstructor.kt @@ -1,10 +1,13 @@ package com.hjq.gson.factory.constructor +import com.google.gson.Gson import com.google.gson.internal.ObjectConstructor +import com.google.gson.reflect.TypeToken import kotlin.reflect.KParameter import kotlin.reflect.KType import kotlin.reflect.full.primaryConstructor import kotlin.reflect.jvm.isAccessible +import kotlin.reflect.jvm.javaType /** * author : Android 轮子哥 @@ -12,7 +15,7 @@ import kotlin.reflect.jvm.isAccessible * time : 2023/11/25 * desc : Kotlin Data Class 创建器,用于处理反射创建 data class 类导致默认值不生效的问题 */ -class KotlinDataClassDefaultValueConstructor(private val rawType: Class<*>) : ObjectConstructor { +class KotlinDataClassDefaultValueConstructor(private val mainConstructor: MainConstructor, private val gson: Gson, private val rawType: Class<*>) : ObjectConstructor { companion object { /** 构造函数的字段的默认值 */ @@ -25,7 +28,8 @@ class KotlinDataClassDefaultValueConstructor(private val rawType: Class val constructor = rawTypeKotlin.primaryConstructor ?: return null constructor.isAccessible = true - var fullInitialized = true + // 是否初始化构造函数中的全部参数 + var initializedAllParameters = true val constructorSize = constructor.parameters.size val values = Array(constructorSize) { ABSENT_VALUE } @@ -36,28 +40,32 @@ class KotlinDataClassDefaultValueConstructor(private val rawType: Class val parameter = constructor.parameters[i] - // 判断这个参数是不是可选的 + // 判断这个参数是否携带了默认值 if (parameter.isOptional) { - fullInitialized = false + initializedAllParameters = false + continue } // 判断这个参数是否标记为空的 if (parameter.type.isMarkedNullable) { values[i] = null - } else if (!parameter.isOptional) { + } else { // 如果这个参数没有标记为可空的,并且没有携带默认值 // 就需要赋一个默认值给它,否则会实例化构造函数会出现崩溃 // java.lang.IllegalArgumentException: method XxxBean. argument 3 has type int, got java.lang.Object // 如果是基本数据类型就一定会出现崩溃,如果是对象的话,需要同时满足以下条件才会出现崩溃 - // 1. 后台给这个参数返回 null 的情况下 + // 1. 后台给这个参数返回 null 的情况下(这种永远不会出现,因为框架内部处理了) // 2. 获取对象的时候,如果没有做判空,也会出现异常 values[i] = getTypeDefaultValue(parameter.type) } } - val result = if (fullInitialized) { + // 判断构造函数上面所有的参数是否都携带了默认值 + val result = if (initializedAllParameters) { + // 如果是的话,则传入元素全为 Any 的数组进去 constructor.call(*values) } else { + // 如果不是的话,就传入自定义顺序的 Map 对象(Key 是参数名,Value 是参数值)进去 constructor.callBy(IndexedParameterMap(constructor.parameters, values)) } @@ -65,27 +73,22 @@ class KotlinDataClassDefaultValueConstructor(private val rawType: Class } private fun getTypeDefaultValue(type: KType): Any? { - // "class kotlin.Int".endsWith("kotlin.Int") - if (String::class.toString().endsWith(type.toString())) { - return "" - } else if (Byte::class.toString().endsWith(type.toString())) { - return 0.toByte() - } else if (Short::class.toString().endsWith(type.toString())) { - return 0.toShort() - } else if (Int::class.toString().endsWith(type.toString())) { - return 0 - } else if (Long::class.toString().endsWith(type.toString())) { - return 0L - } else if (Float::class.toString().endsWith(type.toString())) { - return 0.0f - } else if (Double::class.toString().endsWith(type.toString())) { - return 0.0 - } else if (Char::class.toString().endsWith(type.toString())) { - return '\u0000' - } else if (Boolean::class.toString().endsWith(type.toString())) { - return false + when (type.classifier) { + String::class -> return "" + Boolean::class -> return false + Int::class -> return 0 + Long::class -> return 0L + Float::class -> return 0.0f + Double::class -> return 0.0 + Short::class -> return 0.toShort() + Byte::class -> return 0.toByte() + Char::class -> return '\u0000' } - return null + + val javaType = type.javaType + val typeToken = TypeToken.get(javaType) ?: return null + val objectConstructor = mainConstructor.get(gson, typeToken) ?: return null + return objectConstructor.construct() } /** 一个简单的 Map,它使用参数索引而不是排序或哈希。 */ diff --git a/library/src/main/java/com/hjq/gson/factory/constructor/MainConstructor.java b/library/src/main/java/com/hjq/gson/factory/constructor/MainConstructor.java index 0c08c8e..1754bd6 100644 --- a/library/src/main/java/com/hjq/gson/factory/constructor/MainConstructor.java +++ b/library/src/main/java/com/hjq/gson/factory/constructor/MainConstructor.java @@ -1,5 +1,6 @@ package com.hjq.gson.factory.constructor; +import com.google.gson.Gson; import com.google.gson.InstanceCreator; import com.google.gson.ReflectionAccessFilter; import com.google.gson.ReflectionAccessFilter.FilterResult; @@ -59,7 +60,7 @@ static String checkInstantiable(Class c) { return null; } - public ObjectConstructor get(TypeToken typeToken) { + public ObjectConstructor get(Gson gson, TypeToken typeToken) { final Type type = typeToken.getType(); final Class rawType = typeToken.getRawType(); @@ -88,7 +89,7 @@ public ObjectConstructor get(TypeToken typeToken) { } FilterResult filterResult = ReflectionAccessFilterHelper.getFilterResult(mReflectionFilters, rawType); - ObjectConstructor defaultConstructor = newDefaultConstructor(rawType, filterResult); + ObjectConstructor defaultConstructor = newDefaultConstructor(this, gson, rawType, filterResult); if (defaultConstructor != null) { return defaultConstructor; } @@ -109,7 +110,7 @@ public ObjectConstructor get(TypeToken typeToken) { // Additionally, since it is not calling any constructor at all, don't use if BLOCK_INACCESSIBLE if (filterResult == FilterResult.ALLOW) { // finally try unsafe - return newUnsafeAllocator(rawType); + return newUnsafeAllocator(gson, rawType); } else { final String message = "Unable to create instance of " + rawType + "; ReflectionAccessFilter " + "does not permit using reflection or Unsafe. Register an InstanceCreator or a TypeAdapter " @@ -134,7 +135,7 @@ else if (rawType == EnumMap.class) { return null; } - private static ObjectConstructor newDefaultConstructor(Class rawType, FilterResult filterResult) { + private static ObjectConstructor newDefaultConstructor(MainConstructor mainConstructor, Gson gson, Class rawType, FilterResult filterResult) { // Cannot invoke constructor of abstract class if (Modifier.isAbstract(rawType.getModifiers())) { return null; @@ -180,7 +181,7 @@ private static ObjectConstructor newDefaultConstructor(Class r } } - return new ReflectCreatorConstructor<>(rawType, constructor); + return new ReflectCreatorConstructor<>(mainConstructor, gson, rawType, constructor); } /** @@ -228,9 +229,9 @@ private static ObjectConstructor newDefaultImplementationConstructor( return null; } - private ObjectConstructor newUnsafeAllocator(final Class rawType) { + private ObjectConstructor newUnsafeAllocator(Gson gson, final Class rawType) { if (mUseJdkUnsafe) { - return new ReflectSafeCreatorConstructor<>(rawType); + return new ReflectSafeCreatorConstructor<>(this, gson, rawType); } else { final String exceptionMessage = "Unable to create instance of " + rawType + "; usage of JDK Unsafe " + "is disabled. Registering an InstanceCreator or a TypeAdapter for this type, adding a no-args " diff --git a/library/src/main/java/com/hjq/gson/factory/constructor/ReflectCreatorConstructor.java b/library/src/main/java/com/hjq/gson/factory/constructor/ReflectCreatorConstructor.java index 98364e7..9334370 100644 --- a/library/src/main/java/com/hjq/gson/factory/constructor/ReflectCreatorConstructor.java +++ b/library/src/main/java/com/hjq/gson/factory/constructor/ReflectCreatorConstructor.java @@ -1,5 +1,6 @@ package com.hjq.gson.factory.constructor; +import com.google.gson.Gson; import com.google.gson.internal.ObjectConstructor; import com.google.gson.internal.reflect.ReflectionHelper; import java.lang.reflect.Constructor; @@ -17,9 +18,9 @@ public final class ReflectCreatorConstructor implements ObjectConstructor private final Constructor mConstructor; - public ReflectCreatorConstructor(Class rawType, Constructor constructor) { + public ReflectCreatorConstructor(MainConstructor mainConstructor, Gson gson, Class rawType, Constructor constructor) { mConstructor = constructor; - mKotlinDataClassDefaultValueConstructor = new KotlinDataClassDefaultValueConstructor<>(rawType); + mKotlinDataClassDefaultValueConstructor = new KotlinDataClassDefaultValueConstructor<>(mainConstructor, gson, rawType); } @SuppressWarnings("unchecked") diff --git a/library/src/main/java/com/hjq/gson/factory/constructor/ReflectSafeCreatorConstructor.java b/library/src/main/java/com/hjq/gson/factory/constructor/ReflectSafeCreatorConstructor.java index 3f609cf..f22a72a 100644 --- a/library/src/main/java/com/hjq/gson/factory/constructor/ReflectSafeCreatorConstructor.java +++ b/library/src/main/java/com/hjq/gson/factory/constructor/ReflectSafeCreatorConstructor.java @@ -1,5 +1,6 @@ package com.hjq.gson.factory.constructor; +import com.google.gson.Gson; import com.google.gson.internal.ObjectConstructor; import com.google.gson.internal.UnsafeAllocator; @@ -15,9 +16,9 @@ public final class ReflectSafeCreatorConstructor implements ObjectConstructor private final Class mRawType; - public ReflectSafeCreatorConstructor(Class rawType) { + public ReflectSafeCreatorConstructor(MainConstructor mainConstructor, Gson gson, Class rawType) { mRawType = rawType; - mKotlinDataClassDefaultValueConstructor = new KotlinDataClassDefaultValueConstructor<>(rawType); + mKotlinDataClassDefaultValueConstructor = new KotlinDataClassDefaultValueConstructor<>(mainConstructor, gson, rawType); } @SuppressWarnings("unchecked") diff --git a/library/src/main/java/com/hjq/gson/factory/element/CollectionTypeAdapterFactory.java b/library/src/main/java/com/hjq/gson/factory/element/CollectionTypeAdapterFactory.java index aad7772..2ec46b4 100644 --- a/library/src/main/java/com/hjq/gson/factory/element/CollectionTypeAdapterFactory.java +++ b/library/src/main/java/com/hjq/gson/factory/element/CollectionTypeAdapterFactory.java @@ -21,8 +21,8 @@ public class CollectionTypeAdapterFactory implements TypeAdapterFactory { private final MainConstructor mMainConstructor; - public CollectionTypeAdapterFactory(MainConstructor constructor) { - mMainConstructor = constructor; + public CollectionTypeAdapterFactory(MainConstructor mainConstructor) { + mMainConstructor = mainConstructor; } @SuppressWarnings({"unchecked", "rawtypes"}) @@ -46,7 +46,7 @@ public TypeAdapter create(Gson gson, TypeToken typeToken) { Type elementType = $Gson$Types.getCollectionElementType(type, rawType); TypeAdapter elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType)); - ObjectConstructor constructor = mMainConstructor.get(typeToken); + ObjectConstructor constructor = mMainConstructor.get(gson, typeToken); // create() doesn't define a type parameter CollectionTypeAdapter collectionTypeAdapter = diff --git a/library/src/main/java/com/hjq/gson/factory/element/MapTypeAdapterFactory.java b/library/src/main/java/com/hjq/gson/factory/element/MapTypeAdapterFactory.java index b9d59da..9223ce3 100644 --- a/library/src/main/java/com/hjq/gson/factory/element/MapTypeAdapterFactory.java +++ b/library/src/main/java/com/hjq/gson/factory/element/MapTypeAdapterFactory.java @@ -42,7 +42,7 @@ public TypeAdapter create(Gson gson, TypeToken typeToken) { Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(type, rawTypeOfSrc); TypeAdapter keyAdapter = getKeyAdapter(gson, keyAndValueTypes[0]); TypeAdapter valueAdapter = gson.getAdapter(TypeToken.get(keyAndValueTypes[1])); - ObjectConstructor constructor = mMainConstructor.get(typeToken); + ObjectConstructor constructor = mMainConstructor.get(gson, typeToken); // we don't define a type parameter for the key or value types MapTypeAdapter result = new MapTypeAdapter(gson, keyAndValueTypes[0], keyAdapter, diff --git a/library/src/main/java/com/hjq/gson/factory/element/ReflectiveTypeAdapterFactory.java b/library/src/main/java/com/hjq/gson/factory/element/ReflectiveTypeAdapterFactory.java index 6365793..0ed04a1 100644 --- a/library/src/main/java/com/hjq/gson/factory/element/ReflectiveTypeAdapterFactory.java +++ b/library/src/main/java/com/hjq/gson/factory/element/ReflectiveTypeAdapterFactory.java @@ -29,9 +29,9 @@ public class ReflectiveTypeAdapterFactory implements TypeAdapterFactory { private final FieldNamingStrategy mFieldNamingPolicy; private final Excluder mExcluder; - public ReflectiveTypeAdapterFactory(MainConstructor constructor, + public ReflectiveTypeAdapterFactory(MainConstructor mainConstructor, FieldNamingStrategy strategy, Excluder excluder) { - mMainConstructor = constructor; + mMainConstructor = mainConstructor; mFieldNamingPolicy = strategy; mExcluder = excluder; } @@ -72,7 +72,7 @@ public TypeAdapter create(Gson gson, final TypeToken type) { return null; } ReflectiveTypeAdapter reflectiveTypeAdapter = - new ReflectiveTypeAdapter<>(mMainConstructor.get(type), getBoundFields(gson, type, raw)); + new ReflectiveTypeAdapter<>(mMainConstructor.get(gson, type), getBoundFields(gson, type, raw)); reflectiveTypeAdapter.setReflectiveType(type, null); return reflectiveTypeAdapter; } diff --git a/library/src/main/java/com/hjq/gson/factory/element/ReflectiveTypeUtils.java b/library/src/main/java/com/hjq/gson/factory/element/ReflectiveTypeUtils.java index a1950b1..e341dfb 100644 --- a/library/src/main/java/com/hjq/gson/factory/element/ReflectiveTypeUtils.java +++ b/library/src/main/java/com/hjq/gson/factory/element/ReflectiveTypeUtils.java @@ -86,12 +86,12 @@ public static boolean containsClass(Class clazz) { return TYPE_TOKENS.contains(clazz); } - public static ReflectiveFieldBound createBoundField(final Gson gson, final MainConstructor constructor, final Field field, final String fieldName, + public static ReflectiveFieldBound createBoundField(final Gson gson, final MainConstructor mainConstructor, final Field field, final String fieldName, final TypeToken fieldType, boolean serialize, boolean deserialize) { return new ReflectiveFieldBound(fieldName, serialize, deserialize) { - final TypeAdapter typeAdapter = getFieldAdapter(gson, constructor, field, fieldType, fieldName); + final TypeAdapter typeAdapter = getFieldAdapter(gson, mainConstructor, field, fieldType, fieldName); @SuppressWarnings({"unchecked", "rawtypes"}) @Override @@ -128,11 +128,11 @@ public boolean writeField(Object value) throws IOException, IllegalAccessExcepti }; } - public static TypeAdapter getFieldAdapter(Gson gson, MainConstructor constructor, Field field, TypeToken fieldType, String fieldName) { + public static TypeAdapter getFieldAdapter(Gson gson, MainConstructor mainConstructor, Field field, TypeToken fieldType, String fieldName) { TypeAdapter adapter = null; JsonAdapter annotation = field.getAnnotation(JsonAdapter.class); if (annotation != null) { - adapter = getTypeAdapter(constructor, gson, fieldType, annotation); + adapter = getTypeAdapter(mainConstructor, gson, fieldType, annotation); } if (adapter == null) { adapter = gson.getAdapter(fieldType); @@ -149,7 +149,7 @@ public static TypeAdapter getFieldAdapter(Gson gson, MainConstructor construc return adapter; } - public static TypeAdapter getTypeAdapter(MainConstructor constructor, + public static TypeAdapter getTypeAdapter(MainConstructor mainConstructor, Gson gson, TypeToken fieldType, JsonAdapter annotation) { @@ -158,10 +158,10 @@ public static TypeAdapter getTypeAdapter(MainConstructor constructor, if (TypeAdapter.class.isAssignableFrom(value)) { Class> typeAdapterClass = (Class>) value; - typeAdapter = constructor.get(TypeToken.get(typeAdapterClass)).construct(); + typeAdapter = mainConstructor.get(gson, TypeToken.get(typeAdapterClass)).construct(); } else if (TypeAdapterFactory.class.isAssignableFrom(value)) { Class typeAdapterFactory = (Class) value; - typeAdapter = constructor.get(TypeToken.get(typeAdapterFactory)) + typeAdapter = mainConstructor.get(gson, TypeToken.get(typeAdapterFactory)) .construct() .create(gson, fieldType); } else {