Skip to content

Commit 2ff7b2b

Browse files
authored
Kudos add android JsonReader support (#15)
* MOD: gitignore * Kudos add android JsonReader support (#13) * ADD: Kudos support JsonReader * ADD: KudosJsonAdapter FIR Support * MOD: Modify naming and version * MOD: jsonReader support Float, Array, Set and Map Type * MOD: module and variable name * MOD: upgrade kotlin-compile-testing-extensions * MOD: Improve empty safety test cases * ADD: jsonReader support null validator * ADD: JsonReader null validator testcase * ADD: Kudos function switch * MOD: throw exception when unkown annotation * Update Version and ReadeMe * Release 1.8.20-1.1.0 (#14)
1 parent 14d54b5 commit 2ff7b2b

File tree

67 files changed

+3282
-193
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+3282
-193
lines changed

.github/scripts/tests.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,8 @@ do
2525
./gradlew :kudos-compiler:test -PJACKSON_VERSION=$jackson_version -PVARIANT=jackson -PKOTLIN_COMPILER=K2
2626
done
2727

28+
# Android JsonReader
29+
echo "[Kudos] Testing with Android JsonReader"
30+
./gradlew :kudos-compiler:test -PVARIANT=jsonReader -PKOTLIN_COMPILER=K2
31+
2832
cd -

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ build
22
.idea
33
.gradle
44
*.iml
5-
composite_build.local
5+
composite_build.local
6+
local.properties

README.md

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ English | **[简体中文](README_zh.md)**
66

77
# Kudos
88

9-
**Kudos** is short for **K**otlin **u**tilities for **d**eserializing **o**bjects. It is designed to make it safer and easier to deserializing Kotlin classes with Gson and Jackson.
9+
**Kudos** is short for **K**otlin **u**tilities for **d**eserializing **o**bjects. It is designed to make it safer and easier to deserializing Kotlin classes with Gson and Jackson. Moreover, it can also simplify the use of the high-performance deserialization framework, JsonReader.
1010

1111
## Background
12-
12+
### Null Safety and Default Values
1313
When parsing JSON using common JSON serialization frameworks, Kotlin developers often face issues with no-arg constructors and property null safety. Let's illustrate these issues with some examples.
1414

1515
```kotlin
@@ -99,6 +99,11 @@ Furthermore, Moshi is not always faster than Gson as benchmarks said. Most bench
9999

100100
We kept thinking, is there a way to provide null safety and default values support of the primary constructor parameters for frameworks like Gson? The answer is **Kudos**.
101101

102+
### Performance
103+
In actual use, it can be found that powerful frameworks like Gson, Moshi do not have great advantages in performance, while the system's native JsonReader has a clear edge in performance, especially during code cold start stages when it's not fully JIT optimized. However, JsonReader is costly to use, requiring developers to manually parse JSON, which is unfriendly for most developers.
104+
105+
For this reason, Kudos provides a simple way for developers to use JsonReader through a customized compiler plugin, while ensuring the functionality of type null safety and primary constructor parameter default values.
106+
102107
## Quick Start
103108

104109
### 1. Introduce Kudos into Gradle Projects
@@ -163,6 +168,8 @@ kudos {
163168
gson = true
164169
// Enable Kudos.Jackson. Add kudos-jackson to dependencies.
165170
jackson = true
171+
// Enable Kudos.AndroidJsonReader. Add kudos-android-json-reader to dependencies.
172+
androidJsonReader = true
166173
}
167174
````
168175

@@ -323,6 +330,18 @@ println(user) // User(id=12, name=Benny Huo, age=-1, tel=)
323330

324331
If the JSON lacks the `id` or `name` field, the parsing fails, ensuring that the properties of `User` is null safe.
325332

333+
The `Kudos` annotation also supports adding parameters like `KUDOS_GSON`, `KUDOS_JACKSON`, `KUDOS_ANDROID_JSON_READER`, to enable support for specific libraries, and also allows passing multiple parameters at the same time, for example:
334+
335+
```kotlin
336+
@Kudos(KUDOS_GSON, KUDOS_ANDROID_JSON_READER)
337+
data class User(
338+
val id: Long,
339+
val name: String,
340+
val age: Int = -1,
341+
val tel: String = ""
342+
)
343+
```
344+
326345
### 4. Collections
327346

328347
Properties of collection types declared in classes annotated with @Kudos, such as `List` or `Set`, will be handled carefully in the `validate` function to ensure the null safety for their elements. However, if the type to be parsed is like `List<User>`, Kudos will not be able to provide null safety guarantees at runtime because it cannot obtain whether the element type is nullable.
@@ -344,12 +363,25 @@ The code of nullability check has been optimized carefully which is generated by
344363

345364
We also find out that Kudos.Gson performs better than Moshi on initializing. So it should be a better choice for low frequency deserialization scenarios with both performance(comparing to Moshi) and null safety(comparing to Gson).
346365

347-
| | small json | medium json | large json |
348-
|---------------|----------------|----------------|----------------|
349-
| Gson | 412,375 ns | 1,374,838 ns | 3,641,904 ns |
350-
| Kudos-Gson | 517,123 ns | 1,686,568 ns | 4,311,910 ns |
351-
| Jackson | 1,035,010 ns | 1,750,709 ns | 3,450,974 ns |
352-
| Kudos-Jackson | 1,261,026 ns | 2,030,874 ns | 3,939,600 ns |
366+
### Multi-run test results
367+
| | small json | medium json | large json |
368+
|------------------|----------------|----------------|----------------|
369+
| Gson | 412,375 ns | 1,374,838 ns | 3,641,904 ns |
370+
| Kudos-Gson | 517,123 ns | 1,686,568 ns | 4,311,910 ns |
371+
| Jackson | 1,035,010 ns | 1,750,709 ns | 3,450,974 ns |
372+
| Kudos-Jackson | 1,261,026 ns | 2,030,874 ns | 3,939,600 ns |
373+
| JsonReader | 190,302 ns | 1,176,479 ns | 3,464,174 ns |
374+
| Kudos-JsonReader | 215,974 ns | 1,359,587 ns | 4,019,024 ns |
375+
376+
### One-run test results
377+
| | small json | medium json | large json |
378+
|------------------|-----------------|-----------------|-----------------|
379+
| Gson | 3,974,219 ns | 4,666,927 ns | 8,271,355 ns |
380+
| Kudos-Gson | 4,531,718 ns | 6,244,479 ns | 11,160,782 ns |
381+
| Jackson | 12,821,094 ns | 13,930,625 ns | 15,989,791 ns |
382+
| Kudos-Jackson | 13,233,750 ns | 15,674,010 ns | 18,641,302 ns |
383+
| JsonReader | 662,032 ns | 2,056,666 ns | 4,624,687 ns |
384+
| Kudos-JsonReader | 734,907 ns | 2,362,010 ns | 6,212,917 ns |
353385

354386
For more detail, see [https://github.com/RicardoJiang/json-benchmark](https://github.com/RicardoJiang/json-benchmark)
355387

README_zh.md

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66

77
# Kudos
88

9-
**Kudos****K**otlin **u**tilities for **d**eserializing **o**bjects 的缩写。它可以解决使用 Gson、Jackson 等框架反序列化 JSON 到 Kotlin 类时所存在的空安全问题和构造器默认值失效的问题。
9+
**Kudos****K**otlin **u**tilities for **d**eserializing **o**bjects 的缩写。它可以解决使用 Gson、Jackson 等框架反序列化 JSON 到 Kotlin 类时所存在的空安全问题和构造器默认值失效的问题,同时可以简化高性能的反序列化框架 JsonReader 的使用方式
1010

1111
## 问题背景
12-
12+
### 空安全与默认值问题
1313
在使用常见的 JSON 序列化框架解析 JSON 时,Kotlin 开发者通常会面临无参构造器和属性空安全的问题。接下来我们通过举例来具体说明这几个问题。
1414

1515
```kotlin
@@ -99,6 +99,11 @@ User(id=12, name=Benny Huo, age=0, tel=null)
9999

100100
我们当时就一直在想,有没有什么办法为 Gson 这样的框架提供类型空安全和支持主构造器的参数默认值的能力呢?答案就是 **Kudos**
101101

102+
### 性能问题
103+
在实际使用中可以发现,Gson, Moshi 等功能强大的框架在性能上并没有很大优势,而系统原生的 JsonReader 在性能上却有着明显的优势,尤其是在冷启动阶段代码未经过充分 JIT 优化时。但是,JsonReader 的使用成本很高,需要开发者自己手动解析 JSON ,这对于大部分开发者来说是不友好的。
104+
105+
为此,Kudos 通过自定义编译器插件的方式,为开发者提供了一种简单的方式来使用 JsonReader,同时保证了类型空安全和主构造器参数默认值的功能。
106+
102107
## 快速上手
103108

104109
### 1. 将 Kudos 集成到 Gradle 项目中
@@ -163,6 +168,8 @@ kudos {
163168
gson = true
164169
// 启用 Kudos.Jackson. 添加 kudos-jackson 依赖.
165170
jackson = true
171+
// 启用 Kudos.AndroidJsonReader. 添加 kudos-android-json-reader 依赖.
172+
androidJsonReader = true
166173
}
167174
````
168175

@@ -177,6 +184,9 @@ com.kanyun.kudos:kudos-gson
177184

178185
// 仅当启用 Kudos.Jackson 时
179186
com.kanyun.kudos:kudos-jackson
187+
188+
// 仅当启用 Kudos.AndroidJsonReader 时
189+
com.kanyun.kudos:kudos-android-json-reader
180190
```
181191
182192
当然,开发者也可以在合适的场景下手动引入这些依赖。
@@ -322,6 +332,18 @@ println(user) // User(id=12, name=Benny Huo, age=-1, tel=)
322332

323333
如果 JSON 中缺少 id 或者 name 字段,则解析失败,确保 User 属性的类型空安全。
324334

335+
`Kudos`注解也支持添加`KUDOS_GSON`, `KUDOS_JACKSON`, `KUDOS_ANDROID_JSON_READER`等参数, 开启对指定库的支持, 也支持同时传递多个参数,例如:
336+
337+
```kotlin
338+
@Kudos(KUDOS_GSON, KUDOS_ANDROID_JSON_READER)
339+
data class User(
340+
val id: Long,
341+
val name: String,
342+
val age: Int = -1,
343+
val tel: String = ""
344+
)
345+
```
346+
325347
### 4. 集合类型的支持
326348

327349
`@Kudos` 标注的类的属性类型如果是集合类型,包括 `List``Set` 等,解析之后会在 `validate` 函数中校验元素是否为 `null` 来确保类型空安全。但如果要解析的类型是 `List<User>`,Kudos 在运行时会因为无法获取到元素类型是否可空而无法提供类型空安全的保证。
@@ -343,12 +365,25 @@ val list = kudosGson().fromJson("""[null]""", typeOf<KudosList<User>>().javaType
343365

344366
在解析 JSON 时,考虑到冷启动的初始化耗时的情况,Kudos.Gson 比 Moshi 在大部分测试下性能更优(只有在多次解析同一数据类型时 Moshi 性能表现更好),因此 Kudos.Gson 在低频次的 JSON 解析场景下兼具了运行性能(优于 Moshi)和数据安全(优于 Gson)的优点。
345367

346-
| | small json | medium json | large json |
347-
|---------------|----------------|----------------|----------------|
348-
| Gson | 412,375 ns | 1,374,838 ns | 3,641,904 ns |
349-
| Kudos-Gson | 517,123 ns | 1,686,568 ns | 4,311,910 ns |
350-
| Jackson | 1,035,010 ns | 1,750,709 ns | 3,450,974 ns |
351-
| Kudos-Jackson | 1,261,026 ns | 2,030,874 ns | 3,939,600 ns |
368+
### 多次运行测试结果
369+
| | small json | medium json | large json |
370+
|------------------|----------------|----------------|----------------|
371+
| Gson | 412,375 ns | 1,374,838 ns | 3,641,904 ns |
372+
| Kudos-Gson | 517,123 ns | 1,686,568 ns | 4,311,910 ns |
373+
| Jackson | 1,035,010 ns | 1,750,709 ns | 3,450,974 ns |
374+
| Kudos-Jackson | 1,261,026 ns | 2,030,874 ns | 3,939,600 ns |
375+
| JsonReader | 190,302 ns | 1,176,479 ns | 3,464,174 ns |
376+
| Kudos-JsonReader | 215,974 ns | 1,359,587 ns | 4,019,024 ns |
377+
378+
### 一次运行测试结果
379+
| | small json | medium json | large json |
380+
|------------------|-----------------|-----------------|-----------------|
381+
| Gson | 3,974,219 ns | 4,666,927 ns | 8,271,355 ns |
382+
| Kudos-Gson | 4,531,718 ns | 6,244,479 ns | 11,160,782 ns |
383+
| Jackson | 12,821,094 ns | 13,930,625 ns | 15,989,791 ns |
384+
| Kudos-Jackson | 13,233,750 ns | 15,674,010 ns | 18,641,302 ns |
385+
| JsonReader | 662,032 ns | 2,056,666 ns | 4,624,687 ns |
386+
| Kudos-JsonReader | 734,907 ns | 2,362,010 ns | 6,212,917 ns |
352387

353388
更多细节可见:[https://github.com/RicardoJiang/json-benchmark](https://github.com/RicardoJiang/json-benchmark)
354389

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright (C) 2023 Kanyun, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
plugins {
17+
java
18+
kotlin("jvm")
19+
}
20+
21+
dependencies {
22+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
POM_NAME=android-json-reader

0 commit comments

Comments
 (0)