mirror of
https://github.com/HighCapable/moshi-companion.git
synced 2026-02-04 12:17:10 +08:00
209 lines
8.9 KiB
Markdown
209 lines
8.9 KiB
Markdown
# Moshi Companion Documentation
|
|
|
|

|
|
|
|
Before you start using it, it is recommended that you read this document carefully so that you can better understand how it works and its functions.
|
|
|
|
You can find the demo in samples in the root directory of the project, and refer to this document for better use.
|
|
|
|
## Before You Begin
|
|
|
|
The main function of this project is to provide companion features for [Moshi](https://github.com/square/moshi). The core functionality depends on the
|
|
Moshi project core. You need to use Moshi's `moshi-kotlin` and `moshi-kotlin-codegen` dependencies to generate adapter classes.
|
|
|
|
The purpose of this project is to generate "Entity Class → Adapter Class" mappings for the adapter classes generated by `moshi-kotlin-codegen` and
|
|
register them to the `AdapterRegistry`, then create a custom `JsonAdapter` and set it to the `Moshi.Builder`. This avoids Moshi using `Class.forName`
|
|
reflection to find adapter classes, achieving complete obfuscation of entity class names and fields, while improving performance from O(n) to O(1).
|
|
|
|
This project primarily focuses on Android projects but can still be used in pure Kotlin/Java projects.
|
|
|
|
## Quick Start
|
|
|
|
First, add dependencies to your Android/Kotlin/Java project. We recommend using Gradle's Version Catalog feature to manage dependency versions:
|
|
|
|
> `gradle/libs.versions.toml`
|
|
|
|
```toml
|
|
[versions]
|
|
agp = "8.13.0"
|
|
# Kotlin related dependency versions can be obtained from https://kotlinlang.org/docs/releases.html
|
|
kotlin = "2.2.20"
|
|
ksp = "2.2.20-2.0.3"
|
|
# Moshi version is recommended to use the version provided by Moshi GitHub README
|
|
moshi = "1.15.2"
|
|
moshi-companion = "<version>"
|
|
|
|
[plugins]
|
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
|
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
|
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
|
kotlin-ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
|
|
|
[libraries]
|
|
moshi-kotlin = { module = "com.squareup.moshi:moshi-kotlin", version.ref = "moshi" }
|
|
moshi-kotlin-codegen = { module = "com.squareup.moshi:moshi-kotlin-codegen", version.ref = "moshi" }
|
|
moshi-companion-api = { module = "com.highcapable.moshi.companion:companion-api", version.ref = "moshi-companion" }
|
|
moshi-companion-codegen = { module = "com.highcapable.moshi.companion:companion-codegen", version.ref = "moshi-companion" }
|
|
```
|
|
|
|
Replace the above `<version>` with the latest version number shown at the top.
|
|
|
|
Then, add the following configuration to your Gradle project configuration file `build.gradle` or `build.gradle.kts` where you need to use Moshi:
|
|
|
|
```kotlin
|
|
plugins {
|
|
// For Android projects
|
|
alias(libs.plugins.android.application)
|
|
alias(libs.plugins.kotlin.android)
|
|
// KSP
|
|
alias(libs.plugins.kotlin.ksp)
|
|
}
|
|
|
|
dependencies {
|
|
// Moshi related dependencies
|
|
implementation(libs.moshi.kotlin)
|
|
ksp(libs.moshi.kotlin.codegen)
|
|
|
|
// Moshi Companion related dependencies
|
|
implementation(libs.moshi.companion.api)
|
|
// Moshi Companion Codegen needs to be added after moshi-kotlin-codegen, please note the order
|
|
ksp(libs.moshi.companion.codegen)
|
|
}
|
|
```
|
|
|
|
Then we need to ensure that Moshi's ProGuard rules generation is disabled, as ProGuard rules are now managed by Moshi Companion.
|
|
|
|
```kotlin
|
|
ksp {
|
|
arg("moshi.generateProguardRules", "false")
|
|
}
|
|
```
|
|
|
|
If you don't disable Moshi's ProGuard rules generation, Moshi Companion will throw an exception at compile time prompting you to make corrections.
|
|
|
|
At this point, you have completed the dependency addition and configuration of Moshi Companion. If you are adding Moshi Companion to an existing
|
|
project that uses Moshi, you only need to introduce the `moshi-companion-api` and `moshi-companion-codegen` dependencies from the steps above and add
|
|
the configuration to disable ProGuard rules generation.
|
|
|
|
## Registering Adapters
|
|
|
|
Moshi Companion generates `AdapterRegistry` by reading all classes in the project that use the `@JsonClass(generateAdapter = true)` annotation. You
|
|
need to manually register these adapters through `Moshi.Builder` at runtime.
|
|
|
|
After performing a Gradle build, Moshi Companion will generate an `AdapterRegistry` class in the `build/generated/ksp` directory of the project. The
|
|
default generated format uses a unique package name found with the `@JsonClass(generateAdapter = true)` annotation, converts this package name to a
|
|
16-character hash as the unique identifier for the current module, and generates a package name in the following format:
|
|
|
|
```
|
|
com.highcapable.moshi.companion.r + 16-character hash + generated
|
|
```
|
|
|
|
Such as:
|
|
|
|
```
|
|
com.highcapable.moshi.companion.r1dd1c7f2a95790d7.generated
|
|
```
|
|
|
|
The class name of `AdapterRegistry` is fixed as `DefaultMoshiAdapterRegistry` and implements the `AdapterRegistry` interface.
|
|
|
|
When using Moshi, you can very simply use the extension function `addRegistry` to register this generated class to `Moshi.Builder`:
|
|
|
|
```kotlin
|
|
val moshi = Moshi.Builder()
|
|
.addRegistry(DefaultMoshiAdapterRegistry())
|
|
.build()
|
|
```
|
|
|
|
Then, you can happily continue using Moshi for JSON serialization and deserialization, completely unaffected by R8's obfuscation and optimization.
|
|
Class names can be safely obfuscated, reducing size, minimizing reflection, and reducing exposure risks.
|
|
|
|
## Advanced Usage
|
|
|
|
If you need to customize the class name and package name of `AdapterRegistry`, you can achieve this by adding the following KSP parameters in
|
|
`build.gradle` or `build.gradle.kts`:
|
|
|
|
```kotlin
|
|
ksp {
|
|
// Customize the package name of AdapterRegistry, if it's an Android project, it's recommended to directly use "android.namespace"
|
|
arg("moshi-companion.generateAdapterRegistryPackageName", "com.yourdomain.yourpackage")
|
|
// Customize the class name of AdapterRegistry
|
|
arg("moshi-companion.generateAdapterRegistryClassName", "YourCustomMoshiAdapterRegistry")
|
|
}
|
|
```
|
|
|
|
Such as:
|
|
|
|
```
|
|
com.yourdomain.yourpackage.generated.YourCustomMoshiAdapterRegistry
|
|
```
|
|
|
|
If you maintain a modular project focused on data models, we recommend fixing the generated `AdapterRegistry` package name and class name as shown in
|
|
the example above to prevent automatically generated content from not meeting your project requirements.
|
|
|
|
If you need to generate an `AdapterRegistry` that is only accessible to the current project, you can achieve this by adding the following KSP
|
|
parameter:
|
|
|
|
```kotlin
|
|
ksp {
|
|
arg("moshi-companion.generateAdapterRegistryRestrictedAccess", "true")
|
|
}
|
|
```
|
|
|
|
This way, the generated `AdapterRegistry` class will be set to `internal` and can only be accessed within the current module, avoiding misuse or abuse
|
|
by other projects.
|
|
|
|
Moshi Companion's automatically generated ProGuard rules include obfuscation protection for Enum class key values. By default, only class names are
|
|
obfuscated.
|
|
|
|
Please note that Moshi's default behavior is to not obfuscate Enum classes only when they are annotated with `@JsonClass(generateAdapter = false)`.
|
|
When using Moshi Companion, all Enum classes will be protected from obfuscation.
|
|
|
|
If you don't need this feature, you can disable it by adding the following KSP parameter (not recommended to disable):
|
|
|
|
```kotlin
|
|
ksp {
|
|
arg("moshi-companion.proguardRulesKeepEnumClasses", "false")
|
|
}
|
|
```
|
|
|
|
If you don't want Moshi Companion to automatically generate any ProGuard rules, you can also disable it by adding the following KSP parameter (not
|
|
recommended to disable):
|
|
|
|
```kotlin
|
|
ksp {
|
|
arg("moshi-companion.generateProguardRules", "false")
|
|
}
|
|
```
|
|
|
|
## Extension API
|
|
|
|
Moshi Companion provides the `typeAdapter` extension feature to simplify `Types.newParameterizedType`.
|
|
The core content is implemented using the `TypeRef` feature of the [KavaRef](https://github.com/HighCapable/KavaRef) project.
|
|
|
|
```kotlin
|
|
val adapter = moshi.typeAdapter<List<YourDataClass>>()
|
|
// Compare with the original approach
|
|
val type = Types.newParameterizedType(List::class.java, YourDataClass::class.java)
|
|
val adapter = moshi.adapter<List<YourDataClass>>(type)
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
If you haven't disabled Moshi Companion's ProGuard rules generation, but the ProGuard rules are not included in `shrink-rules`, you can check the
|
|
generated `configuration.txt` file after R8 finishes to see if it contains "JsonAdapter".
|
|
|
|
Currently in Android projects, this issue may occur in the main project module (e.g., "app"). If the ProGuard rules don't take effect, please check if
|
|
there are rule files under `build/generated/ksp/release/resources/META-INF/proguard/`. If they exist, please add the following configuration in the
|
|
`buildTypes` section of `build.gradle.kts`:
|
|
|
|
```kotlin
|
|
release {
|
|
isMinifyEnabled = true
|
|
|
|
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
|
// Specify the ProGuard rules file generated by Moshi Companion
|
|
file("build/generated/ksp/release/resources/META-INF/proguard/").listFiles()?.firstOrNull()?.let {
|
|
proguardFiles += it
|
|
}
|
|
}
|
|
``` |