Showing preview only (1,265K chars total). Download the full file or copy to clipboard to get everything.
Repository: square/moshi
Branch: master
Commit: 2d8a3cc7112f
Files: 183
Total size: 1.2 MB
Directory structure:
gitextract_wxuqnsxb/
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── config.yml
│ │ └── feature_request.md
│ ├── renovate.json5
│ └── workflows/
│ ├── .java-version
│ ├── build.yml
│ └── release.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.txt
├── README.md
├── build.gradle.kts
├── examples/
│ ├── build.gradle.kts
│ └── src/
│ └── main/
│ └── java/
│ └── com/
│ └── squareup/
│ └── moshi/
│ └── recipes/
│ ├── ByteStrings.java
│ ├── CardAdapter.java
│ ├── CustomAdapterFactory.java
│ ├── CustomAdapterWithDelegate.java
│ ├── CustomFieldName.java
│ ├── CustomQualifier.java
│ ├── CustomTypeAdapter.java
│ ├── DefaultOnDataMismatchAdapter.java
│ ├── FallbackEnum.java
│ ├── FromJsonWithoutStrings.java
│ ├── IncludeNullsForAnnotatedTypes.java
│ ├── IncludeNullsForOneType.java
│ ├── JsonString.kt
│ ├── MultipleFormats.java
│ ├── ReadAndWriteRfc3339Dates.java
│ ├── ReadJson.java
│ ├── ReadJsonList.java
│ ├── ReadJsonListKt.kt
│ ├── RecoverFromTypeMismatch.java
│ ├── Unwrap.java
│ ├── WriteJson.java
│ ├── models/
│ │ ├── BlackjackHand.java
│ │ ├── Card.java
│ │ ├── Player.java
│ │ ├── Suit.java
│ │ └── Tournament.java
│ └── package-info.java
├── gradle/
│ ├── libs.versions.toml
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── moshi/
│ ├── build.gradle.kts
│ ├── gradle.properties
│ ├── japicmp/
│ │ └── build.gradle.kts
│ ├── records-tests/
│ │ ├── build.gradle.kts
│ │ └── src/
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── squareup/
│ │ └── moshi/
│ │ └── records/
│ │ └── RecordsTest.java
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── squareup/
│ │ │ └── moshi/
│ │ │ ├── -JsonUtf8Reader.kt
│ │ │ ├── -JsonUtf8Writer.kt
│ │ │ ├── -JsonValueReader.kt
│ │ │ ├── -JsonValueWriter.kt
│ │ │ ├── -MoshiKotlinExtensions.kt
│ │ │ ├── -MoshiKotlinTypesExtensions.kt
│ │ │ ├── FromJson.kt
│ │ │ ├── Json.kt
│ │ │ ├── JsonAdapter.kt
│ │ │ ├── JsonClass.kt
│ │ │ ├── JsonDataException.kt
│ │ │ ├── JsonEncodingException.kt
│ │ │ ├── JsonQualifier.kt
│ │ │ ├── JsonReader.kt
│ │ │ ├── JsonWriter.kt
│ │ │ ├── Moshi.kt
│ │ │ ├── ToJson.kt
│ │ │ ├── Types.kt
│ │ │ ├── internal/
│ │ │ │ ├── AdapterMethodsFactory.kt
│ │ │ │ ├── ArrayJsonAdapter.kt
│ │ │ │ ├── ClassFactory.kt
│ │ │ │ ├── ClassJsonAdapter.kt
│ │ │ │ ├── CollectionJsonAdapter.kt
│ │ │ │ ├── JsonScope.kt
│ │ │ │ ├── JsonValueSource.kt
│ │ │ │ ├── KotlinReflectTypes.kt
│ │ │ │ ├── LinkedHashTreeMap.kt
│ │ │ │ ├── MapJsonAdapter.kt
│ │ │ │ ├── NonNullJsonAdapter.kt
│ │ │ │ ├── NullSafeJsonAdapter.kt
│ │ │ │ ├── RecordJsonAdapter.kt
│ │ │ │ ├── StandardJsonAdapters.kt
│ │ │ │ └── Util.kt
│ │ │ └── package-info.java
│ │ ├── java16/
│ │ │ └── com/
│ │ │ └── squareup/
│ │ │ └── moshi/
│ │ │ └── internal/
│ │ │ └── RecordJsonAdapter.kt
│ │ └── resources/
│ │ └── META-INF/
│ │ └── proguard/
│ │ └── moshi.pro
│ └── test/
│ └── java/
│ ├── android/
│ │ └── util/
│ │ └── Pair.java
│ └── com/
│ └── squareup/
│ └── moshi/
│ ├── AdapterMethodsTest.java
│ ├── CircularAdaptersTest.java
│ ├── DeferredAdapterTest.java
│ ├── FlattenTest.java
│ ├── JsonAdapterTest.java
│ ├── JsonCodecFactory.java
│ ├── JsonQualifiersTest.java
│ ├── JsonReaderPathTest.java
│ ├── JsonReaderTest.java
│ ├── JsonUtf8ReaderTest.java
│ ├── JsonUtf8WriterTest.java
│ ├── JsonValueReaderTest.java
│ ├── JsonValueWriterTest.java
│ ├── JsonWriterPathTest.java
│ ├── JsonWriterTest.java
│ ├── KotlinExtensionsTest.kt
│ ├── MoshiTest.java
│ ├── MoshiTesting.kt
│ ├── ObjectAdapterTest.java
│ ├── PromoteNameToValueTest.java
│ ├── RecursiveTypesResolveTest.java
│ ├── TestUtil.java
│ ├── TypesTest.java
│ └── internal/
│ ├── ClassJsonAdapterTest.java
│ ├── JsonValueSourceTest.java
│ ├── KotlinReflectTypesTest.kt
│ ├── LinkedHashTreeMapTest.java
│ └── MapJsonAdapterTest.java
├── moshi-adapters/
│ ├── README.md
│ ├── build.gradle.kts
│ ├── japicmp/
│ │ └── build.gradle.kts
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── com/
│ │ └── squareup/
│ │ └── moshi/
│ │ ├── Rfc3339DateJsonAdapter.kt
│ │ └── adapters/
│ │ ├── EnumJsonAdapter.kt
│ │ ├── Iso8601Utils.kt
│ │ ├── PolymorphicJsonAdapterFactory.kt
│ │ └── Rfc3339DateJsonAdapter.kt
│ └── test/
│ └── java/
│ └── com/
│ └── squareup/
│ └── moshi/
│ └── adapters/
│ ├── EnumJsonAdapterTest.java
│ ├── PolymorphicJsonAdapterFactoryTest.java
│ └── Rfc3339DateJsonAdapterTest.java
├── moshi-kotlin/
│ ├── build.gradle.kts
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── squareup/
│ │ │ └── moshi/
│ │ │ ├── KotlinJsonAdapterFactory.kt
│ │ │ └── kotlin/
│ │ │ └── reflect/
│ │ │ ├── IndexedParameterMap.kt
│ │ │ ├── Invokable.kt
│ │ │ ├── JvmDescriptors.kt
│ │ │ ├── JvmSignatureSearcher.kt
│ │ │ ├── KmExecutable.kt
│ │ │ ├── KotlinJsonAdapterFactory.kt
│ │ │ └── KtTypes.kt
│ │ └── resources/
│ │ └── META-INF/
│ │ └── com.android.tools/
│ │ ├── proguard/
│ │ │ └── moshi-metadata-reflect.pro
│ │ ├── r8-from-1.6.0/
│ │ │ └── moshi-metadata-reflect.pro
│ │ └── r8-upto-1.6.0/
│ │ └── moshi-metadata-reflect.pro
│ └── test/
│ └── java/
│ └── com/
│ └── squareup/
│ └── moshi/
│ └── kotlin/
│ └── reflect/
│ └── KotlinJsonAdapterTest.kt
├── moshi-kotlin-codegen/
│ ├── build.gradle.kts
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── com/
│ │ └── squareup/
│ │ └── moshi/
│ │ └── kotlin/
│ │ └── codegen/
│ │ ├── api/
│ │ │ ├── AdapterGenerator.kt
│ │ │ ├── DelegateKey.kt
│ │ │ ├── InternalMoshiCodegenApi.kt
│ │ │ ├── Options.kt
│ │ │ ├── ProguardRules.kt
│ │ │ ├── PropertyGenerator.kt
│ │ │ ├── TargetConstructor.kt
│ │ │ ├── TargetParameter.kt
│ │ │ ├── TargetProperty.kt
│ │ │ ├── TargetType.kt
│ │ │ ├── TypeRenderer.kt
│ │ │ ├── kotlintypes.kt
│ │ │ └── typeAliasUnwrapping.kt
│ │ └── ksp/
│ │ ├── AppliedType.kt
│ │ ├── JsonClassSymbolProcessorProvider.kt
│ │ ├── KspUtil.kt
│ │ ├── MoshiApiUtil.kt
│ │ ├── TargetTypes.kt
│ │ └── shadedUtil.kt
│ └── test/
│ └── java/
│ └── com/
│ └── squareup/
│ └── moshi/
│ └── kotlin/
│ └── codegen/
│ ├── JavaSuperclass.java
│ └── ksp/
│ └── JsonClassSymbolProcessorTest.kt
├── moshi-kotlin-tests/
│ ├── build.gradle.kts
│ ├── codegen-only/
│ │ ├── build.gradle.kts
│ │ └── src/
│ │ └── test/
│ │ └── kotlin/
│ │ └── com/
│ │ └── squareup/
│ │ └── moshi/
│ │ └── kotlin/
│ │ └── codegen/
│ │ ├── CompileOnlyTests.kt
│ │ ├── ComplexGenericsInheritanceTest.kt
│ │ ├── DefaultConstructorTest.kt
│ │ ├── GeneratedAdaptersTest.kt
│ │ ├── GeneratedAdaptersTest_CustomGeneratedClassJsonAdapter.kt
│ │ ├── LooksLikeAClass/
│ │ │ └── ClassInPackageThatLooksLikeAClass.kt
│ │ ├── MixingReflectAndCodeGen.kt
│ │ ├── MoshiKspTest.kt
│ │ ├── MultipleMasksTest.kt
│ │ └── annotation/
│ │ └── UppercaseInAnnotationPackage.kt
│ ├── extra-moshi-test-module/
│ │ ├── build.gradle.kts
│ │ └── src/
│ │ └── main/
│ │ └── kotlin/
│ │ └── com/
│ │ └── squareup/
│ │ └── moshi/
│ │ └── kotlin/
│ │ └── codegen/
│ │ └── test/
│ │ └── extra/
│ │ └── AbstractClassInModuleA.kt
│ └── src/
│ └── test/
│ └── kotlin/
│ └── com/
│ └── squareup/
│ └── moshi/
│ └── kotlin/
│ ├── DualKotlinTest.kt
│ └── reflect/
│ └── KotlinJsonAdapterTest.kt
├── releasing.md
└── settings.gradle.kts
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length=100
[*.{kt, kts}]
kotlin_imports_layout = ascii
================================================
FILE: .gitattributes
================================================
* text=auto eol=lf
*.bat text eol=crlf
*.jar binary
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: A reproducible problem
title: ''
labels: bug
assignees: ''
---
Good bug reports include a failing test! Writing a test helps you to isolate and describe the problem, and it helps us to fix it fast. Bug reports without a failing test or reproduction steps are likely to be closed.
Here’s an example test to get you started.
https://gist.github.com/ZacSweers/0ef2c5f0e3f61f82063dd8c67d75879f
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Question?
url: https://stackoverflow.com/questions/tagged/moshi
about: Please ask usage questions on Stack Overflow with the `moshi` tag.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea
title: ''
labels: enhancement
assignees: ''
---
Start by telling us what problem you’re trying to solve. Often a solution already exists!
Don’t send pull requests to implement new features without first getting our support. Sometimes we leave features out on purpose to keep the project small.
================================================
FILE: .github/renovate.json5
================================================
{
$schema: 'https://docs.renovatebot.com/renovate-schema.json',
extends: [
'config:recommended',
],
ignorePresets: [
// Ensure we get the latest version and are not pinned to old versions.
'workarounds:javaLTSVersions',
],
customManagers: [
// Update .java-version file with the latest JDK version.
{
customType: 'regex',
fileMatch: [
'\\.java-version$',
],
matchStrings: [
'(?<currentValue>.*)\\n',
],
datasourceTemplate: 'java-version',
depNameTemplate: 'java',
// Only write the major version.
extractVersionTemplate: '^(?<version>\\d+)',
},
]
}
================================================
FILE: .github/workflows/.java-version
================================================
25
================================================
FILE: .github/workflows/build.yml
================================================
name: CI
on: [push, pull_request]
jobs:
build:
name: 'Test Mode ${{ matrix.kotlin-test-mode }}'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
kotlin-test-mode: [ 'REFLECT', 'KSP' ]
steps:
- name: Checkout
uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version-file: .github/workflows/.java-version
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5
- name: Test
run: ./gradlew build check --stacktrace -PkotlinTestMode=${{ matrix.kotlin-test-mode }}
- name: Publish (default branch only)
if: github.repository == 'square/moshi' && github.ref == 'refs/heads/master' && matrix.kotlin-test-mode == 'reflect'
run: ./gradlew publish
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_CENTRAL_USERNAME }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_CENTRAL_PASSWORD }}
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_SECRET_KEY }}
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_SECRET_PASSPHRASE }}
================================================
FILE: .github/workflows/release.yml
================================================
name: release
on:
push:
tags:
- '**'
jobs:
release:
runs-on: macos-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version-file: .github/workflows/.java-version
- uses: gradle/actions/setup-gradle@v5
- run: ./gradlew publish dokkaGenerate -PmavenCentralDeploymentValidation=PUBLISHED
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_CENTRAL_USERNAME }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_CENTRAL_PASSWORD }}
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_SECRET_KEY }}
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_SECRET_PASSPHRASE }}
- name: Extract release notes
id: release_notes
uses: ffurrer2/extract-release-notes@v3
- name: Create release
uses: softprops/action-gh-release@v2
with:
body: ${{ steps.release_notes.outputs.release_notes }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy docs to website
uses: JamesIves/github-pages-deploy-action@releases/v3
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: site
FOLDER: docs/2.x/
TARGET_FOLDER: docs/2.x/
CLEAN: true
================================================
FILE: .gitignore
================================================
.classpath
.project
.settings
eclipsebin
bin
gen
build
out
lib
target
pom.xml.*
release.properties
dependency-reduced-pom.xml
.idea
*.iml
*.ipr
*.iws
classes
obj
.DS_Store
.gradle
# Temporary until generating a docsite
docs/
================================================
FILE: CHANGELOG.md
================================================
# Change Log
## Unreleased
* None yet.
## [2.0.0-alpha.1] - 2026-01-28
* Refuse `j$.*` types from Android library desugaring as platform types.
* In-development snapshots are now published to the Central Portal Snapshots repository at https://central.sonatype.com/repository/maven-snapshots/.
* Fully supports encoding/decoding of value classes in both moshi-kotlin and code gen.
* Note that Moshi does not propagate inlining to JSON by default. For example: `@JvmInline value class Color(val raw: Int)` is serialized to `{"raw": 12345}`.
* New `@JsonClass.inline` property to allow inlining single-property JSON classes during encoding/decoding.
* This is particularly useful for value classes.
* For example, a class `@JvmInline value class UserId(val id: Int)` with `inline = true` will serialize as just `123` rather than `{"id": 123}`.
* `PolymorphicJsonAdapterFactory` now invokes the fallback adapter when the label key is missing entirely from the JSON, not just when the label value is unrecognized.
### Upgrading to Moshi 2.x
In 2.x, we upgraded Moshi’s source code from .java to .kt. This update is binary-compatible with
Moshi 1.x, and so you can safely upgrade without recompiling your libraries.
The update is not source-compatible for Kotlin users.
#### JsonAdapter.Factory MutableSet
Kotlin defines both a `Set` and a `MutableSet` type, but Java has only `Set`. Implementations of
Moshi’s `JsonAdapter.Factory` interface may declare a function that accepts a `MutableSet`:
```kotlin
override fun create(type: Type, annotations: MutableSet<out Annotation>, moshi: Moshi): JsonAdapter<*>? {
...
}
```
Moshi 2.x requires the `annotations` argument be a `Set`:
```kotlin
override fun create(type: Type, annotations: Set<out Annotation>, moshi: Moshi): JsonAdapter<*>? {
...
}
```
We used this shell script to migrate our code:
```shell
find . \
-name "*.kt" \
-exec sed -i "" 's/annotations: MutableSet<out Annotation>/annotations: Set<Annotation>/g' {} \;
```
#### Propagated Nullability in `JsonAdapter`
Previously, due to limitations of the Java type system, Moshi would always treat the type as
nullable. Kotlin's type system supports nullability natively, and Moshi now propagates nullability
information from the generic type of `JsonAdapter`.
- Calling `nullSafe()` on any `JsonAdapter` returns a `JsonAdapter<T?>` where `T` is the original type.
- Calling `nonNull()` on any `JsonAdapter` returns a `JsonAdapter<T & Any>` where `T` is the original type.
- Calling the reified `Moshi.adapter<T>()` function overloads returns a `JsonAdapter<T>` where `T` matches
and respects the nullability of the reified type.
- Calling the `Moshi.adapter(KType)` function overloads return a `JsonAdapter` that respects the
nullability of the `KType` but trusts that the caller specifies the correct nullability on the
generic type argument.
- Calling any of the other `Moshi.adapter()` functions (that accept either `Type`, `Class`, or
`KClass` types) always return nullable `JsonAdapter`s.
This is often going to be a source-breaking change for Kotlin users, but ABI-compatible. All of
Moshi's internals and code gen continue to function the same way.
#### Explicit Nullability
Moshi has functions like `JsonAdapter.fromJson(String)` that have always been _documented_ to
require non-null parameters. With Moshi 2.x that requirement is enforced by the compiler.
You may need to manually make parameters non-null (such as with `!!`) when you upgrade to Moshi 2.x.
#### Properties
We promoted `JsonWriter.setIndent()` to be a property. If you aren't already, you must use property
syntax:
```diff
val jsonWriter = JsonWriter.of(buffer)
- jsonWriter.setIndent(" ")
+ jsonWriter.indent = " "
```
#### moshi-kotlin-codegen
The KSP code generator now supports (and requires) KSP2.
#### moshi-kotlin
This release switches `KotlinJsonAdapterFactory` to use `kotlin-metadata` instead of `kotlin-reflect`. This is a lightweight alternative to kotlin-reflect and satisfies moshi-kotlin's requirements. It is also ~20% more performant at runtime.
* This is not a source or ABI breaking change but if you were relying on the transitive `kotlin-reflect` dependency you will need to add it explicitly.
* No longer encodes properties/fields from supertypes that are platform types.
## [1.15.2] - 2024-12-05
* Do not generate conditional shrinker rules (i.e., `-if`) when the rule is already predicated on the presence of the target type (as `-keepnames` and `-keepclassmembers` are).
This will improve shrinker performance for projects with hundreds of model types, as conditional rules are more expensive to evaluate.
## [1.15.1] - 2024-01-30
* Upgrade to Okio `3.7.0`
## [1.15.0] - 2023-05-12
* Upgrade to Kotlin `1.8.21`.
* Upgrade to KSP `1.8.21-1.0.11`.
* Upgrade to kotlinx-metadata `0.6.0`.
* Upgrade to KotlinPoet `1.13.2`.
* Support Kotlin language version `1.9.0` in KAPT.
* Include name of the type being processed when creating the adapterGenerator fails in KSP.
* Suppress `UNUSED_PARAMETER` in generated code.
* Deprecate KAPT code gen. Please migrate to KSP, we will remove KAPT support in a future release. This release will also print an annoying noisy warning in KAPT processing if you use it.
## [1.14.0] - 2022-09-06
* Upgrade: [Kotlin 1.7.0][kotlin_1_7_0].
* Upgrade [KotlinPoet 1.12.0][kotlinpoet_1_12_0].
* Moshi no longer shades kotlinpoet-ksp APIs, meaning they can be updated independently of Moshi updates.
* Upgrade: [KSP 1.7.0-1.0.6][ksp_1_7_0_1_0_6].
* Upgrade: [kotlinx-metadata 0.5.0][kotlinx_metadata_0_5_0], allowing reading of kotlin 1.8 APIs too.
## [1.13.0] - 2021-12-08
* New: Support for [Kotlin Symbol Processing (KSP)][ksp]. KSP is an alternative to annotation
processing code gen. It's builds faster and better supports Kotlin language features.
To use KSP in your application you must enable the KSP Gradle plugin and add a KSP dependency
on Moshi codegen.
```
plugins {
id("com.google.devtools.ksp").version("1.6.0-1.0.1")
}
dependencies {
ksp("com.squareup.moshi:moshi-kotlin-codegen:1.13.0")
}
```
If you're switching from annotation processing (kapt) to KSP, you should remove the kapt plugin
and the kapt Moshi dependency.
* New: `@Json(ignore = true)` is a Moshi-specific way to exclude properties from JSON encoding
and decoding.
* New: Support Java 16 records. (Moshi still requires Java 8 only; we're shipping a [multi-release
jar][mrjar] to better support modern JVMs.)
* New: Option to disable generating R8/ProGuard files. These files prevent code shrinkers from
removing files that support JSON processing. If you're not using ProGuard or R8, you can skip
this step.
```
ksp {
arg("moshi.generateProguardRules", "false")
}
```
* Upgrade: [Kotlin 1.6.0][kotlin_1_6_0].
## [1.12.0] - 2021-04-01
* New: Improve generated code performance when all properties are set.
* Fix: Don't crash on a missing type element like `@SuppressLint`.
* Fix: Update the JVM metadata library to avoid problems on Kotlin 1.5.0-M2.
* Fix: Support generic arrays with defaults in generated adapters.
* Fix: Don't generate code with simple name collisions.
* Upgrade: [Okio 2.10.0][okio_2_10_0].
* Upgrade: [Kotlin 1.4.31][kotlin_1_4_31].
## [1.11.0] - 2020-10-04
* New: Kotlin extension functions and properties. Use of these extensions is only possible from
Kotlin, and requires the Kotlin stdlib dependency. This release does not have any Kotlin
requirement and can be used Kotlin-free from Java.
```kotlin
/** Extension alternative to [Types.nextAnnotations()]. */
fun <reified T : Annotation> Set<Annotation>.nextAnnotations(): Set<Annotation>?
/** Extension alternative to [Types.getRawType()]. */
val Type.rawType: Class<*>
/** Extension alternative to [Types.arrayOf()]. */
fun KClass<*>.asArrayType(): GenericArrayType
/** Extension alternative to [Types.arrayOf()]. */
fun Type.asArrayType(): GenericArrayType
```
* New: Experimental Kotlin extensions. These depend on unreleased APIs and may break in a future
release of Kotlin. If you are comfortable with this, add `@ExperimentalStdlibApi` at the callsite
or add this argument to your Kotlin compiler: `"-Xopt-in=kotlin.ExperimentalStdlibApi"`.
```kotlin
/** Returns the adapter for [T]. */
inline fun <reified T> Moshi.adapter(): JsonAdapter<T>
/** Returns the adapter for [ktype]. */
fun <T> Moshi.adapter(ktype: KType): JsonAdapter<T>
/** Adds an adapter for [T]. */
inline fun <reified T> Moshi.Builder.addAdapter(adapter: JsonAdapter<T>): Moshi.Builder
/** Extension alternative to [Types.arrayOf()]. */
fun KType.asArrayType(): GenericArrayType
/** Extension alternative to [Types.subtypeOf()]. */
inline fun <reified T> subtypeOf(): WildcardType
/** Extension alternative to [Types.supertypeOf()]. */
inline fun <reified T> supertypeOf(): WildcardType
```
* New: `JsonReader.nextSource()`. This returns an Okio `BufferedSource` that streams the UTF-8
bytes of a JSON value. Use this to accept JSON values without decoding them, to delegate to
another JSON processor, or for streaming access to very large embedded values.
* New: `Moshi.Builder.addLast()`. Use this when installing widely-applicable adapter factories like
`KotlinJsonAdapterFactory`. Adapters registered with `add()` are preferred (in the order they
were added), followed by all adapters registered with `addLast()` (also in the order they were
added). This precedence is retained when `Moshi.newBuilder()` is used.
* New: `setTag()`, `tag()` methods on `JsonReader` and `JsonWriter`. Use these as a side-channel
between adapters and their uses. For example, a tag may be used to track use of unexpected
data in a custom adapter.
* Fix: Don't crash with a `StackOverflowError` decoding backward-referencing type variables in
Kotlin. This caused problems for parameterized types like `MyInterface<E : Enum<E>>`.
* Upgrade: [Okio 1.17.5][okio_1_7_5].
* Upgrade: [Kotlin 1.4.10][kotlin_1_4_10].
## [1.10.0] - 2020-08-26
* New: Upgrade to Kotlin 1.4.0.
* New: `JsonReader.promoteNameToValue()` makes it easier to build custom `Map` adapters.
* New: `Options.strings()`.
* New: `PolymorphicJsonAdapterFactory.withFallbackJsonAdapter()` makes it possible to handle
unrecognized types when encoding and decoding.
* New: Add `JsonWriter.jsonValue` API
* New: Code gen now generates precise proguard rules on-the-fly.
* New: Improve error when incorrectly trying to use a collection class like `ArrayList` instead of `List`
* Fix: Prevent R8 from keeping all `@Metadata` annotations
* Fix: Avoid VerifyErrors on Android 4.4 devices when using R8
* Fix: Fix resolution of types in superclass settable properties
## Version 1.9.3
_2020-06-11_
* Fix: Tweak a shrinker rule to mitigate an R8 bug which was causing classes unrelated to the Kotlin adpater code generation to be retained.
* Fix: Ensure that the Kotlin adapter code generation does not line wrap in the middle of a string if your JSON keys contain spaces.
* Fix: Strip type annotations before emitting type references like `Foo::class` in the Kotlin adapter code generation.
* Fix: Separate the runtime check for Kotlin's `DefaultConstructorMarker` from the check for `Metadata`. A shrinker may have removed `Metadata` and we should still check for `DefaultConstructorMarker`.
## Version 1.9.2
_2019-11-17_
* Fix: Generate correct adapters for several special cases including reified inline types, public
classes enclosed in internal classes, deprecated types with `-Werror`, primitives in type
parameters, nullables in type parameters, and type aliases in type parameters.
## Version 1.9.1
_2019-10-30_
* Fix: "abstract function ... cannot have code" code gen crash when parsing Kotlin metadata.
* Fix: Generate code to support constructors with more than 32 parameters. The 1.9.0 release had
a regression where classes with 33+ parameters would crash upon decoding.
* Fix: Generate code to support more constructor cases, such as classes with non-property
parameters and classes with multiple constructors.
* Fix: Generate code to handle type aliases in type parameters.
## Version 1.9.0
_2019-10-29_
* **This release requires kotlin-reflect or moshi-kotlin-codegen for all Kotlin classes.**
Previously Moshi wouldn't differentiate between Kotlin classes and Java classes if Kotlin was
not configured. This caused bad runtime behavior such as putting null into non-nullable fields!
If you attempt to create an adapter for a Kotlin type, Moshi will throw an
`IllegalArgumentException`.
Fix this with either the reflection adapter:
```kotlin
val moshi = Moshi.Builder()
// ... add your own JsonAdapters and factories ...
.add(KotlinJsonAdapterFactory())
.build()
```
Or the codegen annotation processor:
```kotlin
@JsonClass(generateAdapter = true)
data class BlackjackHand(
val hidden_card: Card,
val visible_cards: List<Card>
)
```
The [Kotlin documentation][moshi_kotlin_docs] explains the required build configuration changes.
* New: Change how Moshi's generated adapters call constructors. Previous generated code used a
combination of the constructor and `copy()` method to set properties that have default values.
With this update we call the same synthetic constructor that Kotlin uses. This is less surprising
though it requires us to generate some tricky code.
* New: Make `Rfc3339DateJsonAdapter` null-safe. Previously Moshi would refuse to decode null dates.
Restore that behavior by explicitly forbidding nulls with `Rfc3339DateJsonAdapter().nonNull()`.
* New: Require Kotlin 1.3.50 or newer.
* New: `JsonWriter.valueSink()` streams JSON-formatted data inline. Use this to do basic includes
of raw JSON within a streamed document.
* New: Support Gradle incremental processing in code gen.
* New: Improve error messages. This includes better errors when field names and JSON names
disagree, and when failing on an unknown field.
* New: Support default values in `PolymorphicJsonAdapterFactory`.
* New: Permit multiple labels for each subtype in `PolymorphicJsonAdapterFactory`. The first label
is used when writing an object to JSON.
* New: Forbid automatic encoding of platform classes in `kotlinx`. As with `java.*`, `android.*`,
and `kotlin.*` Moshi wants you to specify how to encode platform types.
* New: `@JsonClass(generator=...)` makes it possible for third-party libraries to provide generated
adapters when Moshi's default adapters are insufficient.
* Fix: Simplify wildcard types like `List<? extends Number>` to their base types `List<Number>`
when finding type adapters. This is especially useful with Kotlin where wildcards may be added
automatically.
* Fix: Use the correct name when the `@Json` annotation uses field targeting like `@field:Json`.
* Fix: Support multiple transient properties in `KotlinJsonAdapter`.
* Fix: Don't explode attempting to resolve self-referential type variables like in
`Comparable<T extends Comparable<T>>`.
* Fix: Don't infinite loop on `skipValue()` at the end an object or array. Also disallow calling
`skipValue()` at the end of a document.
## Version 1.8.0
_2018-11-09_
* New: Support JSON objects that include type information in the JSON. The new
`PolymorphicJsonAdapterFactory` writes a type field when encoding, and reads it when decoding.
* New: Fall back to the reflection-based `KotlinJsonAdapterFactory` if it is enabled and a
generated adapter is not found. This makes it possible to use reflection-based JSON adapters in
development (so you don't have to wait for code to be regenerated on every build) and generated
JSON adapters in production (so you don't need the kotlin-reflect library).
* New: The `peekJson()` method on `JsonReader` let you read ahead on a JSON stream without
consuming it. This builds on Okio's new `Buffer.peek()` API.
* New: The `beginFlatten()` and `endFlatten()` methods on `JsonWriter` suppress unwanted nesting
when composing adapters. Previously it was necessary to flatten objects in memory before writing.
* New: Upgrade to Okio 1.16.0. We don't yet require Kotlin-friendly Okio 2.1 but Moshi works fine
with that release.
```kotlin
implementation("com.squareup.okio:okio:1.16.0")
```
* Fix: Don't return partially-constructed adapters when using a Moshi instance concurrently.
* Fix: Eliminate warnings and errors in generated `.kt` triggered by type variance, primitive
types, and required values.
* Fix: Improve the supplied rules (`moshi.pro`) to better retain symbols used by Moshi. We
recommend R8 when shrinking code.
* Fix: Remove code generation companion objects. This API was neither complete nor necessary.
## Version 1.7.0
_2018-09-24_
* New: `EnumJsonAdapter` makes it easy to specify a fallback value for unknown enum constants.
By default Moshi throws an `JsonDataException` if it reads an unknown enum constant. With this
you can specify a fallback value or null.
```java
new Moshi.Builder()
.add(EnumJsonAdapter.create(IsoCurrency.class)
.withUnknownFallback(IsoCurrency.USD))
.build();
```
Note that this adapter is in the optional `moshi-adapters` module.
```groovy
implementation 'com.squareup.moshi:moshi-adapters:1.7.0'
```
* New: Embed R8/ProGuard rules in the `.jar` file.
* New: Use `@CheckReturnValue` in more places. We hope this will encourage you to use `skipName()`
instead of `nextName()` for better performance!
* New: Forbid automatic encoding of platform classes in `androidx`. As with `java.*`, `android.*`,
and `kotlin.*` Moshi wants you to specify how to encode platform types.
* New: Improve error reporting when creating an adapter fails.
* New: Upgrade to Okio 1.15.0. We don't yet require Kotlin-friendly Okio 2.x but Moshi works fine
with that release.
```groovy
implementation 'com.squareup.okio:okio:1.15.0'
```
* Fix: Return false from `JsonReader.hasNext()` at document's end.
* Fix: Improve code gen to handle several broken cases. Our generated adapters had problems with
nulls, nested parameterized types, private transient properties, generic type aliases, fields
with dollar signs in their names, and named companion objects.
## Version 1.6.0
_2018-05-14_
* **Moshi now supports codegen for Kotlin.** We've added a new annotation processor that generates
a small and fast JSON adapter for your Kotlin types. It can be used on its own or with the
existing `KotlinJsonAdapterFactory` adapter.
* **Moshi now resolves all type parameters.** Previously Moshi wouldn't resolve type parameters on
top-level classes.
* New: Support up to 255 levels of nesting when reading and writing JSON. Previously Moshi would
reject JSON input that contained more than 32 levels of nesting.
* New: Write encoded JSON to a stream with `JsonWriter.value(BufferedSource)`. Use this to emit a
JSON value without decoding it first.
* New: `JsonAdapter.nonNull()` returns a new JSON adapter that forbids explicit nulls in the JSON
body. Use this to detect and fail eagerly on unwanted nulls.
* New: `JsonReader.skipName()` is like `nextName()` but it avoids allocating when a name is
unknown. Use this when `JsonReader.selectName()` returns -1.
* New: Automatic module name of `com.squareup.moshi` for use with the Java Platform Module System.
This moves moshi-adapters into its own `.adapters` package and forwards the existing adapter. It
moves the moshi-kotlin into its own `.kotlin.reflect` package and forwards the existing adapter.
* New: Upgrade to Okio 1.14.0.
```xml
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>1.14.0</version>
</dependency>
com.squareup.okio:okio:1.14.0
```
* Fix: Fail fast if there are trailing non-whitespace characters in the JSON passed to
`JsonAdapter.fromJson(String)`. Previously such data was ignored!
* Fix: Fail fast when Kotlin types are abstract, inner, or object instances.
* Fix: Fail fast if `name()` is called out of sequence.
* Fix: Handle asymmetric `Type.equals()` methods when doing type comparisons. Previously it was
possible that a registered type adapter would not be used because its `Type.equals()` method was
not consistent with a user-provided type.
* Fix: `JsonValueReader.selectString()` now returns -1 for non-strings instead of throwing.
* Fix: Permit reading numbers as strings when the `JsonReader` was created from a JSON value. This
was always supported when reading from a stream but broken when reading from a decoded value.
* Fix: Delegate to user-adapters in the adapter for Object.class. Previously when Moshi encountered
an opaque Object it would only use the built-in adapters. With this change user-installed
adapters for types like `String` will always be honored.
## Version 1.5.0
_2017-05-14_
* **Moshi now uses `@Nullable` to annotate all possibly-null values.** We've added a compile-time
dependency on the JSR 305 annotations. This is a [provided][maven_provided] dependency and does
not need to be included in your build configuration, `.jar` file, or `.apk`. We use
`@ParametersAreNonnullByDefault` and all parameters and return types are never null unless
explicitly annotated `@Nullable`.
* **Warning: Moshi APIs in this update are source-incompatible for Kotlin callers.** Nullability
was previously ambiguous and lenient but now the compiler will enforce strict null checks.
* **Kotlin models are now supported via the `moshi-kotlin` extension.** `KotlinJsonAdapterFactory`
is the best way to use Kotlin with Moshi. It honors default values and is null-safe. Kotlin
users that don't use this factory should write custom adapters for their JSON types. Otherwise
Moshi cannot properly initialize delegated properties of the objects it decodes.
* New: Upgrade to Okio 1.13.0.
```xml
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>1.13.0</version>
</dependency>
com.squareup.okio:okio:1.13.0
```
* New: You may now declare delegates in `@ToJson` and `@FromJson` methods. If one of the arguments
to the method is a `JsonAdapter` of the same type, that will be the next eligible adapter for
that type. This may be useful for composing adapters.
* New: `Types.equals(Type, Type)` makes it easier to compare types in `JsonAdapter.Factory`.
* Fix: Retain the sign on negative zero.
## Version 1.4.0
_2017-02-04_
Moshi 1.4 is a major release that adds _JSON values_ as a core part of the library. We consider any
Java object comprised of maps, lists, strings, numbers, booleans and nulls to be a JSON value. These
are equivalent to parsed JSON objects in JavaScript, [Gson][gson]’s `JsonElement`, and
[Jackson][jackson]’s `JsonNode`. Unlike Jackson and Gson, Moshi just uses Java’s built-in types for
its values:
<table>
<tr><th></th><th>JSON type</th><th>Java type</th></tr>
<tr><td>{...}</td><td>Object</td><td>Map<String, Object></th></tr>
<tr><td>[...]</td><td>Array</td><td>List<Object></th></tr>
<tr><td>"abc"</td><td>String</td><td>String</th></tr>
<tr><td>123</td><td>Number</td><td>Double, Long, or BigDecimal</th></tr>
<tr><td>true</td><td>Boolean</td><td>Boolean</th></tr>
<tr><td>null</td><td>null</td><td>null</th></tr>
</table>
Moshi's new API `JsonAdapter.toJsonValue()` converts your application classes to JSON values
comprised of the above types. Symmetrically, `JsonAdapter.fromJsonValue()` converts JSON values to
your application classes.
* New: `JsonAdapter.toJsonValue()` and `fromJsonValue()`.
* New: `JsonReader.readJsonValue()` reads a JSON value from a stream.
* New: `Moshi.adapter(Type, Class<? extends Annotation>)` lets you look up the adapter for a
qualified type.
* New: `JsonAdapter.serializeNulls()` and `indent()` return JSON adapters that customize the
format of the encoded JSON.
* New: `JsonReader.selectName()` and `selectString()` optimize decoding JSON with known names and
values.
* New: `Types.nextAnnotations()` reduces the amount of code required to implement a custom
`JsonAdapter.Factory`.
* Fix: Don't fail on large longs that have a fractional component like `9223372036854775806.0`.
## Version 1.3.1
_2016-10-21_
* Fix: Don't incorrectly report invalid input when a slash character is escaped. When we tightened
our invalid escape handling we missed the one character that is valid both escaped `\/` and
unescaped `/`.
## Version 1.3.0
_2016-10-15_
* New: Permit `@ToJson` and `@FromJson` methods to take any number of `JsonAdapter` parameters to
delegate to. This is supported for `@ToJson` methods that take a `JsonWriter` and `@FromJson`
methods that take a `JsonReader`.
* New: Throw `JsonEncodingException` when the incoming data is not valid JSON. Use this to
differentiate data format problems from connectivity problems.
* New: Upgrade to Okio 1.11.0.
```xml
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>1.11.0</version>
</dependency>
```
* New: Omit Kotlin (`kotlin.*`) and Scala (`scala.*`) platform types when encoding objects using
their fields. This should make it easier to avoid unexpected dependencies on platform versions.
* Fix: Explicitly limit reading and writing to 31 levels of nested structure. Previously no
specific limit was enforced, but deeply nested documents would fail with either an
`ArrayIndexOutOfBoundsException` due to a bug in `JsonWriter`'s path management, or a
`StackOverflowError` due to excessive recursion.
* Fix: Require enclosed types to specify their enclosing type with
`Types.newParameterizedTypeWithOwner()`. Previously this API did not exist and looking up
adapters for enclosed parameterized types was not possible.
* Fix: Fail on invalid escapes. Previously any character could be escaped. With this fix only
characters permitted to be escaped may be escaped. Use `JsonReader.setLenient(true)` to read
JSON documents that escape characters that should not be escaped.
## Version 1.2.0
_2016-05-28_
* New: Take advantage of Okio's new `Options` feature when reading field names and enum values.
This has a significant impact on performance. We measured parsing performance improve from 89k
ops/sec to 140k ops/sec on one benchmark on one machine.
* New: Upgrade to Okio 1.8.0.
```xml
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>1.8.0</version>
</dependency>
```
* New: Support types that lack no-argument constructors objects on Android releases prior to
Gingerbread.
* Fix: Add writer value overload for boxed booleans. Autoboxing resolves boxed longs and doubles
to `value(Number)`, but a boxed boolean would otherwise resolve to value(boolean) with an
implicit call to booleanValue() which has the potential to throw NPEs.
* Fix: Be more aggressive about canonicalizing types.
## Version 1.1.0
_2016-01-19_
* New: Support [RFC 7159][rfc_7159], the latest JSON specification. This removes the constraint
that the root value must be an array or an object. It may now take any value: array, object,
string, number, boolean, or null. Previously this was only permitted if the adapter was
configured to be lenient.
* New: Enum constants may be annotated with `@Json` to customize their encoded value.
* New: Create new builder from Moshi instance with `Moshi.newBuilder()`.
* New: `Types.getRawType()` and `Types.collectionElementType()` APIs to assist in defining generic
type adapter factories.
## Version 1.0.0
_2015-09-27_
* **API Change**: Replaced `new JsonReader()` with `JsonReader.of()` and `new JsonWriter()` with
`JsonWriter.of()`. If your code calls either of these constructors it will need to be updated to
call the static factory method instead.
* **API Change**: Don’t throw `IOException` on `JsonAdapter.toJson(T)`. Code that calls this
method may need to be fixed to no longer catch an impossible `IOException`.
* Fix: the JSON adapter for `Object` no longer fails when encountering `null` in the stream.
* New: `@Json` annotation can customize a field's name. This is particularly handy for fields
whose names are Java keywords, like `default` or `public`.
* New: `Rfc3339DateJsonAdapter` converts between a `java.util.Date` and a string formatted with
RFC 3339 (like `2015-09-26T18:23:50.250Z`). This class is in the new `moshi-adapters`
subproject. You will need to register this adapter if you want this date formatting behavior.
See it in action in the [dates example][dates_example].
* New: `Moshi.adapter()` keeps a cache of all created adapters. For best efficiency, application
code should keep a reference to required adapters in a field.
* New: The `Types` factory class makes it possible to compose types like `List<Card>` or
`Map<String, Integer>`. This is useful to look up JSON adapters for parameterized types.
* New: `JsonAdapter.failOnUnknown()` returns a new JSON adapter that throws if an unknown value is
encountered on the stream. Use this in development and debug builds to detect typos in field
names. This feature shouldn’t be used in production because it makes migrations very difficult.
## Version 0.9.0
_2015-06-16_
* Databinding for primitive types, strings, enums, arrays, collections, and maps.
* Databinding for plain old Java objects.
* [JSONPath](http://goessner.net/articles/JsonPath/) support for both `JsonReader` and
`JsonWriter`.
* Throw `JsonDataException` when there’s a data binding problem.
* Adapter methods: `@ToJson` and `@FromJson`.
* Qualifier annotations: `@JsonQualifier` to permit different type adapters for the same Java
type.
* Imported code from Gson: `JsonReader`, `JsonWriter`. Also some internal classes:
`LinkedHashTreeMap` for hash-collision avoidance and `Types` for typesafe databinding.
[dates_example]: https://github.com/square/moshi/blob/master/examples/src/main/java/com/squareup/moshi/recipes/ReadAndWriteRfc3339Dates.java
[gson]: https://github.com/google/gson
[jackson]: http://wiki.fasterxml.com/JacksonHome
[kotlin_1_4_10]: https://github.com/JetBrains/kotlin/releases/tag/v1.4.10
[kotlin_1_4_31]: https://github.com/JetBrains/kotlin/releases/tag/v1.4.31
[kotlin_1_6_0]: https://github.com/JetBrains/kotlin/releases/tag/v1.6.0
[kotlin_1_7_0]: https://github.com/JetBrains/kotlin/releases/tag/v1.7.0
[kotlinpoet_1_12_0]: https://github.com/square/kotlinpoet/releases/tag/1.12.0
[kotlinx_metadata_0_5_0]: https://github.com/JetBrains/kotlin/blob/master/libraries/kotlinx-metadata/jvm/ChangeLog.md#050
[ksp]: https://github.com/google/ksp
[ksp_1_7_0_1_0_6]: https://github.com/google/ksp/releases/tag/1.7.10-1.0.6
[maven_provided]: https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
[moshi_kotlin_docs]: https://github.com/square/moshi/blob/master/README.md#kotlin
[mrjar]: https://openjdk.java.net/jeps/238
[okio_1_7_5]: https://square.github.io/okio/changelog/#version-1175
[okio_2_10_0]: https://square.github.io/okio/changelog/#version-2100
[rfc_7159]: https://tools.ietf.org/html/rfc7159
================================================
FILE: CONTRIBUTING.md
================================================
Contributing
============
If you would like to contribute code to Moshi you can do so through GitHub by
forking the repository and sending a pull request.
When submitting code, please make every effort to follow existing conventions
and style in order to keep the code as readable as possible. Please also make
sure your code compiles by running `./gradlew build`. For any formatting errors,
run `./gradlew spotlessApply` to fix them.
Before your code can be accepted into the project you must also sign the
[Individual Contributor License Agreement (CLA)][1].
[1]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1
================================================
FILE: LICENSE.txt
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
Moshi
=====
Moshi is a modern JSON library for Android, Java and Kotlin. It makes it easy to parse JSON into Java and Kotlin
classes:
_Note: The Kotlin examples of this README assume use of either Kotlin code gen or `KotlinJsonAdapterFactory` for reflection. Plain Java-based reflection is unsupported on Kotlin classes._
<details>
<summary>Java</summary>
```java
String json = ...;
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<BlackjackHand> jsonAdapter = moshi.adapter(BlackjackHand.class);
BlackjackHand blackjackHand = jsonAdapter.fromJson(json);
System.out.println(blackjackHand);
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
val json: String = ...
val moshi: Moshi = Moshi.Builder().build()
val jsonAdapter: JsonAdapter<BlackjackHand> = moshi.adapter<BlackjackHand>()
val blackjackHand = jsonAdapter.fromJson(json)
println(blackjackHand)
```
</details>
And it can just as easily serialize Java or Kotlin objects as JSON:
<details>
<summary>Java</summary>
```java
BlackjackHand blackjackHand = new BlackjackHand(
new Card('6', SPADES),
Arrays.asList(new Card('4', CLUBS), new Card('A', HEARTS)));
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<BlackjackHand> jsonAdapter = moshi.adapter(BlackjackHand.class);
String json = jsonAdapter.toJson(blackjackHand);
System.out.println(json);
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
val blackjackHand = BlackjackHand(
Card('6', SPADES),
listOf(Card('4', CLUBS), Card('A', HEARTS))
)
val moshi: Moshi = Moshi.Builder().build()
val jsonAdapter: JsonAdapter<BlackjackHand> = moshi.adapter<BlackjackHand>()
val json: String = jsonAdapter.toJson(blackjackHand)
println(json)
```
</details>
### Built-in Type Adapters
Moshi has built-in support for reading and writing Java’s core data types:
* Primitives (int, float, char...) and their boxed counterparts (Integer, Float, Character...).
* Arrays, Collections, Lists, Sets, and Maps
* Strings
* Enums
It supports your model classes by writing them out field-by-field. In the example above Moshi uses
these classes:
<details>
<summary>Java</summary>
```java
class BlackjackHand {
public final Card hidden_card;
public final List<Card> visible_cards;
...
}
class Card {
public final char rank;
public final Suit suit;
...
}
enum Suit {
CLUBS, DIAMONDS, HEARTS, SPADES;
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
class BlackjackHand(
val hidden_card: Card,
val visible_cards: List<Card>,
...
)
class Card(
val rank: Char,
val suit: Suit
...
)
enum class Suit {
CLUBS, DIAMONDS, HEARTS, SPADES;
}
```
</details>
to read and write this JSON:
```json
{
"hidden_card": {
"rank": "6",
"suit": "SPADES"
},
"visible_cards": [
{
"rank": "4",
"suit": "CLUBS"
},
{
"rank": "A",
"suit": "HEARTS"
}
]
}
```
The [Javadoc][javadoc] catalogs the complete Moshi API, which we explore below.
### Custom Type Adapters
With Moshi, it’s particularly easy to customize how values are converted to and from JSON. A type
adapter is any class that has methods annotated `@ToJson` and `@FromJson`.
For example, Moshi’s default encoding of a playing card is verbose: the JSON defines the rank and
suit in separate fields: `{"rank":"A","suit":"HEARTS"}`. With a type adapter, we can change the
encoding to something more compact: `"4H"` for the four of hearts or `"JD"` for the jack of
diamonds:
<details>
<summary>Java</summary>
```java
class CardAdapter {
@ToJson String toJson(Card card) {
return card.rank + card.suit.name().substring(0, 1);
}
@FromJson Card fromJson(String card) {
if (card.length() != 2) throw new JsonDataException("Unknown card: " + card);
char rank = card.charAt(0);
switch (card.charAt(1)) {
case 'C': return new Card(rank, Suit.CLUBS);
case 'D': return new Card(rank, Suit.DIAMONDS);
case 'H': return new Card(rank, Suit.HEARTS);
case 'S': return new Card(rank, Suit.SPADES);
default: throw new JsonDataException("unknown suit: " + card);
}
}
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
class CardAdapter {
@ToJson fun toJson(card: Card): String {
return card.rank + card.suit.name.substring(0, 1)
}
@FromJson fun fromJson(card: String): Card {
if (card.length != 2) throw JsonDataException("Unknown card: $card")
val rank = card[0]
return when (card[1]) {
'C' -> Card(rank, Suit.CLUBS)
'D' -> Card(rank, Suit.DIAMONDS)
'H' -> Card(rank, Suit.HEARTS)
'S' -> Card(rank, Suit.SPADES)
else -> throw JsonDataException("unknown suit: $card")
}
}
}
```
</details>
Register the type adapter with the `Moshi.Builder` and we’re good to go.
<details>
<summary>Java</summary>
```java
Moshi moshi = new Moshi.Builder()
.add(new CardAdapter())
.build();
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
val moshi = Moshi.Builder()
.add(CardAdapter())
.build()
```
</details>
Voilà:
```json
{
"hidden_card": "6S",
"visible_cards": [
"4C",
"AH"
]
}
```
#### Another example
Note that the method annotated with `@FromJson` does not need to take a String as an argument.
Rather it can take input of any type and Moshi will first parse the JSON to an object of that type
and then use the `@FromJson` method to produce the desired final value. Conversely, the method
annotated with `@ToJson` does not have to produce a String.
Assume, for example, that we have to parse a JSON in which the date and time of an event are
represented as two separate strings.
```json
{
"title": "Blackjack tournament",
"begin_date": "20151010",
"begin_time": "17:04"
}
```
We would like to combine these two fields into one string to facilitate the date parsing at a
later point. Also, we would like to have all variable names in CamelCase. Therefore, the `Event`
class we want Moshi to produce like this:
<details>
<summary>Java</summary>
```java
class Event {
String title;
String beginDateAndTime;
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
class Event(
val title: String,
val beginDateAndTime: String
)
```
</details>
Instead of manually parsing the JSON line per line (which we could also do) we can have Moshi do the
transformation automatically. We simply define another class `EventJson` that directly corresponds
to the JSON structure:
<details>
<summary>Java</summary>
```java
class EventJson {
String title;
String begin_date;
String begin_time;
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
class EventJson(
val title: String,
val begin_date: String,
val begin_time: String
)
```
</details>
And another class with the appropriate `@FromJson` and `@ToJson` methods that are telling Moshi how
to convert an `EventJson` to an `Event` and back. Now, whenever we are asking Moshi to parse a JSON
to an `Event` it will first parse it to an `EventJson` as an intermediate step. Conversely, to
serialize an `Event` Moshi will first create an `EventJson` object and then serialize that object as
usual.
<details>
<summary>Java</summary>
```java
class EventJsonAdapter {
@FromJson Event eventFromJson(EventJson eventJson) {
Event event = new Event();
event.title = eventJson.title;
event.beginDateAndTime = eventJson.begin_date + " " + eventJson.begin_time;
return event;
}
@ToJson EventJson eventToJson(Event event) {
EventJson json = new EventJson();
json.title = event.title;
json.begin_date = event.beginDateAndTime.substring(0, 8);
json.begin_time = event.beginDateAndTime.substring(9, 14);
return json;
}
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
class EventJsonAdapter {
@FromJson
fun eventFromJson(eventJson: EventJson): Event {
return Event(
title = eventJson.title,
beginDateAndTime = "${eventJson.begin_date} ${eventJson.begin_time}"
)
}
@ToJson
fun eventToJson(event: Event): EventJson {
return EventJson(
title = event.title,
begin_date = event.beginDateAndTime.substring(0, 8),
begin_time = event.beginDateAndTime.substring(9, 14),
)
}
}
```
</details>
Again we register the adapter with Moshi.
<details>
<summary>Java</summary>
```java
Moshi moshi = new Moshi.Builder()
.add(new EventJsonAdapter())
.build();
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
val moshi = Moshi.Builder()
.add(EventJsonAdapter())
.build()
```
</details>
We can now use Moshi to parse the JSON directly to an `Event`.
<details>
<summary>Java</summary>
```java
JsonAdapter<Event> jsonAdapter = moshi.adapter(Event.class);
Event event = jsonAdapter.fromJson(json);
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
val jsonAdapter = moshi.adapter<Event>()
val event = jsonAdapter.fromJson(json)
```
</details>
### Adapter convenience methods
Moshi provides a number of convenience methods for `JsonAdapter` objects:
- `nullSafe()`
- `nonNull()`
- `lenient()`
- `failOnUnknown()`
- `indent()`
- `serializeNulls()`
These factory methods wrap an existing `JsonAdapter` into additional functionality.
For example, if you have an adapter that doesn't support nullable values, you can use `nullSafe()` to make it null safe:
<details>
<summary>Java</summary>
```java
String dateJson = "\"2018-11-26T11:04:19.342668Z\"";
String nullDateJson = "null";
// Hypothetical IsoDateDapter, doesn't support null by default
JsonAdapter<Date> adapter = new IsoDateDapter();
Date date = adapter.fromJson(dateJson);
System.out.println(date); // Mon Nov 26 12:04:19 CET 2018
Date nullDate = adapter.fromJson(nullDateJson);
// Exception, com.squareup.moshi.JsonDataException: Expected a string but was NULL at path $
Date nullDate = adapter.nullSafe().fromJson(nullDateJson);
System.out.println(nullDate); // null
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
val dateJson = "\"2018-11-26T11:04:19.342668Z\""
val nullDateJson = "null"
// Hypothetical IsoDateDapter, doesn't support null by default
val adapter: JsonAdapter<Date> = IsoDateDapter()
val date = adapter.fromJson(dateJson)
println(date) // Mon Nov 26 12:04:19 CET 2018
val nullDate = adapter.fromJson(nullDateJson)
// Exception, com.squareup.moshi.JsonDataException: Expected a string but was NULL at path $
val nullDate = adapter.nullSafe().fromJson(nullDateJson)
println(nullDate) // null
```
</details>
In contrast to `nullSafe()` there is `nonNull()` to make an adapter refuse null values. Refer to the Moshi JavaDoc for details on the various methods.
### Parse JSON Arrays
Say we have a JSON string of this structure:
```json
[
{
"rank": "4",
"suit": "CLUBS"
},
{
"rank": "A",
"suit": "HEARTS"
}
]
```
We can now use Moshi to parse the JSON string into a `List<Card>`.
<details>
<summary>Java</summary>
```java
String cardsJsonResponse = ...;
Type type = Types.newParameterizedType(List.class, Card.class);
JsonAdapter<List<Card>> adapter = moshi.adapter(type);
List<Card> cards = adapter.fromJson(cardsJsonResponse);
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
val cardsJsonResponse: String = ...
// We can just use a reified extension!
val adapter = moshi.adapter<List<Card>>()
val cards: List<Card> = adapter.fromJson(cardsJsonResponse)
```
</details>
### Fails Gracefully
Automatic databinding almost feels like magic. But unlike the black magic that typically accompanies
reflection, Moshi is designed to help you out when things go wrong.
```
JsonDataException: Expected one of [CLUBS, DIAMONDS, HEARTS, SPADES] but was ANCHOR at path $.visible_cards[2].suit
at com.squareup.moshi.JsonAdapters$11.fromJson(JsonAdapters.java:188)
at com.squareup.moshi.JsonAdapters$11.fromJson(JsonAdapters.java:180)
...
```
Moshi always throws a standard `java.io.IOException` if there is an error reading the JSON document,
or if it is malformed. It throws a `JsonDataException` if the JSON document is well-formed, but
doesn’t match the expected format.
### Built on Okio
Moshi uses [Okio][okio] for simple and powerful I/O. It’s a fine complement to [OkHttp][okhttp],
which can share buffer segments for maximum efficiency.
### Borrows from Gson
Moshi uses the same streaming and binding mechanisms as [Gson][gson]. If you’re a Gson user you’ll
find Moshi works similarly. If you try Moshi and don’t love it, you can even migrate to Gson without
much violence!
But the two libraries have a few important differences:
* **Moshi has fewer built-in type adapters.** For example, you need to configure your own date
adapter. Most binding libraries will encode whatever you throw at them. Moshi refuses to
serialize platform types (`java.*`, `javax.*`, and `android.*`) without a user-provided type
adapter. This is intended to prevent you from accidentally locking yourself to a specific JDK or
Android release.
* **Moshi is less configurable.** There’s no field naming strategy, versioning, instance creators,
or long serialization policy. Instead of naming a field `visibleCards` and using a policy class
to convert that to `visible_cards`, Moshi wants you to just name the field `visible_cards` as it
appears in the JSON.
* **Moshi doesn’t have a `JsonElement` model.** Instead it just uses built-in types like `List` and
`Map`.
* **No HTML-safe escaping.** Gson encodes `=` as `\u003d` by default so that it can be safely
encoded in HTML without additional escaping. Moshi encodes it naturally (as `=`) and assumes that
the HTML encoder – if there is one – will do its job.
### Custom field names with @Json
Moshi works best when your JSON objects and Java or Kotlin classes have the same structure. But when they
don't, Moshi has annotations to customize data binding.
Use `@Json` to specify how Java fields or Kotlin properties map to JSON names. This is necessary when the JSON name
contains spaces or other characters that aren’t permitted in Java field or Kotlin property names. For example, this
JSON has a field name containing a space:
```json
{
"username": "jesse",
"lucky number": 32
}
```
With `@Json` its corresponding Java or Kotlin class is easy:
<details>
<summary>Java</summary>
```java
class Player {
String username;
@Json(name = "lucky number") int luckyNumber;
...
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
class Player {
val username: String
@Json(name = "lucky number") val luckyNumber: Int
...
}
```
</details>
Because JSON field names are always defined with their Java or Kotlin fields, Moshi makes it easy to find
fields when navigating between Java or Koltin and JSON.
### Alternate type adapters with @JsonQualifier
Use `@JsonQualifier` to customize how a type is encoded for some fields without changing its
encoding everywhere. This works similarly to the qualifier annotations in dependency injection
tools like Dagger and Guice.
Here’s a JSON message with two integers and a color:
```json
{
"width": 1024,
"height": 768,
"color": "#ff0000"
}
```
By convention, Android programs also use `int` for colors:
<details>
<summary>Java</summary>
```java
class Rectangle {
int width;
int height;
int color;
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
class Rectangle(
val width: Int,
val height: Int,
val color: Int
)
```
</details>
But if we encoded the above Java or Kotlin class as JSON, the color isn't encoded properly!
```json
{
"width": 1024,
"height": 768,
"color": 16711680
}
```
The fix is to define a qualifier annotation, itself annotated `@JsonQualifier`:
<details>
<summary>Java</summary>
```java
@Retention(RUNTIME)
@JsonQualifier
public @interface HexColor {
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
@Retention(RUNTIME)
@JsonQualifier
annotation class HexColor
```
</details>
Next apply this `@HexColor` annotation to the appropriate field:
<details>
<summary>Java</summary>
```java
class Rectangle {
int width;
int height;
@HexColor int color;
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
class Rectangle(
val width: Int,
val height: Int,
@HexColor val color: Int
)
```
</details>
And finally define a type adapter to handle it:
<details>
<summary>Java</summary>
```java
/** Converts strings like #ff0000 to the corresponding color ints. */
class ColorAdapter {
@ToJson String toJson(@HexColor int rgb) {
return String.format("#%06x", rgb);
}
@FromJson @HexColor int fromJson(String rgb) {
return Integer.parseInt(rgb.substring(1), 16);
}
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
/** Converts strings like #ff0000 to the corresponding color ints. */
class ColorAdapter {
@ToJson fun toJson(@HexColor rgb: Int): String {
return "#%06x".format(rgb)
}
@FromJson @HexColor fun fromJson(rgb: String): Int {
return rgb.substring(1).toInt(16)
}
}
```
</details>
Use `@JsonQualifier` when you need different JSON encodings for the same type. Most programs
shouldn’t need this `@JsonQualifier`, but it’s very handy for those that do.
### Omitting fields
Some models declare fields that shouldn’t be included in JSON. For example, suppose our blackjack
hand has a `total` field with the sum of the cards:
<details>
<summary>Java</summary>
```java
public final class BlackjackHand {
private int total;
...
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
class BlackjackHand(
private val total: Int,
...
)
```
</details>
By default, all fields are emitted when encoding JSON, and all fields are accepted when decoding
JSON. Prevent a field from being included by annotating them with `@Json(ignore = true)`.
<details>
<summary>Java</summary>
```java
public final class BlackjackHand {
@Json(ignore = true)
private int total;
...
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
class BlackjackHand(...) {
@Json(ignore = true)
var total: Int = 0
...
}
```
</details>
These fields are omitted when writing JSON. When reading JSON, the field is skipped even if the
JSON contains a value for the field. Instead, it will get a default value. In Kotlin, these fields
_must_ have a default value if they are in the primary constructor.
Note that you can also use Java’s `transient` keyword or Kotlin's `@Transient` annotation on these fields
for the same effect.
### Default Values & Constructors
When reading JSON that is missing a field, Moshi relies on the Java or Kotlin or Android runtime to assign
the field’s value. Which value it uses depends on whether the class has a no-arguments constructor.
If the class has a no-arguments constructor, Moshi will call that constructor and whatever value
it assigns will be used. For example, because this class has a no-arguments constructor the `total`
field is initialized to `-1`.
Note: This section only applies to Java reflections.
```java
public final class BlackjackHand {
private int total = -1;
...
private BlackjackHand() {
}
public BlackjackHand(Card hidden_card, List<Card> visible_cards) {
...
}
}
```
If the class doesn’t have a no-arguments constructor, Moshi can’t assign the field’s default value,
**even if it’s specified in the field declaration**. Instead, the field’s default is always `0` for
numbers, `false` for booleans, and `null` for references. In this example, the default value of
`total` is `0`!
```java
public final class BlackjackHand {
private int total = -1;
...
public BlackjackHand(Card hidden_card, List<Card> visible_cards) {
...
}
}
```
This is surprising and is a potential source of bugs! For this reason consider defining a
no-arguments constructor in classes that you use with Moshi, using `@SuppressWarnings("unused")` to
prevent it from being inadvertently deleted later:
```java
public final class BlackjackHand {
private int total = -1;
...
@SuppressWarnings("unused") // Moshi uses this!
private BlackjackHand() {
}
public BlackjackHand(Card hidden_card, List<Card> visible_cards) {
...
}
}
```
### Composing Adapters
In some situations Moshi's default Java-to-JSON conversion isn't sufficient. You can compose
adapters to build upon the standard conversion.
In this example, we turn serialize nulls, then delegate to the built-in adapter:
<details>
<summary>Java</summary>
```java
class TournamentWithNullsAdapter {
@ToJson void toJson(JsonWriter writer, Tournament tournament,
JsonAdapter<Tournament> delegate) throws IOException {
boolean wasSerializeNulls = writer.getSerializeNulls();
writer.setSerializeNulls(true);
try {
delegate.toJson(writer, tournament);
} finally {
writer.setLenient(wasSerializeNulls);
}
}
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
class TournamentWithNullsAdapter {
@ToJson fun toJson(writer: JsonWriter, tournament: Tournament?,
delegate: JsonAdapter<Tournament?>) {
val wasSerializeNulls: Boolean = writer.getSerializeNulls()
writer.setSerializeNulls(true)
try {
delegate.toJson(writer, tournament)
} finally {
writer.setLenient(wasSerializeNulls)
}
}
}
```
</details>
When we use this to serialize a tournament, nulls are written! But nulls elsewhere in our JSON
document are skipped as usual.
Moshi has a powerful composition system in its `JsonAdapter.Factory` interface. We can hook in to
the encoding and decoding process for any type, even without knowing about the types beforehand. In
this example, we customize types annotated `@AlwaysSerializeNulls`, which an annotation we create,
not built-in to Moshi:
<details>
<summary>Java</summary>
```java
@Target(TYPE)
@Retention(RUNTIME)
public @interface AlwaysSerializeNulls {}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
@Target(TYPE)
@Retention(RUNTIME)
annotation class AlwaysSerializeNulls
```
</details>
<details>
<summary>Java</summary>
```java
@AlwaysSerializeNulls
static class Car {
String make;
String model;
String color;
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
@AlwaysSerializeNulls
class Car(
val make: String?,
val model: String?,
val color: String?
)
```
</details>
Each `JsonAdapter.Factory` interface is invoked by `Moshi` when it needs to build an adapter for a
user's type. The factory either returns an adapter to use, or null if it doesn't apply to the
requested type. In our case we match all classes that have our annotation.
<details>
<summary>Java</summary>
```java
static class AlwaysSerializeNullsFactory implements JsonAdapter.Factory {
@Override public JsonAdapter<?> create(
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
Class<?> rawType = Types.getRawType(type);
if (!rawType.isAnnotationPresent(AlwaysSerializeNulls.class)) {
return null;
}
JsonAdapter<Object> delegate = moshi.nextAdapter(this, type, annotations);
return delegate.serializeNulls();
}
}
```
</details>
<details open>
<summary>Kotlin</summary>
```kotlin
class AlwaysSerializeNullsFactory : JsonAdapter.Factory {
override fun create(type: Type, annotations: Set<Annotation>, moshi: Moshi): JsonAdapter<*>? {
val rawType: Class<*> = type.rawType
if (!rawType.isAnnotationPresent(AlwaysSerializeNulls::class.java)) {
return null
}
val delegate: JsonAdapter<Any> = moshi.nextAdapter(this, type, annotations)
return delegate.serializeNulls()
}
}
```
</details>
After determining that it applies, the factory looks up Moshi's built-in adapter by calling
`Moshi.nextAdapter()`. This is key to the composition mechanism: adapters delegate to each other!
The composition in this example is simple: it applies the `serializeNulls()` transform on the
delegate.
Composing adapters can be very sophisticated:
* An adapter could transform the input object before it is JSON-encoded. A string could be
trimmed or truncated; a value object could be simplified or normalized.
* An adapter could repair the output object after it is JSON-decoded. It could fill-in missing
data or discard unwanted data.
* The JSON could be given extra structure, such as wrapping values in objects or arrays.
Moshi is itself built on the pattern of repeatedly composing adapters. For example, Moshi's built-in
adapter for `List<T>` delegates to the adapter of `T`, and calls it repeatedly.
### Precedence
Moshi's composition mechanism tries to find the best adapter for each type. It starts with the first
adapter or factory registered with `Moshi.Builder.add()`, and proceeds until it finds an adapter for
the target type.
If a type can be matched multiple adapters, the earliest one wins.
To register an adapter at the end of the list, use `Moshi.Builder.addLast()` instead. This is most
useful when registering general-purpose adapters, such as the `KotlinJsonAdapterFactory` below.
Kotlin
------
Moshi is a great JSON library for Kotlin. It understands Kotlin’s non-nullable types and default
parameter values. When you use Kotlin with Moshi you may use reflection, codegen, or both.
#### Reflection
The reflection adapter uses Kotlin’s reflection library to convert your Kotlin classes to and from
JSON. Enable it by adding the `KotlinJsonAdapterFactory` to your `Moshi.Builder`:
```kotlin
val moshi = Moshi.Builder()
.addLast(KotlinJsonAdapterFactory())
.build()
```
Moshi’s adapters are ordered by precedence, so you should use `addLast()` with
`KotlinJsonAdapterFactory`, and `add()` with your custom adapters.
The reflection adapter requires the following additional dependency:
```xml
<dependency>
<groupId>com.squareup.moshi</groupId>
<artifactId>moshi-kotlin</artifactId>
<version>1.15.2</version>
</dependency>
```
```kotlin
implementation("com.squareup.moshi:moshi-kotlin:2.0.0-alpha.1")
```
Note that the reflection adapter transitively depends on the `kotlin-reflect` library which is a
2.5 MiB .jar file.
#### Codegen
Moshi’s Kotlin codegen support can be used as a Kotlin SymbolProcessor ([KSP][ksp]).
It generates a small and fast adapter for each of your Kotlin classes at compile-time. Enable it by annotating
each class that you want to encode as JSON:
```kotlin
@JsonClass(generateAdapter = true)
data class BlackjackHand(
val hidden_card: Card,
val visible_cards: List<Card>
)
```
The codegen adapter requires that your Kotlin types and their properties be either `internal` or
`public` (this is Kotlin’s default visibility).
Kotlin codegen has no additional runtime dependency. You’ll need to enable kapt or KSP and then
add the following to your build to enable the annotation processor:
<details open>
<summary>KSP</summary>
```kotlin
plugins {
id("com.google.devtools.ksp") version "2.3.4" // Or latest version of KSP
}
dependencies {
ksp("com.squareup.moshi:moshi-kotlin-codegen:2.0.0-alpha.1")
}
```
</details>
#### Limitations
If your Kotlin class has a superclass, it must also be a Kotlin class. Neither reflection or codegen
support Kotlin types with Java supertypes or Java types with Kotlin supertypes. If you need to
convert such classes to JSON you must create a custom type adapter.
The JSON encoding of Kotlin types is the same whether using reflection or codegen. Prefer codegen
for better performance and to avoid the `kotlin-reflect` dependency; prefer reflection to convert
both private and protected properties. If you have configured both, generated adapters will be used
on types that are annotated `@JsonClass(generateAdapter = true)`.
Download
--------
Download [the latest JAR][dl] or depend via Maven:
```xml
<dependency>
<groupId>com.squareup.moshi</groupId>
<artifactId>moshi</artifactId>
<version>1.15.2</version>
</dependency>
```
or Gradle:
```kotlin
implementation("com.squareup.moshi:moshi:2.0.0-alpha.1")
```
Snapshots of the development version are available in [the Central Portal Snapshots repository][snap].
R8 / ProGuard
--------
Moshi contains minimally required rules for its own internals to work without need for consumers to embed their own. However if you are using reflective serialization and R8 or ProGuard, you must add keep rules in your proguard configuration file for your reflectively serialized classes.
#### Enums
Annotate enums with `@JsonClass(generateAdapter = false)` to prevent them from being removed/obfuscated from your code by R8/ProGuard.
License
--------
Copyright 2015 Square, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
[dl]: https://search.maven.org/classic/remote_content?g=com.squareup.moshi&a=moshi&v=LATEST
[snap]: https://central.sonatype.com/repository/maven-snapshots/
[okio]: https://github.com/square/okio/
[okhttp]: https://github.com/square/okhttp/
[gson]: https://github.com/google/gson/
[javadoc]: https://square.github.io/moshi/1.x/moshi/
[ksp]: https://github.com/google/ksp
================================================
FILE: build.gradle.kts
================================================
import com.diffplug.gradle.spotless.JavaExtension
import com.vanniktech.maven.publish.MavenPublishBaseExtension
import java.net.URI
import org.jetbrains.dokka.gradle.DokkaExtension
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
buildscript {
dependencies {
val kotlinVersion = System.getenv("MOSHI_KOTLIN_VERSION") ?: libs.versions.kotlin.get()
val kspVersion = System.getenv("MOSHI_KSP_VERSION") ?: libs.versions.ksp.get()
classpath(kotlin("gradle-plugin", version = kotlinVersion))
classpath("com.google.devtools.ksp:symbol-processing-gradle-plugin:$kspVersion")
}
}
plugins {
alias(libs.plugins.mavenPublish) apply false
alias(libs.plugins.dokka)
alias(libs.plugins.spotless)
alias(libs.plugins.japicmp) apply false
alias(libs.plugins.ksp) apply false
}
allprojects {
group = "com.squareup.moshi"
version = project.property("VERSION_NAME") as String
repositories { mavenCentral() }
}
spotless {
format("misc") {
target("*.md", ".gitignore")
trimTrailingWhitespace()
leadingTabsToSpaces(2)
endWithNewline()
}
val configureCommonJavaFormat: JavaExtension.() -> Unit = {
googleJavaFormat(libs.googleJavaFormat.get().version)
}
java {
configureCommonJavaFormat()
target("**/*.java")
targetExclude("**/build/**")
}
kotlin {
ktfmt(libs.ktfmt.get().version).googleStyle()
target("**/*.kt")
trimTrailingWhitespace()
endWithNewline()
targetExclude("**/Dependencies.kt", "**/build/**")
}
kotlinGradle {
ktfmt(libs.ktfmt.get().version).googleStyle()
target("**/*.gradle.kts")
trimTrailingWhitespace()
endWithNewline()
}
}
subprojects {
// Apply with "java" instead of just "java-library" so kotlin projects get it too
pluginManager.withPlugin("java") {
configure<JavaPluginExtension> {
toolchain { languageVersion.set(libs.versions.jdk.map(JavaLanguageVersion::of)) }
}
if (project.name != "records-tests") {
tasks.withType<JavaCompile>().configureEach { options.release.set(8) }
}
}
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
tasks.withType<KotlinCompile>().configureEach {
compilerOptions {
progressiveMode.set(true)
jvmTarget.set(JvmTarget.fromTarget(libs.versions.jvmTarget.get()))
}
}
configure<KotlinProjectExtension> {
if (project.name != "examples") {
explicitApi()
}
}
}
}
dependencies {
dokka(project(":moshi"))
dokka(project(":moshi-adapters"))
dokka(project(":moshi-kotlin"))
dokka(project(":moshi-kotlin-codegen"))
}
dokka { dokkaPublications.html { outputDirectory.set(layout.projectDirectory.dir("docs/2.x")) } }
subprojects {
plugins.withId("org.jetbrains.dokka") {
configure<DokkaExtension> {
basePublicationsDirectory.set(layout.buildDirectory.dir("dokkaDir"))
dokkaSourceSets.configureEach {
skipDeprecated.set(true)
reportUndocumented.set(true)
jdkVersion.set(8)
perPackageOption {
matchingRegex.set("com\\.squareup\\.moshi\\.internal.*")
suppress.set(true)
}
externalDocumentationLinks.register("Okio") {
packageListUrl("https://square.github.io/okio/3.x/okio/okio/package-list")
url("https://square.github.io/okio/3.x/okio")
}
sourceLink {
localDirectory.set(layout.projectDirectory.dir("src"))
val relPath =
rootProject.isolated.projectDirectory.asFile.toPath().relativize(projectDir.toPath())
remoteUrl("https://github.com/square/moshi/tree/main/$relPath/src")
remoteLineSuffix.set("#L")
}
}
}
}
plugins.withId("com.vanniktech.maven.publish") {
configure<PublishingExtension> {
repositories {
/*
* Want to push to an internal repository for testing?
* Set the following properties in ~/.gradle/gradle.properties.
*
* internalUrl=YOUR_INTERNAL_URL
* internalUsername=YOUR_USERNAME
* internalPassword=YOUR_PASSWORD
*
* Then run the following command to publish a new internal release:
*
* ./gradlew publishAllPublicationsToInternalRepository -DRELEASE_SIGNING_ENABLED=false
*/
val internalUrl = providers.gradleProperty("internalUrl").orNull
if (internalUrl != null) {
maven {
name = "internal"
url = URI(internalUrl)
credentials {
username = providers.gradleProperty("internalUsername").get()
password = providers.gradleProperty("internalPassword").get()
}
}
}
}
}
configure<MavenPublishBaseExtension> {
publishToMavenCentral(automaticRelease = true)
signAllPublications()
pom {
description.set("A modern JSON API for Android and Java")
name.set(project.name)
url.set("https://github.com/square/moshi/")
licenses {
license {
name.set("The Apache Software License, Version 2.0")
url.set("https://www.apache.org/licenses/LICENSE-2.0.txt")
distribution.set("repo")
}
}
scm {
url.set("https://github.com/square/moshi/")
connection.set("scm:git:git://github.com/square/moshi.git")
developerConnection.set("scm:git:ssh://git@github.com/square/moshi.git")
}
developers {
developer {
id.set("square")
name.set("Square, Inc.")
}
}
}
}
}
}
================================================
FILE: examples/build.gradle.kts
================================================
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm")
alias(libs.plugins.ksp)
}
dependencies {
ksp(project(":moshi-kotlin-codegen"))
compileOnly(libs.jsr305)
implementation(project(":moshi"))
implementation(project(":moshi-adapters"))
}
tasks.withType<KotlinCompile>().configureEach {
compilerOptions { freeCompilerArgs.add("-opt-in=kotlin.ExperimentalStdlibApi") }
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/ByteStrings.java
================================================
/*
* Copyright (C) 2018 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import com.squareup.moshi.Moshi;
import java.io.IOException;
import okio.ByteString;
public final class ByteStrings {
public void run() throws Exception {
String json = "\"TW9zaGksIE9saXZlLCBXaGl0ZSBDaGluPw\"";
Moshi moshi = new Moshi.Builder().add(ByteString.class, new Base64ByteStringAdapter()).build();
JsonAdapter<ByteString> jsonAdapter = moshi.adapter(ByteString.class);
ByteString byteString = jsonAdapter.fromJson(json);
System.out.println(byteString);
}
/**
* Formats byte strings using <a href="http://www.ietf.org/rfc/rfc2045.txt">Base64</a>. No line
* breaks or whitespace is included in the encoded form.
*/
public final class Base64ByteStringAdapter extends JsonAdapter<ByteString> {
@Override
public ByteString fromJson(JsonReader reader) throws IOException {
String base64 = reader.nextString();
return ByteString.decodeBase64(base64);
}
@Override
public void toJson(JsonWriter writer, ByteString value) throws IOException {
String string = value.base64();
writer.value(string);
}
}
public static void main(String[] args) throws Exception {
new ByteStrings().run();
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/CardAdapter.java
================================================
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import com.squareup.moshi.FromJson;
import com.squareup.moshi.JsonDataException;
import com.squareup.moshi.ToJson;
import com.squareup.moshi.recipes.models.Card;
import com.squareup.moshi.recipes.models.Suit;
public final class CardAdapter {
@ToJson
String toJson(Card card) {
return card.rank + card.suit.name().substring(0, 1);
}
@FromJson
Card fromJson(String card) {
if (card.length() != 2) throw new JsonDataException("Unknown card: " + card);
char rank = card.charAt(0);
switch (card.charAt(1)) {
case 'C':
return new Card(rank, Suit.CLUBS);
case 'D':
return new Card(rank, Suit.DIAMONDS);
case 'H':
return new Card(rank, Suit.HEARTS);
case 'S':
return new Card(rank, Suit.SPADES);
default:
throw new JsonDataException("unknown suit: " + card);
}
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/CustomAdapterFactory.java
================================================
/*
* Copyright (C) 2018 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.Types;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.annotation.Nullable;
public final class CustomAdapterFactory {
public void run() throws Exception {
Moshi moshi = new Moshi.Builder().add(new SortedSetAdapterFactory()).build();
JsonAdapter<SortedSet<String>> jsonAdapter =
moshi.adapter(Types.newParameterizedType(SortedSet.class, String.class));
TreeSet<String> model = new TreeSet<>();
model.add("a");
model.add("b");
model.add("c");
String json = jsonAdapter.toJson(model);
System.out.println(json);
}
/**
* This class composes an adapter for any element type into an adapter for a sorted set of those
* elements. For example, given a {@code JsonAdapter<MovieTicket>}, use this to get a {@code
* JsonAdapter<SortedSet<MovieTicket>>}. It works by looping over the input elements when both
* reading and writing.
*/
static final class SortedSetAdapter<T> extends JsonAdapter<SortedSet<T>> {
private final JsonAdapter<T> elementAdapter;
SortedSetAdapter(JsonAdapter<T> elementAdapter) {
this.elementAdapter = elementAdapter;
}
@Override
public SortedSet<T> fromJson(JsonReader reader) throws IOException {
TreeSet<T> result = new TreeSet<>();
reader.beginArray();
while (reader.hasNext()) {
result.add(elementAdapter.fromJson(reader));
}
reader.endArray();
return result;
}
@Override
public void toJson(JsonWriter writer, SortedSet<T> set) throws IOException {
writer.beginArray();
for (T element : set) {
elementAdapter.toJson(writer, element);
}
writer.endArray();
}
}
/**
* Moshi asks this class to create JSON adapters. It only knows how to create JSON adapters for
* {@code SortedSet} types, so it returns null for all other requests. When it does get a request
* for a {@code SortedSet<X>}, it asks Moshi for an adapter of the element type {@code X} and then
* uses that to create an adapter for the set.
*/
static class SortedSetAdapterFactory implements JsonAdapter.Factory {
@Override
public @Nullable JsonAdapter<?> create(
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
if (!annotations.isEmpty()) {
return null; // Annotations? This factory doesn't apply.
}
if (!(type instanceof ParameterizedType)) {
return null; // No type parameter? This factory doesn't apply.
}
ParameterizedType parameterizedType = (ParameterizedType) type;
if (parameterizedType.getRawType() != SortedSet.class) {
return null; // Not a sorted set? This factory doesn't apply.
}
Type elementType = parameterizedType.getActualTypeArguments()[0];
JsonAdapter<Object> elementAdapter = moshi.adapter(elementType);
return new SortedSetAdapter<>(elementAdapter).nullSafe();
}
}
public static void main(String[] args) throws Exception {
new CustomAdapterFactory().run();
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/CustomAdapterWithDelegate.java
================================================
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import com.squareup.moshi.FromJson;
import com.squareup.moshi.Json;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.Moshi;
import java.io.IOException;
import javax.annotation.Nullable;
public final class CustomAdapterWithDelegate {
public void run() throws Exception {
// We want to match any Stage that starts with 'in-progress' as Stage.IN_PROGRESS
// and leave the rest of the enum values as to match as normal.
Moshi moshi = new Moshi.Builder().add(new StageAdapter()).build();
JsonAdapter<Stage> jsonAdapter = moshi.adapter(Stage.class);
System.out.println(jsonAdapter.fromJson("\"not-started\""));
System.out.println(jsonAdapter.fromJson("\"in-progress\""));
System.out.println(jsonAdapter.fromJson("\"in-progress-step1\""));
}
public static void main(String[] args) throws Exception {
new CustomAdapterWithDelegate().run();
}
private enum Stage {
@Json(name = "not-started")
NOT_STARTED,
@Json(name = "in-progress")
IN_PROGRESS,
@Json(name = "rejected")
REJECTED,
@Json(name = "completed")
COMPLETED
}
private static final class StageAdapter {
@FromJson
@Nullable
Stage fromJson(JsonReader jsonReader, JsonAdapter<Stage> delegate) throws IOException {
String value = jsonReader.nextString();
Stage stage;
if (value.startsWith("in-progress")) {
stage = Stage.IN_PROGRESS;
} else {
stage = delegate.fromJsonValue(value);
}
return stage;
}
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/CustomFieldName.java
================================================
/*
* Copyright (C) 2016 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.recipes.models.Player;
public final class CustomFieldName {
public void run() throws Exception {
String json = "" + "{" + " \"username\": \"jesse\"," + " \"lucky number\": 32" + "}\n";
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<Player> jsonAdapter = moshi.adapter(Player.class);
Player player = jsonAdapter.fromJson(json);
System.out.println(player);
}
public static void main(String[] args) throws Exception {
new CustomFieldName().run();
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/CustomQualifier.java
================================================
/*
* Copyright (C) 2016 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.squareup.moshi.FromJson;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonQualifier;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.ToJson;
import java.lang.annotation.Retention;
public final class CustomQualifier {
public void run() throws Exception {
String json =
""
+ "{\n"
+ " \"color\": \"#ff0000\",\n"
+ " \"height\": 768,\n"
+ " \"width\": 1024\n"
+ "}\n";
Moshi moshi = new Moshi.Builder().add(new ColorAdapter()).build();
JsonAdapter<Rectangle> jsonAdapter = moshi.adapter(Rectangle.class);
Rectangle rectangle = jsonAdapter.fromJson(json);
System.out.println(rectangle);
}
public static void main(String[] args) throws Exception {
new CustomQualifier().run();
}
static class Rectangle {
int width;
int height;
@HexColor int color;
@Override
public String toString() {
return String.format("%dx%d #%06x", width, height, color);
}
}
@Retention(RUNTIME)
@JsonQualifier
public @interface HexColor {}
static class ColorAdapter {
@ToJson
String toJson(@HexColor int rgb) {
return String.format("#%06x", rgb);
}
@FromJson
@HexColor
int fromJson(String rgb) {
return Integer.parseInt(rgb.substring(1), 16);
}
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/CustomTypeAdapter.java
================================================
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.recipes.models.BlackjackHand;
public final class CustomTypeAdapter {
public void run() throws Exception {
String json =
""
+ "{\n"
+ " \"hidden_card\": \"6S\",\n"
+ " \"visible_cards\": [\n"
+ " \"4C\",\n"
+ " \"AH\"\n"
+ " ]\n"
+ "}\n";
Moshi moshi = new Moshi.Builder().add(new CardAdapter()).build();
JsonAdapter<BlackjackHand> jsonAdapter = moshi.adapter(BlackjackHand.class);
BlackjackHand blackjackHand = jsonAdapter.fromJson(json);
System.out.println(blackjackHand);
}
public static void main(String[] args) throws Exception {
new CustomTypeAdapter().run();
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/DefaultOnDataMismatchAdapter.java
================================================
/*
* Copyright (C) 2017 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonDataException;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import com.squareup.moshi.Moshi;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Set;
import javax.annotation.Nullable;
public final class DefaultOnDataMismatchAdapter<T> extends JsonAdapter<T> {
private final JsonAdapter<T> delegate;
private final T defaultValue;
private DefaultOnDataMismatchAdapter(JsonAdapter<T> delegate, T defaultValue) {
this.delegate = delegate;
this.defaultValue = defaultValue;
}
@Override
public T fromJson(JsonReader reader) throws IOException {
// Use a peeked reader to leave the reader in a known state even if there's an exception.
JsonReader peeked = reader.peekJson();
T result;
try {
// Attempt to decode to the target type with the peeked reader.
result = delegate.fromJson(peeked);
} catch (JsonDataException e) {
result = defaultValue;
} finally {
peeked.close();
}
// Skip the value back on the reader, no matter the state of the peeked reader.
reader.skipValue();
return result;
}
@Override
public void toJson(JsonWriter writer, T value) throws IOException {
delegate.toJson(writer, value);
}
public static <T> Factory newFactory(final Class<T> type, final T defaultValue) {
return new Factory() {
@Override
public @Nullable JsonAdapter<?> create(
Type requestedType, Set<? extends Annotation> annotations, Moshi moshi) {
if (type != requestedType) return null;
JsonAdapter<T> delegate = moshi.nextAdapter(this, type, annotations);
return new DefaultOnDataMismatchAdapter<>(delegate, defaultValue);
}
};
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/FallbackEnum.java
================================================
/*
* Copyright (C) 2018 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonQualifier;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.Types;
import com.squareup.moshi.internal.Util;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.reflect.Type;
import java.util.Set;
import javax.annotation.Nullable;
final class FallbackEnum {
@Retention(RUNTIME)
@JsonQualifier
public @interface Fallback {
/** The enum name. */
String value();
}
public static final class FallbackEnumJsonAdapter<T extends Enum<T>> extends JsonAdapter<T> {
public static final Factory FACTORY =
new Factory() {
@Nullable
@Override
@SuppressWarnings("unchecked")
public JsonAdapter<?> create(
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
Class<?> rawType = Types.getRawType(type);
if (!rawType.isEnum()) {
return null;
}
if (annotations.size() != 1) {
return null;
}
Annotation annotation = annotations.iterator().next();
if (!(annotation instanceof Fallback)) {
return null;
}
//noinspection rawtypes
return new FallbackEnumJsonAdapter<>(
(Class<? extends Enum>) rawType, ((Fallback) annotation).value());
}
};
final Class<T> enumType;
final String[] nameStrings;
final T[] constants;
final JsonReader.Options options;
final T defaultValue;
FallbackEnumJsonAdapter(Class<T> enumType, String fallbackName) {
this.enumType = enumType;
this.defaultValue = Enum.valueOf(enumType, fallbackName);
try {
constants = enumType.getEnumConstants();
nameStrings = new String[constants.length];
for (int i = 0; i < constants.length; i++) {
String constantName = constants[i].name();
nameStrings[i] = Util.jsonName(enumType.getField(constantName), constantName);
}
options = JsonReader.Options.of(nameStrings);
} catch (NoSuchFieldException e) {
throw new AssertionError(e);
}
}
@Override
public T fromJson(JsonReader reader) throws IOException {
int index = reader.selectString(options);
if (index != -1) return constants[index];
reader.nextString();
return defaultValue;
}
@Override
public void toJson(JsonWriter writer, T value) throws IOException {
writer.value(nameStrings[value.ordinal()]);
}
@Override
public String toString() {
return "JsonAdapter(" + enumType.getName() + ").defaultValue( " + defaultValue + ")";
}
}
static final class Example {
enum Transportation {
WALKING,
BIKING,
TRAINS,
PLANES
}
@Fallback("WALKING")
final Transportation transportation;
Example(Transportation transportation) {
this.transportation = transportation;
}
@Override
public String toString() {
return transportation.toString();
}
}
public static void main(String[] args) throws Exception {
Moshi moshi = new Moshi.Builder().add(FallbackEnumJsonAdapter.FACTORY).build();
JsonAdapter<Example> adapter = moshi.adapter(Example.class);
System.out.println(adapter.fromJson("{\"transportation\":\"CARS\"}"));
}
private FallbackEnum() {}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/FromJsonWithoutStrings.java
================================================
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import com.squareup.moshi.FromJson;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.ToJson;
public final class FromJsonWithoutStrings {
public void run() throws Exception {
// For some reason our JSON has date and time as separate fields. We will clean that up during
// parsing: Moshi will first parse the JSON directly to an EventJson and from that the
// EventJsonAdapter will create the actual Event.
String json =
""
+ "{\n"
+ " \"title\": \"Blackjack tournament\",\n"
+ " \"begin_date\": \"20151010\",\n"
+ " \"begin_time\": \"17:04\"\n"
+ "}\n";
Moshi moshi = new Moshi.Builder().add(new EventJsonAdapter()).build();
JsonAdapter<Event> jsonAdapter = moshi.adapter(Event.class);
Event event = jsonAdapter.fromJson(json);
System.out.println(event);
System.out.println(jsonAdapter.toJson(event));
}
public static void main(String[] args) throws Exception {
new FromJsonWithoutStrings().run();
}
private static final class EventJson {
String title;
String begin_date;
String begin_time;
}
public static final class Event {
String title;
String beginDateAndTime;
@Override
public String toString() {
return "Event{"
+ "title='"
+ title
+ '\''
+ ", beginDateAndTime='"
+ beginDateAndTime
+ '\''
+ '}';
}
}
private static final class EventJsonAdapter {
@FromJson
Event eventFromJson(EventJson eventJson) {
Event event = new Event();
event.title = eventJson.title;
event.beginDateAndTime = eventJson.begin_date + " " + eventJson.begin_time;
return event;
}
@ToJson
EventJson eventToJson(Event event) {
EventJson json = new EventJson();
json.title = event.title;
json.begin_date = event.beginDateAndTime.substring(0, 8);
json.begin_time = event.beginDateAndTime.substring(9, 14);
return json;
}
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/IncludeNullsForAnnotatedTypes.java
================================================
/*
* Copyright (C) 2020 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.Types;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Type;
import java.util.Set;
public final class IncludeNullsForAnnotatedTypes {
public void run() throws Exception {
Moshi moshi = new Moshi.Builder().add(new AlwaysSerializeNullsFactory()).build();
JsonAdapter<Driver> driverAdapter = moshi.adapter(Driver.class);
Car car = new Car();
car.make = "Ford";
car.model = "Mach-E";
car.color = null; // This null will show up in the JSON because Car has @AlwaysSerializeNulls.
Driver driver = new Driver();
driver.name = "Jesse";
driver.emailAddress = null; // This null will be omitted.
driver.favoriteCar = car;
System.out.println(driverAdapter.toJson(driver));
}
@Target(TYPE)
@Retention(RUNTIME)
public @interface AlwaysSerializeNulls {}
@AlwaysSerializeNulls
static class Car {
String make;
String model;
String color;
}
static class Driver {
String name;
String emailAddress;
Car favoriteCar;
}
static class AlwaysSerializeNullsFactory implements JsonAdapter.Factory {
@Override
public JsonAdapter<?> create(Type type, Set<? extends Annotation> annotations, Moshi moshi) {
Class<?> rawType = Types.getRawType(type);
if (!rawType.isAnnotationPresent(AlwaysSerializeNulls.class)) {
return null;
}
JsonAdapter<Object> delegate = moshi.nextAdapter(this, type, annotations);
return delegate.serializeNulls();
}
}
public static void main(String[] args) throws Exception {
new IncludeNullsForAnnotatedTypes().run();
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/IncludeNullsForOneType.java
================================================
/*
* Copyright (C) 2020 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonWriter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.ToJson;
import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter;
import com.squareup.moshi.recipes.models.Tournament;
import java.io.IOException;
import java.util.Date;
public final class IncludeNullsForOneType {
public void run() throws Exception {
Moshi moshi =
new Moshi.Builder()
.add(Date.class, new Rfc3339DateJsonAdapter())
.add(new TournamentWithNullsAdapter())
.build();
JsonAdapter<Tournament> tournamentAdapter = moshi.adapter(Tournament.class);
// Moshi normally skips nulls, but with our adapter registered they are emitted.
Tournament withNulls = new Tournament("Waterloo Classic", null, null);
System.out.println(tournamentAdapter.toJson(withNulls));
}
public static final class TournamentWithNullsAdapter {
@ToJson
void toJson(JsonWriter writer, Tournament tournament, JsonAdapter<Tournament> delegate)
throws IOException {
boolean wasSerializeNulls = writer.getSerializeNulls();
writer.setSerializeNulls(true);
try {
// Once we've customized the JSON writer, we let the default JSON adapter do its job.
delegate.toJson(writer, tournament);
} finally {
writer.setLenient(wasSerializeNulls);
}
}
}
public static void main(String[] args) throws Exception {
new IncludeNullsForOneType().run();
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/JsonString.kt
================================================
/*
* Copyright (C) 2020 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonClass
import com.squareup.moshi.JsonQualifier
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import com.squareup.moshi.Moshi
import com.squareup.moshi.Moshi.Builder
import com.squareup.moshi.Types
import java.lang.reflect.Type
import kotlin.annotation.AnnotationRetention.RUNTIME
import okio.BufferedSource
@JsonClass(generateAdapter = true)
data class ExampleClass(val type: Int, @JsonString val rawJson: String)
@Retention(RUNTIME) @JsonQualifier annotation class JsonString
class JsonStringJsonAdapterFactory : JsonAdapter.Factory {
override fun create(type: Type, annotations: Set<Annotation>, moshi: Moshi): JsonAdapter<*>? {
if (type != String::class.java) return null
Types.nextAnnotations(annotations, JsonString::class.java) ?: return null
return JsonStringJsonAdapter().nullSafe()
}
private class JsonStringJsonAdapter : JsonAdapter<String>() {
override fun fromJson(reader: JsonReader): String =
reader.nextSource().use(BufferedSource::readUtf8)
override fun toJson(writer: JsonWriter, value: String) {
writer.valueSink().use { sink -> sink.writeUtf8(value) }
}
}
}
fun main() {
// language=JSON
val json = "{\"type\":1,\"rawJson\":{\"a\":2,\"b\":3,\"c\":[1,2,3]}}"
val moshi = Builder().add(JsonStringJsonAdapterFactory()).build()
val example: ExampleClass = moshi.adapter<ExampleClass>().fromJson(json)
check(example.type == 1)
// language=JSON
check(example.rawJson == "{\"a\":2,\"b\":3,\"c\":[1,2,3]}")
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/MultipleFormats.java
================================================
/*
* Copyright (C) 2018 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import com.squareup.moshi.FromJson;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonDataException;
import com.squareup.moshi.JsonQualifier;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.ToJson;
import com.squareup.moshi.recipes.models.Card;
import com.squareup.moshi.recipes.models.Suit;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public final class MultipleFormats {
public void run() throws Exception {
Moshi moshi =
new Moshi.Builder()
.add(new MultipleFormatsCardAdapter())
.add(new CardStringAdapter())
.build();
JsonAdapter<Card> cardAdapter = moshi.adapter(Card.class);
// Decode cards from one format or the other.
System.out.println(cardAdapter.fromJson("\"5D\""));
System.out.println(cardAdapter.fromJson("{\"suit\": \"SPADES\", \"rank\": 5}"));
// Cards are always encoded as strings.
System.out.println(cardAdapter.toJson(new Card('5', Suit.CLUBS)));
}
/** Handles cards either as strings "5D" or as objects {"suit": "SPADES", "rank": 5}. */
public final class MultipleFormatsCardAdapter {
@ToJson
void toJson(JsonWriter writer, Card value, @CardString JsonAdapter<Card> stringAdapter)
throws IOException {
stringAdapter.toJson(writer, value);
}
@FromJson
Card fromJson(
JsonReader reader,
@CardString JsonAdapter<Card> stringAdapter,
JsonAdapter<Card> defaultAdapter)
throws IOException {
if (reader.peek() == JsonReader.Token.STRING) {
return stringAdapter.fromJson(reader);
} else {
return defaultAdapter.fromJson(reader);
}
}
}
/** Handles cards as strings only. */
public final class CardStringAdapter {
@ToJson
String toJson(@CardString Card card) {
return card.rank + card.suit.name().substring(0, 1);
}
@FromJson
@CardString
Card fromJson(String card) {
if (card.length() != 2) throw new JsonDataException("Unknown card: " + card);
char rank = card.charAt(0);
switch (card.charAt(1)) {
case 'C':
return new Card(rank, Suit.CLUBS);
case 'D':
return new Card(rank, Suit.DIAMONDS);
case 'H':
return new Card(rank, Suit.HEARTS);
case 'S':
return new Card(rank, Suit.SPADES);
default:
throw new JsonDataException("unknown suit: " + card);
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@JsonQualifier
@interface CardString {}
public static void main(String[] args) throws Exception {
new MultipleFormats().run();
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/ReadAndWriteRfc3339Dates.java
================================================
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter;
import com.squareup.moshi.recipes.models.Tournament;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
public final class ReadAndWriteRfc3339Dates {
public void run() throws Exception {
Moshi moshi = new Moshi.Builder().add(Date.class, new Rfc3339DateJsonAdapter()).build();
JsonAdapter<Tournament> jsonAdapter = moshi.adapter(Tournament.class);
// The RFC3339 JSON adapter can read dates with a timezone offset like '-05:00'.
String lastTournament =
""
+ "{"
+ " \"location\":\"Chainsaw\","
+ " \"name\":\"21 for 21\","
+ " \"start\":\"2015-09-01T20:00:00-05:00\""
+ "}";
System.out.println("Last tournament: " + jsonAdapter.fromJson(lastTournament));
// The RFC3339 JSON adapter always writes dates with UTC, using a 'Z' suffix.
Tournament nextTournament =
new Tournament("Waterloo Classic", "Bauer Kitchen", newDate(2015, 10, 1, 20, -5));
System.out.println("Next tournament JSON: " + jsonAdapter.toJson(nextTournament));
}
public static void main(String[] args) throws Exception {
new ReadAndWriteRfc3339Dates().run();
}
private Date newDate(int year, int month, int day, int hour, int offset) {
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
calendar.set(year, month - 1, day, hour, 0, 0);
calendar.set(Calendar.MILLISECOND, 0);
return new Date(calendar.getTimeInMillis() - TimeUnit.HOURS.toMillis(offset));
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/ReadJson.java
================================================
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.recipes.models.BlackjackHand;
public final class ReadJson {
public void run() throws Exception {
String json =
""
+ "{\n"
+ " \"hidden_card\": {\n"
+ " \"rank\": \"6\",\n"
+ " \"suit\": \"SPADES\"\n"
+ " },\n"
+ " \"visible_cards\": [\n"
+ " {\n"
+ " \"rank\": \"4\",\n"
+ " \"suit\": \"CLUBS\"\n"
+ " },\n"
+ " {\n"
+ " \"rank\": \"A\",\n"
+ " \"suit\": \"HEARTS\"\n"
+ " }\n"
+ " ]\n"
+ "}\n";
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<BlackjackHand> jsonAdapter = moshi.adapter(BlackjackHand.class);
BlackjackHand blackjackHand = jsonAdapter.fromJson(json);
System.out.println(blackjackHand);
}
public static void main(String[] args) throws Exception {
new ReadJson().run();
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/ReadJsonList.java
================================================
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.Types;
import com.squareup.moshi.recipes.models.Card;
import java.lang.reflect.Type;
import java.util.List;
public final class ReadJsonList {
public void run() throws Exception {
String json =
""
+ "[\n"
+ " {\n"
+ " \"rank\": \"4\",\n"
+ " \"suit\": \"CLUBS\"\n"
+ " },\n"
+ " {\n"
+ " \"rank\": \"A\",\n"
+ " \"suit\": \"HEARTS\"\n"
+ " },\n"
+ " {\n"
+ " \"rank\": \"J\",\n"
+ " \"suit\": \"SPADES\"\n"
+ " }\n"
+ "]";
Moshi moshi = new Moshi.Builder().build();
Type listOfCardsType = Types.newParameterizedType(List.class, Card.class);
JsonAdapter<List<Card>> jsonAdapter = moshi.adapter(listOfCardsType);
List<Card> cards = jsonAdapter.fromJson(json);
System.out.println(cards);
}
public static void main(String[] args) throws Exception {
new ReadJsonList().run();
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/ReadJsonListKt.kt
================================================
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapter
import com.squareup.moshi.recipes.models.Card
class ReadJsonListKt {
// language=JSON
private val jsonString =
"""
[{"rank": "4",
"suit": "CLUBS"
},
{"rank": "A",
"suit": "HEARTS"
},
{"rank": "J",
"suit": "SPADES"
}]
"""
.trimIndent()
fun readJsonList() {
val jsonAdapter = Moshi.Builder().build().adapter<List<Card>>()
val cards = jsonAdapter.fromJson(jsonString)
println(cards)
cards[0].run {
println(rank)
println(suit)
}
}
}
fun main() {
ReadJsonListKt().readJsonList()
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/RecoverFromTypeMismatch.java
================================================
/*
* Copyright (C) 2017 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.Types;
import com.squareup.moshi.recipes.models.Suit;
import java.util.List;
public final class RecoverFromTypeMismatch {
public void run() throws Exception {
String json = "[\"DIAMONDS\", \"STARS\", \"HEARTS\"]";
Moshi moshi =
new Moshi.Builder()
.add(DefaultOnDataMismatchAdapter.newFactory(Suit.class, Suit.CLUBS))
.build();
JsonAdapter<List<Suit>> jsonAdapter =
moshi.adapter(Types.newParameterizedType(List.class, Suit.class));
List<Suit> suits = jsonAdapter.fromJson(json);
System.out.println(suits);
}
public static void main(String[] args) throws Exception {
new RecoverFromTypeMismatch().run();
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/Unwrap.java
================================================
/*
* Copyright (C) 2017 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonQualifier;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.Types;
import com.squareup.moshi.recipes.Unwrap.EnvelopeJsonAdapter.Enveloped;
import com.squareup.moshi.recipes.models.Card;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.reflect.Type;
import java.util.Set;
import javax.annotation.Nullable;
final class Unwrap {
private Unwrap() {}
public static void main(String[] args) throws Exception {
String json =
""
+ "{\"data\":"
+ " {\n"
+ " \"rank\": \"4\",\n"
+ " \"suit\": \"CLUBS\"\n"
+ " }"
+ "}";
Moshi moshi = new Moshi.Builder().add(EnvelopeJsonAdapter.FACTORY).build();
JsonAdapter<Card> adapter = moshi.adapter(Card.class, Enveloped.class);
Card out = adapter.fromJson(json);
System.out.println(out);
}
public static final class EnvelopeJsonAdapter extends JsonAdapter<Object> {
public static final JsonAdapter.Factory FACTORY =
new Factory() {
@Override
public @Nullable JsonAdapter<?> create(
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
Set<? extends Annotation> delegateAnnotations =
Types.nextAnnotations(annotations, Enveloped.class);
if (delegateAnnotations == null) {
return null;
}
Type envelope =
Types.newParameterizedTypeWithOwner(
EnvelopeJsonAdapter.class, Envelope.class, type);
JsonAdapter<Envelope<?>> delegate =
moshi.nextAdapter(this, envelope, delegateAnnotations);
return new EnvelopeJsonAdapter(delegate);
}
};
@Retention(RUNTIME)
@JsonQualifier
public @interface Enveloped {}
private static final class Envelope<T> {
final T data;
Envelope(T data) {
this.data = data;
}
}
private final JsonAdapter<Envelope<?>> delegate;
EnvelopeJsonAdapter(JsonAdapter<Envelope<?>> delegate) {
this.delegate = delegate;
}
@Override
public Object fromJson(JsonReader reader) throws IOException {
return delegate.fromJson(reader).data;
}
@Override
public void toJson(JsonWriter writer, Object value) throws IOException {
delegate.toJson(writer, new Envelope<>(value));
}
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/WriteJson.java
================================================
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes;
import static com.squareup.moshi.recipes.models.Suit.CLUBS;
import static com.squareup.moshi.recipes.models.Suit.HEARTS;
import static com.squareup.moshi.recipes.models.Suit.SPADES;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.recipes.models.BlackjackHand;
import com.squareup.moshi.recipes.models.Card;
import java.util.Arrays;
public final class WriteJson {
public void run() throws Exception {
BlackjackHand blackjackHand =
new BlackjackHand(
new Card('6', SPADES), Arrays.asList(new Card('4', CLUBS), new Card('A', HEARTS)));
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<BlackjackHand> jsonAdapter = moshi.adapter(BlackjackHand.class);
String json = jsonAdapter.toJson(blackjackHand);
System.out.println(json);
}
public static void main(String[] args) throws Exception {
new WriteJson().run();
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/models/BlackjackHand.java
================================================
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes.models;
import java.util.List;
public final class BlackjackHand {
public final Card hidden_card;
public final List<Card> visible_cards;
public BlackjackHand(Card hiddenCard, List<Card> visibleCards) {
this.hidden_card = hiddenCard;
this.visible_cards = visibleCards;
}
@Override
public String toString() {
return "hidden=" + hidden_card + ",visible=" + visible_cards;
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/models/Card.java
================================================
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes.models;
public final class Card {
public final char rank;
public final Suit suit;
public Card(char rank, Suit suit) {
this.rank = rank;
this.suit = suit;
}
@Override
public String toString() {
return String.format("%s%s", rank, suit);
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/models/Player.java
================================================
/*
* Copyright (C) 2016 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes.models;
import com.squareup.moshi.Json;
public final class Player {
public final String username;
public final @Json(name = "lucky number") int luckyNumber;
public Player(String username, int luckyNumber) {
this.username = username;
this.luckyNumber = luckyNumber;
}
@Override
public String toString() {
return username + " gets lucky with " + luckyNumber;
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/models/Suit.java
================================================
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes.models;
public enum Suit {
CLUBS,
DIAMONDS,
HEARTS,
SPADES;
@Override
public String toString() {
return name().substring(0, 1);
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/models/Tournament.java
================================================
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.recipes.models;
import java.util.Date;
public final class Tournament {
public final String name;
public final String location;
public final Date start;
public Tournament(String name, String location, Date start) {
this.name = name;
this.location = location;
this.start = start;
}
@Override
public String toString() {
return name + " at " + location + " on " + start;
}
}
================================================
FILE: examples/src/main/java/com/squareup/moshi/recipes/package-info.java
================================================
/** Moshi code samples. */
@javax.annotation.ParametersAreNonnullByDefault
package com.squareup.moshi.recipes;
================================================
FILE: gradle/libs.versions.toml
================================================
[versions]
autoService = "1.1.1"
jdk = "21"
jvmTarget = "1.8"
kotlin = "2.3.20"
kotlinCompileTesting = "0.12.1"
kotlinpoet = "2.2.0"
ksp = "2.3.6"
[plugins]
dokka = { id = "org.jetbrains.dokka", version = "2.1.0" }
japicmp = { id = "me.champeau.gradle.japicmp", version = "0.4.6" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
mavenPublish = { id = "com.vanniktech.maven.publish", version = "0.36.0" }
spotless = { id = "com.diffplug.spotless", version = "8.4.0" }
[libraries]
asm = "org.ow2.asm:asm:9.9.1"
autoCommon = "com.google.auto:auto-common:1.2.2"
autoService = { module = "com.google.auto.service:auto-service-annotations", version.ref = "autoService" }
autoService-ksp = "dev.zacsweers.autoservice:auto-service-ksp:1.2.0"
jsr305 = "com.google.code.findbugs:jsr305:3.0.2"
kotlin-annotationProcessingEmbeddable = { module = "org.jetbrains.kotlin:kotlin-annotation-processing-embeddable", version.ref = "kotlin" }
kotlin-compilerEmbeddable = { module = "org.jetbrains.kotlin:kotlin-compiler-embeddable", version.ref = "kotlin" }
kotlin-metadata = { module = "org.jetbrains.kotlin:kotlin-metadata-jvm", version.ref = "kotlin" }
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
kotlinpoet = { module = "com.squareup:kotlinpoet", version.ref = "kotlinpoet" }
kotlinpoet-ksp = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlinpoet" }
ksp = { module = "com.google.devtools.ksp:symbol-processing", version.ref = "ksp" }
ksp-api = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" }
okio = "com.squareup.okio:okio:3.17.0"
assertj = "org.assertj:assertj-core:3.27.7"
assertk = "com.willowtreeapps.assertk:assertk:0.28.1"
junit = "junit:junit:4.13.2"
kotlinCompileTesting = { module = "dev.zacsweers.kctfork:core", version.ref = "kotlinCompileTesting" }
kotlinCompileTesting-ksp = { module = "dev.zacsweers.kctfork:ksp", version.ref ="kotlinCompileTesting" }
truth = "com.google.truth:truth:1.4.5"
googleJavaFormat = "com.google.googlejavaformat:google-java-format:1.35.0"
ktfmt = "com.facebook:ktfmt:0.62"
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
================================================
FILE: gradle.properties
================================================
# Memory for Dokka https://github.com/Kotlin/dokka/issues/1405
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
VERSION_NAME=2.0.0-SNAPSHOT
================================================
FILE: gradlew
================================================
#!/bin/sh
#
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
================================================
FILE: gradlew.bat
================================================
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: moshi/build.gradle.kts
================================================
import org.gradle.jvm.tasks.Jar
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm")
id("com.vanniktech.maven.publish")
id("org.jetbrains.dokka")
}
kotlin.target {
val main = compilations.getByName(MAIN_COMPILATION_NAME)
val java16 =
compilations.create("java16") {
associateWith(main)
defaultSourceSet.kotlin.srcDir("src/main/java16")
compileJavaTaskProvider.configure { options.release = 16 }
compileTaskProvider.configure {
(compilerOptions as KotlinJvmCompilerOptions).jvmTarget = JvmTarget.JVM_16
}
}
// Package our actual RecordJsonAdapter from java16 sources in and denote it as an MRJAR
tasks.named<Jar>(artifactsTaskName) {
from(java16.output) {
into("META-INF/versions/16")
exclude("META-INF")
}
manifest { attributes("Multi-Release" to "true") }
}
}
tasks.withType<Test>().configureEach {
// ExtendsPlatformClassWithProtectedField tests a case where we set a protected
// ByteArrayOutputStream.buf field
jvmArgs("--add-opens=java.base/java.io=ALL-UNNAMED")
}
tasks.withType<KotlinCompile>().configureEach {
compilerOptions {
freeCompilerArgs.addAll("-opt-in=kotlin.contracts.ExperimentalContracts", "-Xjvm-default=all")
if (name.contains("test", true)) {
freeCompilerArgs.add("-opt-in=kotlin.ExperimentalStdlibApi")
}
}
}
dependencies {
compileOnly(libs.jsr305)
api(libs.okio)
testCompileOnly(libs.jsr305)
testImplementation(libs.assertk)
testImplementation(libs.junit)
testImplementation(libs.kotlin.reflect)
testImplementation(libs.truth)
}
tasks.withType<Jar>().configureEach {
manifest { attributes("Automatic-Module-Name" to "com.squareup.moshi") }
}
================================================
FILE: moshi/gradle.properties
================================================
kotlin.build.archivesTaskOutputAsFriendModule=false
================================================
FILE: moshi/japicmp/build.gradle.kts
================================================
import me.champeau.gradle.japicmp.JapicmpTask
plugins {
`java-library`
id("me.champeau.gradle.japicmp")
}
val baseline = configurations.create("baseline")
val latest = configurations.create("latest")
dependencies {
baseline("com.squareup.moshi:moshi:1.15.2") {
isTransitive = false
version { strictly("1.14.0") }
}
latest(project(":moshi"))
}
val japicmp =
tasks.register<JapicmpTask>("japicmp") {
dependsOn("jar")
oldClasspath.from(baseline)
newClasspath.from(latest)
onlyBinaryIncompatibleModified.set(true)
failOnModification.set(true)
txtOutputFile.set(layout.buildDirectory.file("reports/japi.txt"))
ignoreMissingClasses.set(true)
includeSynthetic.set(true)
classExcludes.addAll(
// Internal.
"com.squareup.moshi.AdapterMethodsFactory",
"com.squareup.moshi.ClassJsonAdapter",
"com.squareup.moshi.internal.NonNullJsonAdapter",
"com.squareup.moshi.internal.NullSafeJsonAdapter",
"com.squareup.moshi.internal.Util\$GenericArrayTypeImpl",
"com.squareup.moshi.internal.Util\$ParameterizedTypeImpl",
"com.squareup.moshi.internal.Util\$WildcardTypeImpl",
// Package-private
"com.squareup.moshi.RecordJsonAdapter\$ComponentBinding",
"com.squareup.moshi.StandardJsonAdapters",
)
methodExcludes.addAll(
// Was unintentionally open before
"com.squareup.moshi.JsonAdapter#indent(java.lang.String)",
"com.squareup.moshi.internal.Util#hasNullable(java.lang.annotation.Annotation[])",
"com.squareup.moshi.internal.Util#jsonAnnotations(java.lang.annotation.Annotation[])",
"com.squareup.moshi.internal.Util#jsonAnnotations(java.lang.reflect.AnnotatedElement)",
"com.squareup.moshi.internal.Util#jsonName(java.lang.String, com.squareup.moshi.Json)",
"com.squareup.moshi.internal.Util#jsonName(java.lang.String, java.lang.reflect.AnnotatedElement)",
"com.squareup.moshi.internal.Util#resolve(java.lang.reflect.Type, java.lang.Class, java.lang.reflect.Type)",
"com.squareup.moshi.internal.Util#typeAnnotatedWithAnnotations(java.lang.reflect.Type, java.util.Set)",
"com.squareup.moshi.internal.Util#typesMatch(java.lang.reflect.Type, java.lang.reflect.Type)",
)
fieldExcludes.addAll(
// False-positive, class is not public anyway
"com.squareup.moshi.CollectionJsonAdapter#FACTORY",
// Class is not public
"com.squareup.moshi.MapJsonAdapter#FACTORY",
// Class is not public
"com.squareup.moshi.ArrayJsonAdapter#FACTORY",
)
}
tasks.named("check").configure { dependsOn(japicmp) }
================================================
FILE: moshi/records-tests/build.gradle.kts
================================================
plugins { `java-library` }
java { toolchain { languageVersion.set(JavaLanguageVersion.of(17)) } }
tasks.withType<JavaCompile>().configureEach {
// Target 16 to ensure minimum compatibility
options.release.set(16)
}
dependencies {
testImplementation(project(":moshi"))
testCompileOnly(libs.jsr305)
testImplementation(libs.junit)
testImplementation(libs.truth)
}
================================================
FILE: moshi/records-tests/src/test/java/com/squareup/moshi/records/RecordsTest.java
================================================
/*
* Copyright (C) 2021 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi.records;
import static com.google.common.truth.Truth.assertThat;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.junit.Assert.fail;
import com.squareup.moshi.FromJson;
import com.squareup.moshi.Json;
import com.squareup.moshi.JsonDataException;
import com.squareup.moshi.JsonQualifier;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.ToJson;
import com.squareup.moshi.Types;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import okio.Buffer;
import org.junit.Test;
public final class RecordsTest {
private final Moshi moshi = new Moshi.Builder().build();
@Test
public void smokeTest() throws IOException {
var stringAdapter = moshi.adapter(String.class);
var adapter =
moshi
.newBuilder()
.add(CharSequence.class, stringAdapter)
.add(Types.subtypeOf(CharSequence.class), stringAdapter)
.add(Types.supertypeOf(CharSequence.class), stringAdapter)
.build()
.adapter(SmokeTestType.class);
var instance =
new SmokeTestType(
"John",
"Smith",
25,
List.of("American"),
70.5f,
null,
true,
List.of("super wildcards!"),
List.of("extend wildcards!"),
List.of("unbounded"),
List.of("objectList"),
new int[] {1, 2, 3},
new String[] {"fav", "arrays"},
Map.of("italian", "pasta"),
Set.of(List.of(Map.of("someKey", new int[] {1}))),
new Map[] {Map.of("Hello", "value")});
var json = adapter.toJson(instance);
var deserialized = adapter.fromJson(json);
assertThat(deserialized).isEqualTo(instance);
}
public record SmokeTestType(
@Json(name = "first_name") String firstName,
@Json(name = "last_name") String lastName,
int age,
List<String> nationalities,
float weight,
Boolean tattoos, // Boxed primitive test
boolean hasChildren,
List<? super CharSequence> superWildcard,
List<? extends CharSequence> extendsWildcard,
List<?> unboundedWildcard,
List<Object> objectList,
int[] favoriteThreeNumbers,
String[] favoriteArrayValues,
Map<String, String> foodPreferences,
Set<List<Map<String, int[]>>> setListMapArrayInt,
Map<String, Object>[] nestedArray) {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SmokeTestType that = (SmokeTestType) o;
return age == that.age
&& Float.compare(that.weight, weight) == 0
&& hasChildren == that.hasChildren
&& firstName.equals(that.firstName)
&& lastName.equals(that.lastName)
&& nationalities.equals(that.nationalities)
&& Objects.equals(tattoos, that.tattoos)
&& superWildcard.equals(that.superWildcard)
&& extendsWildcard.equals(that.extendsWildcard)
&& unboundedWildcard.equals(that.unboundedWildcard)
&& objectList.equals(that.objectList)
&& Arrays.equals(favoriteThreeNumbers, that.favoriteThreeNumbers)
&& Arrays.equals(favoriteArrayValues, that.favoriteArrayValues)
&& foodPreferences.equals(that.foodPreferences)
// && setListMapArrayInt.equals(that.setListMapArrayInt) // Nested array equality doesn't
// carry over
&& Arrays.equals(nestedArray, that.nestedArray);
}
@Override
public int hashCode() {
int result =
Objects.hash(
firstName,
lastName,
age,
nationalities,
weight,
tattoos,
hasChildren,
superWildcard,
extendsWildcard,
unboundedWildcard,
objectList,
foodPreferences,
setListMapArrayInt);
result = 31 * result + Arrays.hashCode(favoriteThreeNumbers);
result = 31 * result + Arrays.hashCode(favoriteArrayValues);
result = 31 * result + Arrays.hashCode(nestedArray);
return result;
}
}
@Test
public void genericRecord() throws IOException {
var adapter =
moshi.<GenericRecord<String>>adapter(
Types.newParameterizedTypeWithOwner(
RecordsTest.class, GenericRecord.class, String.class));
assertThat(adapter.fromJson("{\"value\":\"Okay!\"}")).isEqualTo(new GenericRecord<>("Okay!"));
}
public record GenericRecord<T>(T value) {}
@Test
public void genericBoundedRecord() throws IOException {
var adapter =
moshi.<GenericBoundedRecord<Integer>>adapter(
Types.newParameterizedTypeWithOwner(
RecordsTest.class, GenericBoundedRecord.class, Integer.class));
assertThat(adapter.fromJson("{\"value\":4}")).isEqualTo(new GenericBoundedRecord<>(4));
}
@Test
public void indirectGenerics() throws IOException {
var value =
new HasIndirectGenerics(
new IndirectGenerics<>(1L, List.of(2L, 3L, 4L), Map.of("five", 5L)));
var jsonAdapter = moshi.adapter(HasIndirectGenerics.class);
var json = "{\"value\":{\"single\":1,\"list\":[2,3,4],\"map\":{\"five\":5}}}";
assertThat(jsonAdapter.toJson(value)).isEqualTo(json);
assertThat(jsonAdapter.fromJson(json)).isEqualTo(value);
}
public record IndirectGenerics<T>(T single, List<T> list, Map<String, T> map) {}
public record HasIndirectGenerics(IndirectGenerics<Long> value) {}
@Test
public void qualifiedValues() throws IOException {
var adapter = moshi.newBuilder().add(new ColorAdapter()).build().adapter(QualifiedValues.class);
assertThat(adapter.fromJson("{\"value\":\"#ff0000\"}"))
.isEqualTo(new QualifiedValues(16711680));
}
public record QualifiedValues(@HexColor int value) {}
@Retention(RUNTIME)
@JsonQualifier
@interface HexColor {}
/** Converts strings like #ff0000 to the corresponding color ints. */
public static class ColorAdapter {
@ToJson
public String toJson(@HexColor int rgb) {
return String.format("#%06x", rgb);
}
@FromJson
@HexColor
public int fromJson(String rgb) {
return Integer.parseInt(rgb.substring(1), 16);
}
}
public record GenericBoundedRecord<T extends Number>(T value) {}
@Test
public void jsonName() throws IOException {
var adapter = moshi.adapter(JsonName.class);
assertThat(adapter.fromJson("{\"actualValue\":3}")).isEqualTo(new JsonName(3));
}
public record JsonName(@Json(name = "actualValue") int value) {}
/**
* We had a bug where we were incorrectly wrapping exceptions thrown when delegating to the
* JsonAdapters of component fields.
*/
@Test
public void memberEncodeDecodeThrowsExceptionException() throws IOException {
var throwingAdapter =
new Object() {
@ToJson
void booleanToJson(JsonWriter writer, boolean value) throws IOException {
throw new IOException("boom!");
}
@FromJson
boolean booleanFromJson(JsonReader reader) throws IOException {
throw new IOException("boom!");
}
};
var json = "{\"value\":true}";
Moshi throwingMoshi = this.moshi.newBuilder().add(throwingAdapter).build();
var adapter = throwingMoshi.adapter(BooleanRecord.class);
try {
adapter.fromJson(json);
fail();
} catch (IOException expected) {
assertThat(expected).hasMessageThat().isEqualTo("boom!");
}
try {
adapter.toJson(new Buffer(), new BooleanRecord(true));
fail();
} catch (IOException expected) {
assertThat(expected).hasMessageThat().isEqualTo("boom!");
}
}
public record BooleanRecord(boolean value) {}
@Test
public void absentPrimitiveFails() throws IOException {
var adapter = moshi.adapter(AbsentValues.class);
try {
adapter.fromJson("{\"s\":\"\"}");
fail();
} catch (JsonDataException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Required value 'i' missing at $");
}
}
@Test
public void nullPrimitiveFails() throws IOException {
var adapter = moshi.adapter(AbsentValues.class);
try {
adapter.fromJson("{\"s\":\"\",\"i\":null}");
fail();
} catch (JsonDataException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Expected an int but was NULL at path $.i");
}
}
@Test
public void absentObjectIsNull() throws IOException {
var adapter = moshi.adapter(AbsentValues.class);
String json = "{\"i\":5}";
AbsentValues value = new AbsentValues(null, 5);
assertThat(adapter.fromJson(json)).isEqualTo(value);
assertThat(adapter.toJson(value)).isEqualTo(json);
}
@Test
public void nullObjectIsNull() throws IOException {
var adapter = moshi.adapter(AbsentValues.class);
String json = "{\"i\":5,\"s\":null}";
AbsentValues value = new AbsentValues(null, 5);
assertThat(adapter.fromJson(json)).isEqualTo(value);
assertThat(adapter.toJson(value)).isEqualTo("{\"i\":5}");
}
public record AbsentValues(String s, int i) {}
}
================================================
FILE: moshi/src/main/java/com/squareup/moshi/-JsonUtf8Reader.kt
================================================
/*
* Copyright (C) 2010 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi
import com.squareup.moshi.internal.JsonScope
import com.squareup.moshi.internal.JsonValueSource
import com.squareup.moshi.internal.knownNotNull
import java.math.BigDecimal
import okio.Buffer
import okio.BufferedSource
import okio.ByteString
import okio.ByteString.Companion.encodeUtf8
import okio.EOFException
import okio.IOException
import okio.buffer
@Suppress("ktlint:standard:class-naming") // Hide this symbol from Java callers.
internal class `-JsonUtf8Reader` : JsonReader {
/** The input JSON. */
private val source: BufferedSource
private val buffer: Buffer
private var peeked = PEEKED_NONE
/**
* A peeked value that was composed entirely of digits with an optional leading dash. Positive
* values may not have a leading 0.
*/
private var peekedLong = 0L
/** The number of characters in a peeked number literal. */
private var peekedNumberLength = 0
/**
* A peeked string that should be parsed on the next double, long or string. This is populated
* before a numeric value is parsed and used if that parsing fails.
*/
private var peekedString: String? = null
/**
* If non-null, the most recent value read was [nextSource]. The caller may be mid-stream so it is
* necessary to call [JsonValueSource.discard] to get to the end of the current JSON value before
* proceeding.
*/
private var valueSource: JsonValueSource? = null
constructor(source: BufferedSource) {
this.source = source
buffer = source.buffer
pushScope(JsonScope.EMPTY_DOCUMENT)
}
/** Copy-constructor makes a deep copy for peeking. */
constructor(copyFrom: `-JsonUtf8Reader`) : super(copyFrom) {
val sourcePeek = copyFrom.source.peek()
source = sourcePeek
buffer = sourcePeek.buffer
peeked = copyFrom.peeked
peekedLong = copyFrom.peekedLong
peekedNumberLength = copyFrom.peekedNumberLength
peekedString = copyFrom.peekedString
// Make sure our buffer has as many bytes as the source's buffer. This is necessary because
// JsonUtf8Reader assumes any data it has peeked (like the peekedNumberLength) are buffered.
sourcePeek.require(copyFrom.buffer.size)
}
override fun beginArray() {
val p = peekIfNone()
if (p == PEEKED_BEGIN_ARRAY) {
pushScope(JsonScope.EMPTY_ARRAY)
pathIndices[stackSize - 1] = 0
peeked = PEEKED_NONE
} else {
throw JsonDataException("Expected BEGIN_ARRAY but was ${peek()} at path $path")
}
}
override fun endArray() {
val p = peekIfNone()
if (p == PEEKED_END_ARRAY) {
stackSize--
pathIndices[stackSize - 1]++
peeked = PEEKED_NONE
} else {
throw JsonDataException("Expected END_ARRAY but was ${peek()} at path $path")
}
}
override fun beginObject() {
val p = peekIfNone()
if (p == PEEKED_BEGIN_OBJECT) {
pushScope(JsonScope.EMPTY_OBJECT)
peeked = PEEKED_NONE
} else {
throw JsonDataException("Expected BEGIN_OBJECT but was ${peek()} at path $path")
}
}
override fun endObject() {
val p = peekIfNone()
if (p == PEEKED_END_OBJECT) {
stackSize--
pathNames[stackSize] = null // Free the last path name so that it can be garbage collected!
pathIndices[stackSize - 1]++
peeked = PEEKED_NONE
} else {
throw JsonDataException("Expected END_OBJECT but was ${peek()} at path $path")
}
}
override fun hasNext(): Boolean {
val p = peekIfNone()
return p != PEEKED_END_OBJECT && p != PEEKED_END_ARRAY && p != PEEKED_EOF
}
override fun peek(): Token {
return when (peekIfNone()) {
PEEKED_BEGIN_OBJECT -> Token.BEGIN_OBJECT
PEEKED_END_OBJECT -> Token.END_OBJECT
PEEKED_BEGIN_ARRAY -> Token.BEGIN_ARRAY
PEEKED_END_ARRAY -> Token.END_ARRAY
PEEKED_SINGLE_QUOTED_NAME,
PEEKED_DOUBLE_QUOTED_NAME,
PEEKED_UNQUOTED_NAME,
PEEKED_BUFFERED_NAME -> Token.NAME
PEEKED_TRUE,
PEEKED_FALSE -> Token.BOOLEAN
PEEKED_NULL -> Token.NULL
PEEKED_SINGLE_QUOTED,
PEEKED_DOUBLE_QUOTED,
PEEKED_UNQUOTED,
PEEKED_BUFFERED -> Token.STRING
PEEKED_LONG,
PEEKED_NUMBER -> Token.NUMBER
PEEKED_EOF -> Token.END_DOCUMENT
else -> throw AssertionError()
}
}
private fun doPeek(): Int {
val peekStack = scopes[stackSize - 1]
when (peekStack) {
JsonScope.EMPTY_ARRAY -> scopes[stackSize - 1] = JsonScope.NONEMPTY_ARRAY
JsonScope.NONEMPTY_ARRAY -> {
// Look for a comma before the next element.
val c = nextNonWhitespace(true).toChar()
buffer.readByte() // consume ']' or ','.
when (c) {
']' -> {
return setPeeked(PEEKED_END_ARRAY)
}
';' -> checkLenient()
/*no op*/
',' -> Unit
else -> throw syntaxError("Unterminated array")
}
}
JsonScope.EMPTY_OBJECT,
JsonScope.NONEMPTY_OBJECT -> {
scopes[stackSize - 1] = JsonScope.DANGLING_NAME
// Look for a comma before the next element.
if (peekStack == JsonScope.NONEMPTY_OBJECT) {
val c = nextNonWhitespace(true).toChar()
buffer.readByte() // Consume '}' or ','.
when (c) {
'}' -> {
return setPeeked(PEEKED_END_OBJECT)
}
/*no op*/
',' -> Unit
';' -> checkLenient()
else -> throw syntaxError("Unterminated object")
}
}
val next =
when (val c = nextNonWhitespace(true).toChar()) {
'"' -> {
buffer.readByte() // consume the '\"'.
PEEKED_DOUBLE_QUOTED_NAME
}
'\'' -> {
buffer.readByte() // consume the '\''.
checkLenient()
PEEKED_SINGLE_QUOTED_NAME
}
'}' ->
if (peekStack != JsonScope.NONEMPTY_OBJECT) {
buffer.readByte() // consume the '}'.
PEEKED_END_OBJECT
} else {
throw syntaxError("Expected name")
}
else -> {
checkLenient()
if (isLiteral(c.code)) {
PEEKED_UNQUOTED_NAME
} else {
throw syntaxError("Expected name")
}
}
}
peeked = next
return next
}
JsonScope.DANGLING_NAME -> {
scopes[stackSize - 1] = JsonScope.NONEMPTY_OBJECT
// Look for a colon before the value.
val c = nextNonWhitespace(true).toChar()
buffer.readByte() // Consume ':'.
when (c) {
/*no op*/
':' -> Unit
'=' -> {
checkLenient()
if (source.request(1) && buffer[0].asChar() == '>') {
buffer.readByte() // Consume '>'.
}
}
else -> throw syntaxError("Expected ':'")
}
}
JsonScope.EMPTY_DOCUMENT -> scopes[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT
JsonScope.NONEMPTY_DOCUMENT -> {
if (nextNonWhitespace(false) == -1) {
return setPeeked(PEEKED_EOF)
} else {
checkLenient()
}
}
JsonScope.STREAMING_VALUE -> {
valueSource!!.discard()
valueSource = null
stackSize--
return doPeek()
}
else -> check(peekStack != JsonScope.CLOSED) { "JsonReader is closed" }
}
when (nextNonWhitespace(true).toChar()) {
']' -> {
return when (peekStack) {
JsonScope.EMPTY_ARRAY -> {
buffer.readByte() // Consume ']'.
setPeeked(PEEKED_END_ARRAY)
}
JsonScope.NONEMPTY_ARRAY -> {
// In lenient mode, a 0-length literal in an array means 'null'.
checkLenient()
setPeeked(PEEKED_NULL)
}
else -> throw syntaxError("Unexpected value")
}
}
// In lenient mode, a 0-length literal in an array means 'null'.
';',
',' ->
return when (peekStack) {
JsonScope.EMPTY_ARRAY,
JsonScope.NONEMPTY_ARRAY -> {
checkLenient()
setPeeked(PEEKED_NULL)
}
else -> throw syntaxError("Unexpected value")
}
'\'' -> {
checkLenient()
buffer.readByte() // Consume '\''.
return setPeeked(PEEKED_SINGLE_QUOTED)
}
'"' -> {
buffer.readByte() // Consume '\"'.
return setPeeked(PEEKED_DOUBLE_QUOTED)
}
'[' -> {
buffer.readByte() // Consume '['.
return setPeeked(PEEKED_BEGIN_ARRAY)
}
'{' -> {
buffer.readByte() // Consume '{'.
return setPeeked(PEEKED_BEGIN_OBJECT)
}
else -> Unit /* no-op */
}
var result = peekKeyword()
if (result != PEEKED_NONE) {
return result
}
result = peekNumber()
if (result != PEEKED_NONE) {
return result
}
if (!isLiteral(buffer[0].toInt())) {
throw syntaxError("Expected value")
}
checkLenient()
return setPeeked(PEEKED_UNQUOTED)
}
private fun peekKeyword(): Int {
// Figure out which keyword we're matching against by its first character.
var c = buffer[0].asChar()
val keyword: String
val keywordUpper: String
val peeking: Int
when (c) {
't',
'T' -> {
keyword = "true"
keywordUpper = "TRUE"
peeking = PEEKED_TRUE
}
'f',
'F' -> {
keyword = "false"
keywordUpper = "FALSE"
peeking = PEEKED_FALSE
}
'n',
'N' -> {
keyword = "null"
keywordUpper = "NULL"
peeking = PEEKED_NULL
}
else -> return PEEKED_NONE
}
// Confirm that chars [1..length) match the keyword.
val length = keyword.length
for (i in 1 until length) {
val iAsLong = i.toLong()
if (!source.request(iAsLong + 1)) {
return PEEKED_NONE
}
c = buffer[iAsLong].asChar()
if (c != keyword[i] && c != keywordUpper[i]) {
return PEEKED_NONE
}
}
if (source.request((length + 1).toLong()) && isLiteral(buffer[length.toLong()].toInt())) {
return PEEKED_NONE // Don't match trues, falsey or nullsoft!
}
// We've found the keyword followed either by EOF or by a non-literal character.
buffer.skip(length.toLong())
return setPeeked(peeking)
}
private fun peekNumber(): Int {
var value = 0L // Negative to accommodate Long.MIN_VALUE more easily.
var negative = false
var fitsInLong = true
var last = NUMBER_CHAR_NONE
var i = 0L
while (true) {
if (!source.request(i + 1)) {
break
}
when (val c = buffer[i].asChar()) {
'-' -> {
when (last) {
NUMBER_CHAR_NONE -> {
negative = true
last = NUMBER_CHAR_SIGN
i++
continue
}
NUMBER_CHAR_EXP_E -> {
last = NUMBER_CHAR_EXP_SIGN
i++
continue
}
}
return PEEKED_NONE
}
'+' -> {
if (last == NUMBER_CHAR_EXP_E) {
last = NUMBER_CHAR_EXP_SIGN
i++
continue
}
return PEEKED_NONE
}
'e',
'E' -> {
if (last == NUMBER_CHAR_DIGIT || last == NUMBER_CHAR_FRACTION_DIGIT) {
last = NUMBER_CHAR_EXP_E
i++
continue
}
return PEEKED_NONE
}
'.' -> {
if (last == NUMBER_CHAR_DIGIT) {
last = NUMBER_CHAR_DECIMAL
i++
continue
}
return PEEKED_NONE
}
else -> {
if (c !in '0'..'9') {
if (!isLiteral(c.code)) break
return PEEKED_NONE
}
when (last) {
NUMBER_CHAR_SIGN,
NUMBER_CHAR_NONE -> {
value = -(c - '0').toLong()
last = NUMBER_CHAR_DIGIT
}
NUMBER_CHAR_DIGIT -> {
if (value == 0L) {
return PEEKED_NONE // Leading '0' prefix is not allowed (since it could be octal).
}
val newValue = value * 10 - (c - '0').toLong()
fitsInLong =
fitsInLong and
((value > MIN_INCOMPLETE_INTEGER) ||
((value == MIN_INCOMPLETE_INTEGER) && (newValue < value)))
value = newValue
}
NUMBER_CHAR_DECIMAL -> last = NUMBER_CHAR_FRACTION_DIGIT
NUMBER_CHAR_EXP_E,
NUMBER_CHAR_EXP_SIGN -> last = NUMBER_CHAR_EXP_DIGIT
}
}
}
i++
}
// We've read a complete number. Decide if it's a PEEKED_LONG or a PEEKED_NUMBER.
return when {
last == NUMBER_CHAR_DIGIT &&
fitsInLong &&
(value != Long.MIN_VALUE || negative) &&
(value != 0L || !negative) -> {
peekedLong = if (negative) value else -value
buffer.skip(i)
setPeeked(PEEKED_LONG)
}
last == NUMBER_CHAR_DIGIT ||
last == NUMBER_CHAR_FRACTION_DIGIT ||
last == NUMBER_CHAR_EXP_DIGIT -> {
peekedNumberLength = i.toInt()
setPeeked(PEEKED_NUMBER)
}
else -> PEEKED_NONE
}
}
@Throws(IOException::class)
private fun isLiteral(c: Int): Boolean {
return when (c.toChar()) {
'/',
'\\',
';',
'#',
'=' -> {
checkLenient() // fall-through
false
}
// 0x000C = \f
'{',
'}',
'[',
']',
':',
',',
' ',
'\t',
'\u000C',
'\r',
'\n' -> false
else -> true
}
}
@Throws(IOException::class)
override fun nextName(): String {
val result =
when (peekIfNone()) {
PEEKED_UNQUOTED_NAME -> nextUnquotedValue()
PEEKED_DOUBLE_QUOTED_NAME -> nextQuotedValue(DOUBLE_QUOTE_OR_SLASH)
PEEKED_SINGLE_QUOTED_NAME -> nextQuotedValue(SINGLE_QUOTE_OR_SLASH)
PEEKED_BUFFERED_NAME -> {
val name = peekedString!!
peekedString = null
name
}
else -> throw JsonDataException("Expected a name but was ${peek()} at path $path")
}
peeked = PEEKED_NONE
pathNames[stackSize - 1] = result
return result
}
@Throws(IOException::class)
override fun selectName(options: Options): Int {
val p = peekIfNone()
if (p < PEEKED_SINGLE_QUOTED_NAME || p > PEEKED_BUFFERED_NAME) {
return -1
}
if (p == PEEKED_BUFFERED_NAME) {
return findName(peekedString, options)
}
var result = source.select(options.doubleQuoteSuffix)
if (result != -1) {
peeked = PEEKED_NONE
pathNames[stackSize - 1] = options.strings[result]
return result
}
// The next name may be unnecessary escaped. Save the last recorded path name, so that we
// can restore the peek state in case we fail to find a match.
val lastPathName = pathNames[stackSize - 1]
val nextName = nextName()
result = findName(nextName, options)
if (result == -1) {
peeked = PEEKED_BUFFERED_NAME
peekedString = nextName
// We can't push the path further, make it seem like nothing happened.
pathNames[stackSize - 1] = lastPathName
}
return result
}
@Throws(IOException::class)
override fun skipName() {
if (failOnUnknown) {
// Capture the peeked value before nextName() since it will reset its value.
val peeked = peek()
nextName() // Move the path forward onto the offending name.
throw JsonDataException("Cannot skip unexpected $peeked at $path")
}
val p = peekIfNone()
when {
p == PEEKED_UNQUOTED_NAME -> skipUnquotedValue()
p == PEEKED_DOUBLE_QUOTED_NAME -> skipQuotedValue(DOUBLE_QUOTE_OR_SLASH)
p == PEEKED_SINGLE_QUOTED_NAME -> skipQuotedValue(SINGLE_QUOTE_OR_SLASH)
p != PEEKED_BUFFERED_NAME ->
throw JsonDataException("Expected a name but was ${peek()} at path $path")
}
peeked = PEEKED_NONE
pathNames[stackSize - 1] = "null"
}
/**
* If `name` is in `options` this consumes it and returns its index. Otherwise this returns -1 and
* no name is consumed.
*/
private fun findName(name: String?, options: Options): Int {
val i = options.strings.indexOfFirst { it == name }
return if (i > -1) {
peeked = PEEKED_NONE
pathNames[stackSize - 1] = name
i
} else {
-1
}
}
override fun nextString(): String {
val result =
when (peekIfNone()) {
PEEKED_UNQUOTED -> nextUnquotedValue()
PEEKED_DOUBLE_QUOTED -> nextQuotedValue(DOUBLE_QUOTE_OR_SLASH)
PEEKED_SINGLE_QUOTED -> nextQuotedValue(SINGLE_QUOTE_OR_SLASH)
PEEKED_BUFFERED -> {
val buffered = peekedString!!
peekedString = null
buffered
}
PEEKED_LONG -> peekedLong.toString()
PEEKED_NUMBER -> buffer.readUtf8(peekedNumberLength.toLong())
else -> throw JsonDataException("Expected a string but was ${peek()} at path $path")
}
peeked = PEEKED_NONE
pathIndices[stackSize - 1]++
return result
}
override fun selectString(options: Options): Int {
val p = peekIfNone()
if (p < PEEKED_SINGLE_QUOTED || p > PEEKED_BUFFERED) {
return -1
}
if (p == PEEKED_BUFFERED) {
return findString(peekedString, options)
}
var result = source.select(options.doubleQuoteSuffix)
if (result != -1) {
peeked = PEEKED_NONE
pathIndices[stackSize - 1]++
return result
}
val nextString = nextString()
result = findString(nextString, options)
if (result == -1) {
peeked = PEEKED_BUFFERED
peekedString = nextString
pathIndices[stackSize - 1]--
}
return result
}
/**
* If `string` is in `options` this consumes it and returns its index. Otherwise this returns -1
* and no string is consumed.
*/
private fun findString(string: String?, options: Options): Int {
val i = options.strings.indexOfFirst { it == string }
return if (i > -1) {
peeked = PEEKED_NONE
pathIndices[stackSize - 1]++
i
} else {
-1
}
}
override fun nextBoolean(): Boolean {
return when (peekIfNone()) {
PEEKED_TRUE -> {
peeked = PEEKED_NONE
pathIndices[stackSize - 1]++
true
}
PEEKED_FALSE -> {
peeked = PEEKED_NONE
pathIndices[stackSize - 1]++
false
}
else -> throw JsonDataException("Expected a boolean but was ${peek()} at path $path")
}
}
override fun <T> nextNull(): T? {
val p = peekIfNone()
return if (p == PEEKED_NULL) {
peeked = PEEKED_NONE
pathIndices[stackSize - 1]++
null
} else {
throw JsonDataException("Expected null but was ${peek()} at path $path")
}
}
override fun nextDouble(): Double {
val p = peekIfNone()
if (p == PEEKED_LONG) {
peeked = PEEKED_NONE
pathIndices[stackSize - 1]++
return peekedLong.toDouble()
}
val next =
when (p) {
PEEKED_NUMBER -> buffer.readUtf8(peekedNumberLength.toLong()).also { peekedString = it }
PEEKED_DOUBLE_QUOTED -> nextQuotedValue(DOUBLE_QUOTE_OR_SLASH).also { peekedString = it }
PEEKED_SINGLE_QUOTED -> nextQuotedValue(SINGLE_QUOTE_OR_SLASH).also { peekedString = it }
PEEKED_UNQUOTED -> nextUnquotedValue().also { peekedString = it }
PEEKED_BUFFERED -> {
// PEEKED_BUFFERED means the value's been stored in peekedString
knownNotNull(peekedString)
}
else -> throw JsonDataException("Expected a double but was " + peek() + " at path " + path)
}
peeked = PEEKED_BUFFERED
val result =
try {
next.toDouble()
} catch (_: NumberFormatException) {
throw JsonDataException("Expected a double but was $next at path $path")
}
if (!lenient && (result.isNaN() || result.isInfinite())) {
throw JsonEncodingException("JSON forbids NaN and infinities: $result at path $path")
}
peekedString = null
peeked = PEEKED_NONE
pathIndices[stackSize - 1]++
return result
}
override fun nextLong(): Long {
val p = peekIfNone()
if (p == PEEKED_LONG) {
peeked = PEEKED_NONE
pathIndices[stackSize - 1]++
return peekedLong
}
when {
p == PEEKED_NUMBER -> peekedString = buffer.readUtf8(peekedNumberLength.toLong())
p == PEEKED_DOUBLE_QUOTED || p == PEEKED_SINGLE_QUOTED -> {
peekedString =
if (p == PEEKED_DOUBLE_QUOTED) {
nextQuotedValue(DOUBLE_QUOTE_OR_SLASH)
} else {
nextQuotedValue(SINGLE_QUOTE_OR_SLASH)
}
try {
val result = peekedString!!.toLong()
peeked = PEEKED_NONE
pathIndices[stackSize - 1]++
return result
} catch (_: NumberFormatException) {
// Fall back to parse as a BigDecimal below.
}
}
p != PEEKED_BUFFERED -> {
throw JsonDataException("Expected a long but was " + peek() + " at path " + path)
}
}
peeked = PEEKED_BUFFERED
val result =
try {
val asDecimal = BigDecimal(peekedString)
asDecimal.longValueExact()
} catch (_: NumberFormatException) {
throw JsonDataException("Expected a long but was $peekedString at path $path")
} catch (_: ArithmeticException) {
throw JsonDataException("Expected a long but was $peekedString at path $path")
}
peekedString = null
peeked = PEEKED_NONE
pathIndices[stackSize - 1]++
return result
}
/**
* Returns the string up to but not including `quote`, unescaping any character escape sequences
* encountered along the way. The opening quote should have already been read. This consumes the
* closing quote, but does not include it in the returned string.
*
* @throws IOException if any Unicode escape sequences are malformed.
*/
private fun nextQuotedValue(runTerminator: ByteString): String {
var builder: StringBuilder? = null
while (true) {
val index = source.indexOfElement(runTerminator)
if (index == -1L) throw syntaxError("Unterminated string")
// If we've got an escape character, we're going to need a string builder.
if (buffer[index].asChar() == '\\') {
if (builder == null) builder = StringBuilder()
builder.append(buffer.readUtf8(index))
buffer.readByte() // '\'
builder.append(readEscapeCharacter())
continue
}
// If it isn't the escape character, it's the quote. Return the string.
return if (builder == null) {
buffer.readUtf8(index).also {
buffer.readByte() // Consume the quote character.
}
} else {
builder.append(buffer.readUtf8(index))
buffer.readByte() // Consume the quote character.
builder.toString()
}
}
}
/** Returns an unquoted value as a string. */
private fun nextUnquotedValue(): String {
val i = source.indexOfElement(UNQUOTED_STRING_TERMINALS)
return if (i != -1L) buffer.readUtf8(i) else buffer.readUtf8()
}
private fun skipQuotedValue(runTerminator: ByteString) {
while (true) {
val index = source.indexOfElement(runTerminator)
if (index == -1L) throw syntaxError("Unterminated string")
val terminator = buffer[index].asChar()
buffer.skip(index + 1)
if (terminator == '\\') {
readEscapeCharacter()
} else {
return
}
}
}
private fun skipUnquotedValue() {
val i = source.indexOfElement(UNQUOTED_STRING_TERMINALS)
buffer.skip(if (i != -1L) i else buffer.size)
}
override fun nextInt(): Int {
val p = peekIfNone()
if (p == PEEKED_LONG) {
val result = peekedLong.toInt()
if (peekedLong != result.toLong()) { // Make sure no precision was lost casting to 'int'.
throw JsonDataException("Expected an int but was $peekedLong at path $path")
}
peeked = PEEKED_NONE
pathIndices[stackSize - 1]++
return result
}
val next: String =
when (p) {
PEEKED_NUMBER -> {
buffer.readUtf8(peekedNumberLength.toLong()).also { peekedString = it }
}
PEEKED_DOUBLE_QUOTED,
PEEKED_SINGLE_QUOTED -> {
val next =
if (p == PEEKED_DOUBLE_QUOTED) {
nextQuotedValue(DOUBLE_QUOTE_OR_SLASH)
} else {
nextQuotedValue(SINGLE_QUOTE_OR_SLASH)
}
peekedString = next
try {
val result = next.toInt()
peeked = PEEKED_NONE
pathIndices[stackSize - 1]++
return result
} catch (_: NumberFormatException) {
// Fall back to parse as a double below.
next
}
}
PEEKED_BUFFERED -> {
// PEEKED_BUFFERED means the value's been stored in peekedString
knownNotNull(peekedString)
}
gitextract_wxuqnsxb/ ├── .editorconfig ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── config.yml │ │ └── feature_request.md │ ├── renovate.json5 │ └── workflows/ │ ├── .java-version │ ├── build.yml │ └── release.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── build.gradle.kts ├── examples/ │ ├── build.gradle.kts │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── squareup/ │ └── moshi/ │ └── recipes/ │ ├── ByteStrings.java │ ├── CardAdapter.java │ ├── CustomAdapterFactory.java │ ├── CustomAdapterWithDelegate.java │ ├── CustomFieldName.java │ ├── CustomQualifier.java │ ├── CustomTypeAdapter.java │ ├── DefaultOnDataMismatchAdapter.java │ ├── FallbackEnum.java │ ├── FromJsonWithoutStrings.java │ ├── IncludeNullsForAnnotatedTypes.java │ ├── IncludeNullsForOneType.java │ ├── JsonString.kt │ ├── MultipleFormats.java │ ├── ReadAndWriteRfc3339Dates.java │ ├── ReadJson.java │ ├── ReadJsonList.java │ ├── ReadJsonListKt.kt │ ├── RecoverFromTypeMismatch.java │ ├── Unwrap.java │ ├── WriteJson.java │ ├── models/ │ │ ├── BlackjackHand.java │ │ ├── Card.java │ │ ├── Player.java │ │ ├── Suit.java │ │ └── Tournament.java │ └── package-info.java ├── gradle/ │ ├── libs.versions.toml │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── moshi/ │ ├── build.gradle.kts │ ├── gradle.properties │ ├── japicmp/ │ │ └── build.gradle.kts │ ├── records-tests/ │ │ ├── build.gradle.kts │ │ └── src/ │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── squareup/ │ │ └── moshi/ │ │ └── records/ │ │ └── RecordsTest.java │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── squareup/ │ │ │ └── moshi/ │ │ │ ├── -JsonUtf8Reader.kt │ │ │ ├── -JsonUtf8Writer.kt │ │ │ ├── -JsonValueReader.kt │ │ │ ├── -JsonValueWriter.kt │ │ │ ├── -MoshiKotlinExtensions.kt │ │ │ ├── -MoshiKotlinTypesExtensions.kt │ │ │ ├── FromJson.kt │ │ │ ├── Json.kt │ │ │ ├── JsonAdapter.kt │ │ │ ├── JsonClass.kt │ │ │ ├── JsonDataException.kt │ │ │ ├── JsonEncodingException.kt │ │ │ ├── JsonQualifier.kt │ │ │ ├── JsonReader.kt │ │ │ ├── JsonWriter.kt │ │ │ ├── Moshi.kt │ │ │ ├── ToJson.kt │ │ │ ├── Types.kt │ │ │ ├── internal/ │ │ │ │ ├── AdapterMethodsFactory.kt │ │ │ │ ├── ArrayJsonAdapter.kt │ │ │ │ ├── ClassFactory.kt │ │ │ │ ├── ClassJsonAdapter.kt │ │ │ │ ├── CollectionJsonAdapter.kt │ │ │ │ ├── JsonScope.kt │ │ │ │ ├── JsonValueSource.kt │ │ │ │ ├── KotlinReflectTypes.kt │ │ │ │ ├── LinkedHashTreeMap.kt │ │ │ │ ├── MapJsonAdapter.kt │ │ │ │ ├── NonNullJsonAdapter.kt │ │ │ │ ├── NullSafeJsonAdapter.kt │ │ │ │ ├── RecordJsonAdapter.kt │ │ │ │ ├── StandardJsonAdapters.kt │ │ │ │ └── Util.kt │ │ │ └── package-info.java │ │ ├── java16/ │ │ │ └── com/ │ │ │ └── squareup/ │ │ │ └── moshi/ │ │ │ └── internal/ │ │ │ └── RecordJsonAdapter.kt │ │ └── resources/ │ │ └── META-INF/ │ │ └── proguard/ │ │ └── moshi.pro │ └── test/ │ └── java/ │ ├── android/ │ │ └── util/ │ │ └── Pair.java │ └── com/ │ └── squareup/ │ └── moshi/ │ ├── AdapterMethodsTest.java │ ├── CircularAdaptersTest.java │ ├── DeferredAdapterTest.java │ ├── FlattenTest.java │ ├── JsonAdapterTest.java │ ├── JsonCodecFactory.java │ ├── JsonQualifiersTest.java │ ├── JsonReaderPathTest.java │ ├── JsonReaderTest.java │ ├── JsonUtf8ReaderTest.java │ ├── JsonUtf8WriterTest.java │ ├── JsonValueReaderTest.java │ ├── JsonValueWriterTest.java │ ├── JsonWriterPathTest.java │ ├── JsonWriterTest.java │ ├── KotlinExtensionsTest.kt │ ├── MoshiTest.java │ ├── MoshiTesting.kt │ ├── ObjectAdapterTest.java │ ├── PromoteNameToValueTest.java │ ├── RecursiveTypesResolveTest.java │ ├── TestUtil.java │ ├── TypesTest.java │ └── internal/ │ ├── ClassJsonAdapterTest.java │ ├── JsonValueSourceTest.java │ ├── KotlinReflectTypesTest.kt │ ├── LinkedHashTreeMapTest.java │ └── MapJsonAdapterTest.java ├── moshi-adapters/ │ ├── README.md │ ├── build.gradle.kts │ ├── japicmp/ │ │ └── build.gradle.kts │ └── src/ │ ├── main/ │ │ └── java/ │ │ └── com/ │ │ └── squareup/ │ │ └── moshi/ │ │ ├── Rfc3339DateJsonAdapter.kt │ │ └── adapters/ │ │ ├── EnumJsonAdapter.kt │ │ ├── Iso8601Utils.kt │ │ ├── PolymorphicJsonAdapterFactory.kt │ │ └── Rfc3339DateJsonAdapter.kt │ └── test/ │ └── java/ │ └── com/ │ └── squareup/ │ └── moshi/ │ └── adapters/ │ ├── EnumJsonAdapterTest.java │ ├── PolymorphicJsonAdapterFactoryTest.java │ └── Rfc3339DateJsonAdapterTest.java ├── moshi-kotlin/ │ ├── build.gradle.kts │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── squareup/ │ │ │ └── moshi/ │ │ │ ├── KotlinJsonAdapterFactory.kt │ │ │ └── kotlin/ │ │ │ └── reflect/ │ │ │ ├── IndexedParameterMap.kt │ │ │ ├── Invokable.kt │ │ │ ├── JvmDescriptors.kt │ │ │ ├── JvmSignatureSearcher.kt │ │ │ ├── KmExecutable.kt │ │ │ ├── KotlinJsonAdapterFactory.kt │ │ │ └── KtTypes.kt │ │ └── resources/ │ │ └── META-INF/ │ │ └── com.android.tools/ │ │ ├── proguard/ │ │ │ └── moshi-metadata-reflect.pro │ │ ├── r8-from-1.6.0/ │ │ │ └── moshi-metadata-reflect.pro │ │ └── r8-upto-1.6.0/ │ │ └── moshi-metadata-reflect.pro │ └── test/ │ └── java/ │ └── com/ │ └── squareup/ │ └── moshi/ │ └── kotlin/ │ └── reflect/ │ └── KotlinJsonAdapterTest.kt ├── moshi-kotlin-codegen/ │ ├── build.gradle.kts │ └── src/ │ ├── main/ │ │ └── java/ │ │ └── com/ │ │ └── squareup/ │ │ └── moshi/ │ │ └── kotlin/ │ │ └── codegen/ │ │ ├── api/ │ │ │ ├── AdapterGenerator.kt │ │ │ ├── DelegateKey.kt │ │ │ ├── InternalMoshiCodegenApi.kt │ │ │ ├── Options.kt │ │ │ ├── ProguardRules.kt │ │ │ ├── PropertyGenerator.kt │ │ │ ├── TargetConstructor.kt │ │ │ ├── TargetParameter.kt │ │ │ ├── TargetProperty.kt │ │ │ ├── TargetType.kt │ │ │ ├── TypeRenderer.kt │ │ │ ├── kotlintypes.kt │ │ │ └── typeAliasUnwrapping.kt │ │ └── ksp/ │ │ ├── AppliedType.kt │ │ ├── JsonClassSymbolProcessorProvider.kt │ │ ├── KspUtil.kt │ │ ├── MoshiApiUtil.kt │ │ ├── TargetTypes.kt │ │ └── shadedUtil.kt │ └── test/ │ └── java/ │ └── com/ │ └── squareup/ │ └── moshi/ │ └── kotlin/ │ └── codegen/ │ ├── JavaSuperclass.java │ └── ksp/ │ └── JsonClassSymbolProcessorTest.kt ├── moshi-kotlin-tests/ │ ├── build.gradle.kts │ ├── codegen-only/ │ │ ├── build.gradle.kts │ │ └── src/ │ │ └── test/ │ │ └── kotlin/ │ │ └── com/ │ │ └── squareup/ │ │ └── moshi/ │ │ └── kotlin/ │ │ └── codegen/ │ │ ├── CompileOnlyTests.kt │ │ ├── ComplexGenericsInheritanceTest.kt │ │ ├── DefaultConstructorTest.kt │ │ ├── GeneratedAdaptersTest.kt │ │ ├── GeneratedAdaptersTest_CustomGeneratedClassJsonAdapter.kt │ │ ├── LooksLikeAClass/ │ │ │ └── ClassInPackageThatLooksLikeAClass.kt │ │ ├── MixingReflectAndCodeGen.kt │ │ ├── MoshiKspTest.kt │ │ ├── MultipleMasksTest.kt │ │ └── annotation/ │ │ └── UppercaseInAnnotationPackage.kt │ ├── extra-moshi-test-module/ │ │ ├── build.gradle.kts │ │ └── src/ │ │ └── main/ │ │ └── kotlin/ │ │ └── com/ │ │ └── squareup/ │ │ └── moshi/ │ │ └── kotlin/ │ │ └── codegen/ │ │ └── test/ │ │ └── extra/ │ │ └── AbstractClassInModuleA.kt │ └── src/ │ └── test/ │ └── kotlin/ │ └── com/ │ └── squareup/ │ └── moshi/ │ └── kotlin/ │ ├── DualKotlinTest.kt │ └── reflect/ │ └── KotlinJsonAdapterTest.kt ├── releasing.md └── settings.gradle.kts
SYMBOL INDEX (1070 symbols across 55 files)
FILE: examples/src/main/java/com/squareup/moshi/recipes/ByteStrings.java
class ByteStrings (line 25) | public final class ByteStrings {
method run (line 26) | public void run() throws Exception {
class Base64ByteStringAdapter (line 40) | public final class Base64ByteStringAdapter extends JsonAdapter<ByteStr...
method fromJson (line 41) | @Override
method toJson (line 47) | @Override
method main (line 54) | public static void main(String[] args) throws Exception {
FILE: examples/src/main/java/com/squareup/moshi/recipes/CardAdapter.java
class CardAdapter (line 24) | public final class CardAdapter {
method toJson (line 25) | @ToJson
method fromJson (line 30) | @FromJson
FILE: examples/src/main/java/com/squareup/moshi/recipes/CustomAdapterFactory.java
class CustomAdapterFactory (line 32) | public final class CustomAdapterFactory {
method run (line 33) | public void run() throws Exception {
class SortedSetAdapter (line 53) | static final class SortedSetAdapter<T> extends JsonAdapter<SortedSet<T...
method SortedSetAdapter (line 56) | SortedSetAdapter(JsonAdapter<T> elementAdapter) {
method fromJson (line 60) | @Override
method toJson (line 71) | @Override
class SortedSetAdapterFactory (line 87) | static class SortedSetAdapterFactory implements JsonAdapter.Factory {
method create (line 88) | @Override
method main (line 111) | public static void main(String[] args) throws Exception {
FILE: examples/src/main/java/com/squareup/moshi/recipes/CustomAdapterWithDelegate.java
class CustomAdapterWithDelegate (line 26) | public final class CustomAdapterWithDelegate {
method run (line 27) | public void run() throws Exception {
method main (line 38) | public static void main(String[] args) throws Exception {
type Stage (line 42) | private enum Stage {
class StageAdapter (line 53) | private static final class StageAdapter {
method fromJson (line 54) | @FromJson
FILE: examples/src/main/java/com/squareup/moshi/recipes/CustomFieldName.java
class CustomFieldName (line 22) | public final class CustomFieldName {
method run (line 23) | public void run() throws Exception {
method main (line 33) | public static void main(String[] args) throws Exception {
FILE: examples/src/main/java/com/squareup/moshi/recipes/CustomQualifier.java
class CustomQualifier (line 27) | public final class CustomQualifier {
method run (line 28) | public void run() throws Exception {
method main (line 44) | public static void main(String[] args) throws Exception {
class Rectangle (line 48) | static class Rectangle {
method toString (line 53) | @Override
class ColorAdapter (line 63) | static class ColorAdapter {
method toJson (line 64) | @ToJson
method fromJson (line 69) | @FromJson
FILE: examples/src/main/java/com/squareup/moshi/recipes/CustomTypeAdapter.java
class CustomTypeAdapter (line 22) | public final class CustomTypeAdapter {
method run (line 23) | public void run() throws Exception {
method main (line 41) | public static void main(String[] args) throws Exception {
FILE: examples/src/main/java/com/squareup/moshi/recipes/DefaultOnDataMismatchAdapter.java
class DefaultOnDataMismatchAdapter (line 29) | public final class DefaultOnDataMismatchAdapter<T> extends JsonAdapter<T> {
method DefaultOnDataMismatchAdapter (line 33) | private DefaultOnDataMismatchAdapter(JsonAdapter<T> delegate, T defaul...
method fromJson (line 38) | @Override
method toJson (line 56) | @Override
method newFactory (line 61) | public static <T> Factory newFactory(final Class<T> type, final T defa...
FILE: examples/src/main/java/com/squareup/moshi/recipes/FallbackEnum.java
class FallbackEnum (line 34) | final class FallbackEnum {
class FallbackEnumJsonAdapter (line 42) | public static final class FallbackEnumJsonAdapter<T extends Enum<T>> e...
method create (line 45) | @Nullable
method FallbackEnumJsonAdapter (line 73) | FallbackEnumJsonAdapter(Class<T> enumType, String fallbackName) {
method fromJson (line 89) | @Override
method toJson (line 97) | @Override
method toString (line 102) | @Override
class Example (line 108) | static final class Example {
type Transportation (line 109) | enum Transportation {
method Example (line 119) | Example(Transportation transportation) {
method toString (line 123) | @Override
method main (line 129) | public static void main(String[] args) throws Exception {
method FallbackEnum (line 135) | private FallbackEnum() {}
FILE: examples/src/main/java/com/squareup/moshi/recipes/FromJsonWithoutStrings.java
class FromJsonWithoutStrings (line 23) | public final class FromJsonWithoutStrings {
method run (line 24) | public void run() throws Exception {
method main (line 44) | public static void main(String[] args) throws Exception {
class EventJson (line 48) | private static final class EventJson {
class Event (line 54) | public static final class Event {
method toString (line 58) | @Override
class EventJsonAdapter (line 71) | private static final class EventJsonAdapter {
method eventFromJson (line 72) | @FromJson
method eventToJson (line 80) | @ToJson
FILE: examples/src/main/java/com/squareup/moshi/recipes/IncludeNullsForAnnotatedTypes.java
class IncludeNullsForAnnotatedTypes (line 30) | public final class IncludeNullsForAnnotatedTypes {
method run (line 31) | public void run() throws Exception {
class Car (line 53) | @AlwaysSerializeNulls
class Driver (line 60) | static class Driver {
class AlwaysSerializeNullsFactory (line 66) | static class AlwaysSerializeNullsFactory implements JsonAdapter.Factory {
method create (line 67) | @Override
method main (line 78) | public static void main(String[] args) throws Exception {
FILE: examples/src/main/java/com/squareup/moshi/recipes/IncludeNullsForOneType.java
class IncludeNullsForOneType (line 27) | public final class IncludeNullsForOneType {
method run (line 28) | public void run() throws Exception {
class TournamentWithNullsAdapter (line 42) | public static final class TournamentWithNullsAdapter {
method toJson (line 43) | @ToJson
method main (line 57) | public static void main(String[] args) throws Exception {
FILE: examples/src/main/java/com/squareup/moshi/recipes/MultipleFormats.java
class MultipleFormats (line 32) | public final class MultipleFormats {
method run (line 33) | public void run() throws Exception {
class MultipleFormatsCardAdapter (line 51) | public final class MultipleFormatsCardAdapter {
method toJson (line 52) | @ToJson
method fromJson (line 58) | @FromJson
class CardStringAdapter (line 73) | public final class CardStringAdapter {
method toJson (line 74) | @ToJson
method fromJson (line 79) | @FromJson
method main (line 104) | public static void main(String[] args) throws Exception {
FILE: examples/src/main/java/com/squareup/moshi/recipes/ReadAndWriteRfc3339Dates.java
class ReadAndWriteRfc3339Dates (line 28) | public final class ReadAndWriteRfc3339Dates {
method run (line 29) | public void run() throws Exception {
method main (line 49) | public static void main(String[] args) throws Exception {
method newDate (line 53) | private Date newDate(int year, int month, int day, int hour, int offse...
FILE: examples/src/main/java/com/squareup/moshi/recipes/ReadJson.java
class ReadJson (line 22) | public final class ReadJson {
method run (line 23) | public void run() throws Exception {
method main (line 50) | public static void main(String[] args) throws Exception {
FILE: examples/src/main/java/com/squareup/moshi/recipes/ReadJsonList.java
class ReadJsonList (line 25) | public final class ReadJsonList {
method run (line 26) | public void run() throws Exception {
method main (line 53) | public static void main(String[] args) throws Exception {
FILE: examples/src/main/java/com/squareup/moshi/recipes/RecoverFromTypeMismatch.java
class RecoverFromTypeMismatch (line 24) | public final class RecoverFromTypeMismatch {
method run (line 25) | public void run() throws Exception {
method main (line 39) | public static void main(String[] args) throws Exception {
FILE: examples/src/main/java/com/squareup/moshi/recipes/Unwrap.java
class Unwrap (line 35) | final class Unwrap {
method Unwrap (line 36) | private Unwrap() {}
method main (line 38) | public static void main(String[] args) throws Exception {
class EnvelopeJsonAdapter (line 53) | public static final class EnvelopeJsonAdapter extends JsonAdapter<Obje...
method create (line 56) | @Override
class Envelope (line 77) | private static final class Envelope<T> {
method Envelope (line 80) | Envelope(T data) {
method EnvelopeJsonAdapter (line 87) | EnvelopeJsonAdapter(JsonAdapter<Envelope<?>> delegate) {
method fromJson (line 91) | @Override
method toJson (line 96) | @Override
FILE: examples/src/main/java/com/squareup/moshi/recipes/WriteJson.java
class WriteJson (line 28) | public final class WriteJson {
method run (line 29) | public void run() throws Exception {
method main (line 41) | public static void main(String[] args) throws Exception {
FILE: examples/src/main/java/com/squareup/moshi/recipes/models/BlackjackHand.java
class BlackjackHand (line 20) | public final class BlackjackHand {
method BlackjackHand (line 24) | public BlackjackHand(Card hiddenCard, List<Card> visibleCards) {
method toString (line 29) | @Override
FILE: examples/src/main/java/com/squareup/moshi/recipes/models/Card.java
class Card (line 18) | public final class Card {
method Card (line 22) | public Card(char rank, Suit suit) {
method toString (line 27) | @Override
FILE: examples/src/main/java/com/squareup/moshi/recipes/models/Player.java
class Player (line 20) | public final class Player {
method Player (line 24) | public Player(String username, int luckyNumber) {
method toString (line 29) | @Override
FILE: examples/src/main/java/com/squareup/moshi/recipes/models/Suit.java
type Suit (line 18) | public enum Suit {
method toString (line 24) | @Override
FILE: examples/src/main/java/com/squareup/moshi/recipes/models/Tournament.java
class Tournament (line 20) | public final class Tournament {
method Tournament (line 25) | public Tournament(String name, String location, Date start) {
method toString (line 31) | @Override
FILE: moshi-adapters/src/test/java/com/squareup/moshi/adapters/EnumJsonAdapterTest.java
class EnumJsonAdapterTest (line 27) | @SuppressWarnings("CheckReturnValue")
method toAndFromJson (line 29) | @Test
method withJsonName (line 36) | @Test
method withoutFallbackValue (line 43) | @Test
method withFallbackValue (line 58) | @Test
method withNullFallbackValue (line 67) | @Test
type Roshambo (line 76) | enum Roshambo {
FILE: moshi-adapters/src/test/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactoryTest.java
class PolymorphicJsonAdapterFactoryTest (line 33) | @SuppressWarnings("CheckReturnValue")
method fromJson (line 35) | @Test
method toJson (line 52) | @Test
method unregisteredLabelValue (line 69) | @Test
method specifiedFallbackSubtype (line 95) | @Test
method specifiedNullFallbackSubtype (line 112) | @Test
method specifiedFallbackJsonAdapter (line 128) | @Test
method unregisteredSubtype (line 165) | @Test
method unregisteredSubtypeWithDefaultValue (line 191) | @Test
method unregisteredSubtypeWithFallbackJsonAdapter (line 219) | @Test
method nonStringLabelValue (line 247) | @Test
method nonObjectDoesNotConsume (line 268) | @Test
method nonUniqueSubtypes (line 292) | @Test
method uniqueLabels (line 315) | @Test
method nullSafe (line 327) | @Test
method unportableTypes (line 347) | @Test
method failOnUnknownMissingTypeLabel (line 365) | @Test
method missingLabelKey (line 380) | @Test
method missingLabelKeyWithSpecifiedFallbackJsonAdapter (line 401) | @Test
method missingLabelKeyWithSpecifiedDefaultValue (line 435) | @Test
type Message (line 452) | interface Message {}
class Success (line 454) | static final class Success implements Message {
method Success (line 457) | Success(String value) {
method equals (line 461) | @Override
method hashCode (line 469) | @Override
class Error (line 475) | static final class Error implements Message {
method Error (line 478) | Error(Map<String, Object> error_logs) {
method equals (line 482) | @Override
method hashCode (line 490) | @Override
class EmptyMessage (line 496) | static final class EmptyMessage implements Message {
method toString (line 497) | @Override
class MessageWithUnportableTypes (line 503) | static final class MessageWithUnportableTypes implements Message {
method MessageWithUnportableTypes (line 506) | MessageWithUnportableTypes(long long_value) {
class MessageWithType (line 511) | static final class MessageWithType implements Message {
method MessageWithType (line 515) | MessageWithType(String type, String value) {
FILE: moshi-adapters/src/test/java/com/squareup/moshi/adapters/Rfc3339DateJsonAdapterTest.java
class Rfc3339DateJsonAdapterTest (line 30) | public final class Rfc3339DateJsonAdapterTest {
method fromJsonWithTwoDigitMillis (line 33) | @Test
method fromJson (line 39) | @Test
method toJson (line 55) | @Test
method nullSafety (line 71) | @Test
method presentOrAbsentTime (line 77) | @Test
method variableFractionDigits (line 86) | @Test
method absentTimeZone (line 96) | @Test
method newDate (line 107) | private Date newDate(
method newDateWithHostZone (line 119) | private Date newDateWithHostZone(int year, int month, int day) {
FILE: moshi-kotlin-codegen/src/test/java/com/squareup/moshi/kotlin/codegen/JavaSuperclass.java
class JavaSuperclass (line 21) | public class JavaSuperclass {
FILE: moshi/records-tests/src/test/java/com/squareup/moshi/records/RecordsTest.java
class RecordsTest (line 41) | public final class RecordsTest {
method smokeTest (line 45) | @Test
method equals (line 96) | @Override
method hashCode (line 120) | @Override
method genericRecord (line 144) | @Test
method genericBoundedRecord (line 155) | @Test
method indirectGenerics (line 164) | @Test
method qualifiedValues (line 179) | @Test
class ColorAdapter (line 193) | public static class ColorAdapter {
method toJson (line 194) | @ToJson
method fromJson (line 199) | @FromJson
method jsonName (line 208) | @Test
method memberEncodeDecodeThrowsExceptionException (line 220) | @Test
method absentPrimitiveFails (line 253) | @Test
method nullPrimitiveFails (line 264) | @Test
method absentObjectIsNull (line 275) | @Test
method nullObjectIsNull (line 284) | @Test
FILE: moshi/src/test/java/android/util/Pair.java
class Pair (line 18) | public final class Pair {}
FILE: moshi/src/test/java/com/squareup/moshi/AdapterMethodsTest.java
class AdapterMethodsTest (line 39) | public final class AdapterMethodsTest {
method toAndFromJsonViaListOfIntegers (line 40) | @Test
class PointAsListOfIntegersJsonAdapter (line 48) | static class PointAsListOfIntegersJsonAdapter {
method pointToJson (line 49) | @ToJson
method pointFromJson (line 54) | @FromJson
method toAndFromJsonWithWriterAndReader (line 61) | @Test
class PointWriterAndReaderJsonAdapter (line 69) | static class PointWriterAndReaderJsonAdapter {
method pointToJson (line 70) | @ToJson
method pointFromJson (line 78) | @FromJson
class PointJsonAdapterWithDelegate (line 88) | private static final class PointJsonAdapterWithDelegate {
method fromJson (line 89) | @FromJson
method toJson (line 97) | @ToJson
class PointJsonAdapterWithDelegateWithQualifier (line 105) | private static final class PointJsonAdapterWithDelegateWithQualifier {
method fromJson (line 106) | @FromJson
method toJson (line 115) | @ToJson
method toAndFromWithDelegate (line 124) | @Test
method toAndFromWithDelegateWithQualifier (line 133) | @Test
method toAndFromWithIntermediate (line 146) | @Test
method toAndFromWithIntermediateWithQualifier (line 168) | @Test
method toJsonOnly (line 193) | @Test
class PointAsListOfIntegersToAdapter (line 201) | static class PointAsListOfIntegersToAdapter {
method pointToJson (line 202) | @ToJson
method fromJsonOnly (line 208) | @Test
class PointAsListOfIntegersFromAdapter (line 216) | static class PointAsListOfIntegersFromAdapter {
method pointFromJson (line 217) | @FromJson
method multipleLayersOfAdapters (line 224) | @Test
class MultipleLayersJsonAdapter (line 232) | static class MultipleLayersJsonAdapter {
method pointToJson (line 233) | @ToJson
method integerListToJson (line 238) | @ToJson
method pointFromJson (line 248) | @FromJson
method listOfIntegersFromJson (line 254) | @FromJson
method conflictingToAdapters (line 264) | @Test
class ConflictingsToJsonAdapter (line 277) | static class ConflictingsToJsonAdapter {
method pointToJson1 (line 278) | @ToJson
method pointToJson2 (line 283) | @ToJson
method conflictingFromAdapters (line 289) | @Test
class ConflictingsFromJsonAdapter (line 302) | static class ConflictingsFromJsonAdapter {
method pointFromJson1 (line 303) | @FromJson
method pointFromJson2 (line 308) | @FromJson
method emptyAdapters (line 314) | @Test
class EmptyJsonAdapter (line 329) | static class EmptyJsonAdapter {}
method unexpectedSignatureToAdapters (line 331) | @Test
class UnexpectedSignatureToJsonAdapter (line 352) | static class UnexpectedSignatureToJsonAdapter {
method pointToJson (line 353) | @ToJson
method unexpectedSignatureFromAdapters (line 357) | @Test
class UnexpectedSignatureFromJsonAdapter (line 378) | static class UnexpectedSignatureFromJsonAdapter {
method pointFromJson (line 379) | @FromJson
method toAndFromNullNotNullable (line 387) | @Test
class NotNullablePointAsListOfIntegersJsonAdapter (line 396) | static class NotNullablePointAsListOfIntegersJsonAdapter {
method pointToJson (line 397) | @ToJson
method pointFromJson (line 402) | @FromJson
method toAndFromNullNullable (line 408) | @Test
class NullablePointAsListOfIntegersJsonAdapter (line 416) | static class NullablePointAsListOfIntegersJsonAdapter {
method pointToJson (line 417) | @ToJson
method pointFromJson (line 422) | @FromJson
method toAndFromNullJsonWithWriterAndReader (line 433) | @Test
class NullableIntToJsonAdapter (line 441) | static class NullableIntToJsonAdapter {
method jsonToInt (line 442) | @FromJson
method intToJson (line 451) | @ToJson
method adapterThrows (line 461) | @Test
class ExceptionThrowingPointJsonAdapter (line 480) | static class ExceptionThrowingPointJsonAdapter {
method pointToJson (line 481) | @ToJson
method pointFromJson (line 487) | @FromJson
method adapterDoesToJsonOnly (line 494) | @Test
method adapterDoesFromJsonOnly (line 523) | @Test
method parameterizedTypeEqualsNotUsed (line 556) | @Test
class ListOfStringJsonAdapter (line 568) | static class ListOfStringJsonAdapter {
method listOfStringToJson (line 569) | @ToJson
method listOfStringFromJson (line 579) | @FromJson
method parameterizedTypeCacheKey (line 589) | @Test
method writerAndReaderTakingJsonAdapterParameter (line 601) | @Test
class JsonAdapterWithWriterAndReaderTakingJsonAdapterParameter (line 614) | static class JsonAdapterWithWriterAndReaderTakingJsonAdapterParameter {
method lineToJson (line 615) | @ToJson
method lineFromJson (line 624) | @FromJson
method writerAndReaderTakingAnnotatedJsonAdapterParameter (line 634) | @Test
class PointWithParensJsonAdapter (line 647) | static class PointWithParensJsonAdapter {
method pointToJson (line 648) | @ToJson
method pointFromJson (line 653) | @FromJson
class JsonAdapterWithWriterAndReaderTakingAnnotatedJsonAdapterParameter (line 662) | static class JsonAdapterWithWriterAndReaderTakingAnnotatedJsonAdapterP...
method lineToJson (line 663) | @ToJson
method lineFromJson (line 672) | @FromJson
method writerAndReaderTakingMultipleJsonAdapterParameters (line 683) | @Test
class JsonAdapterWithWriterAndReaderTakingMultipleJsonAdapterParameters (line 697) | static class JsonAdapterWithWriterAndReaderTakingMultipleJsonAdapterPa...
method lineToJson (line 698) | @ToJson
method lineFromJson (line 711) | @FromJson
method noToJsonAdapterTakingJsonAdapterParameter (line 727) | @Test
class ToJsonAdapterTakingJsonAdapterParameter (line 737) | static class ToJsonAdapterTakingJsonAdapterParameter {
method lineToJson (line 738) | @ToJson
method noFromJsonAdapterTakingJsonAdapterParameter (line 744) | @Test
class FromJsonAdapterTakingJsonAdapterParameter (line 754) | static class FromJsonAdapterTakingJsonAdapterParameter {
method lineFromJson (line 755) | @FromJson
method adaptedTypeIsEnclosedParameterizedType (line 761) | @Test
class EnclosedParameterizedTypeJsonAdapter (line 773) | static class EnclosedParameterizedTypeJsonAdapter {
method boxFromJson (line 774) | @FromJson
method boxToJson (line 779) | @ToJson
class Box (line 785) | static class Box<T> {
method Box (line 788) | public Box(T data) {
method equals (line 792) | @Override
method hashCode (line 797) | @Override
method genericArrayTypes (line 803) | @Test
class ByteArrayJsonAdapter (line 816) | static class ByteArrayJsonAdapter {
method byteArrayToJson (line 817) | @ToJson
method byteArrayFromJson (line 822) | @FromJson
class MapOfByteArrays (line 828) | static class MapOfByteArrays {
method MapOfByteArrays (line 831) | public MapOfByteArrays(Map<String, byte[]> map) {
method equals (line 835) | @Override
method hashCode (line 840) | @Override
method toString (line 845) | @Override
class Point (line 856) | static class Point {
method Point (line 860) | public Point(int x, int y) {
method equals (line 865) | @Override
method hashCode (line 870) | @Override
class Line (line 876) | static class Line {
method Line (line 880) | public Line(Point a, Point b) {
method equals (line 885) | @Override
method hashCode (line 890) | @Override
type Shape (line 896) | interface Shape {
method draw (line 897) | String draw();
method brokenParameterizedType (line 905) | ParameterizedType brokenParameterizedType(
FILE: moshi/src/test/java/com/squareup/moshi/CircularAdaptersTest.java
class CircularAdaptersTest (line 29) | public final class CircularAdaptersTest {
class Team (line 30) | static class Team {
method Team (line 34) | public Team(String lead, Project... projects) {
class Project (line 40) | static class Project {
method Project (line 44) | Project(String name, Team... teams) {
method circularAdapters (line 50) | @Test
class Node (line 82) | static class Node {
method Node (line 87) | Node(String name, Node left, Node right) {
method plusPrefix (line 93) | Node plusPrefix(String prefix) {
method minusPrefix (line 97) | Node minusPrefix(String prefix) {
class PrefixingNodeFactory (line 108) | static class PrefixingNodeFactory implements JsonAdapter.Factory {
method create (line 109) | @Override
method circularAdaptersAndAnnotations (line 139) | @Test
FILE: moshi/src/test/java/com/squareup/moshi/DeferredAdapterTest.java
class DeferredAdapterTest (line 32) | public final class DeferredAdapterTest {
method concurrentSafe (line 45) | @Test
method doInAnotherThread (line 84) | private void doInAnotherThread(Runnable runnable) {
class BlueNode (line 97) | static class BlueNode {
method BlueNode (line 101) | BlueNode(@Nullable GreenNode green, @Nullable RedNode red) {
class RedNode (line 107) | static class RedNode {
method RedNode (line 110) | RedNode(@Nullable BlueNode blue) {
class GreenNode (line 115) | static class GreenNode {
method GreenNode (line 118) | GreenNode(@Nullable BlueNode blue) {
FILE: moshi/src/test/java/com/squareup/moshi/FlattenTest.java
class FlattenTest (line 31) | @RunWith(Parameterized.class)
method parameters (line 35) | @Parameters(name = "{0}")
method flattenExample (line 40) | @Test
method flattenObject (line 58) | @Test
method flattenArray (line 82) | @Test
method recursiveFlatten (line 103) | @Test
method flattenMultipleNested (line 134) | @Test
method flattenIsOnlyOneLevelDeep (line 160) | @Test
method flattenOnlySomeChildren (line 187) | @Test
method multipleCallsToFlattenSameNesting (line 213) | @Test
method deepFlatten (line 248) | @Test
method flattenTopLevel (line 283) | @Test
method flattenDoesNotImpactOtherTypesInObjects (line 294) | @Test
method flattenDoesNotImpactOtherTypesInArrays (line 320) | @Test
FILE: moshi/src/test/java/com/squareup/moshi/JsonAdapterTest.java
class JsonAdapterTest (line 35) | @RunWith(Parameterized.class)
method parameters (line 39) | @Parameters(name = "{0}")
method lenient (line 44) | @Test
method nullSafe (line 75) | @Test
method nonNull (line 106) | @Test
method failOnUnknown (line 149) | @Test
method indent (line 177) | @Test
method indentDisallowsNull (line 204) | @Test
method serializeNulls (line 226) | @Test
method stringDocumentMustBeFullyConsumed (line 250) | @Test
method adapterFromJsonStringPeeksAtEnd (line 272) | @Test
method lenientAdapterFromJsonStringDoesNotPeekAtEnd (line 296) | @Test
method adaptersDelegateLeniency (line 313) | @Test
method nullSafeDoesntDuplicate (line 330) | @Test
method nonNullDoesntDuplicate (line 336) | @Test
FILE: moshi/src/test/java/com/squareup/moshi/JsonCodecFactory.java
class JsonCodecFactory (line 26) | abstract class JsonCodecFactory {
method factories (line 30) | static List<Object[]> factories() {
method newReader (line 190) | abstract JsonReader newReader(String json) throws IOException;
method newWriter (line 192) | abstract JsonWriter newWriter() throws IOException;
method implementsStrictPrecision (line 194) | boolean implementsStrictPrecision() {
method json (line 198) | abstract String json() throws IOException;
method encodesToBytes (line 200) | boolean encodesToBytes() {
method supportsBigNumbers (line 204) | boolean supportsBigNumbers() {
FILE: moshi/src/test/java/com/squareup/moshi/JsonQualifiersTest.java
class JsonQualifiersTest (line 27) | public final class JsonQualifiersTest {
method builtInTypes (line 28) | @Test
class BuiltInTypesJsonAdapter (line 43) | static class BuiltInTypesJsonAdapter {
method fooPrefixStringToString (line 44) | @ToJson
method fooPrefixStringFromString (line 49) | @FromJson
method readerWriterJsonAdapter (line 57) | @Test
class ReaderWriterJsonAdapter (line 72) | static class ReaderWriterJsonAdapter {
method fooPrefixStringToString (line 73) | @ToJson
method fooPrefixStringFromString (line 78) | @FromJson
class StringAndFooString (line 97) | static class StringAndFooString {
class StringAndFooBazString (line 102) | static class StringAndFooBazString {
method builtInTypesWithMultipleAnnotations (line 107) | @Test
class BuiltInTypesWithMultipleAnnotationsJsonAdapter (line 123) | static class BuiltInTypesWithMultipleAnnotationsJsonAdapter {
method fooPrefixAndBazSuffixStringToString (line 124) | @ToJson
method fooPrefixAndBazSuffixStringFromString (line 129) | @FromJson
method readerWriterWithMultipleAnnotations (line 139) | @Test
class ReaderWriterWithMultipleAnnotationsJsonAdapter (line 155) | static class ReaderWriterWithMultipleAnnotationsJsonAdapter {
method fooPrefixAndBazSuffixStringToString (line 156) | @ToJson
method fooPrefixAndBazSuffixStringFromString (line 162) | @FromJson
method basicTypesAnnotationDelegating (line 173) | @Test
class BuiltInTypesDelegatingJsonAdapter (line 192) | static class BuiltInTypesDelegatingJsonAdapter {
method fooPrefixAndBazSuffixStringToString (line 193) | @ToJson
method fooPrefixAndBazSuffixStringFromString (line 199) | @FromJson
method readerWriterAnnotationDelegating (line 208) | @Test
method manualJsonAdapter (line 227) | @Test
method noJsonAdapterForAnnotatedType (line 257) | @Test
method annotationWithoutJsonQualifierIsIgnoredByAdapterMethods (line 267) | @Test
class MissingJsonQualifierJsonAdapter (line 283) | static class MissingJsonQualifierJsonAdapter {
method dateToJson (line 284) | @ToJson
method jsonToDate (line 289) | @FromJson
class DateAndMillisDate (line 300) | static class DateAndMillisDate {
method annotationWithoutJsonQualifierIsRejectedOnRegistration (line 305) | @Test
method annotationsConflict (line 332) | @Test
class AnnotationsConflictJsonAdapter (line 342) | static class AnnotationsConflictJsonAdapter {
method fooPrefixStringToString (line 343) | @ToJson
method fooPrefixStringToString2 (line 348) | @ToJson
method toButNoFromJson (line 354) | @Test
class ToButNoFromJsonAdapter (line 385) | static class ToButNoFromJsonAdapter {
method fooPrefixStringToString (line 386) | @ToJson
method fromButNoToJson (line 392) | @Test
class FromButNoToJsonAdapter (line 423) | static class FromButNoToJsonAdapter {
method fooPrefixStringFromString (line 424) | @FromJson
FILE: moshi/src/test/java/com/squareup/moshi/JsonReaderPathTest.java
class JsonReaderPathTest (line 29) | @RunWith(Parameterized.class)
method parameters (line 33) | @Parameters(name = "{0}")
method path (line 38) | @SuppressWarnings("CheckReturnValue")
method arrayOfObjects (line 79) | @Test
method arrayOfArrays (line 100) | @Test
method objectPath (line 121) | @SuppressWarnings("CheckReturnValue")
method arrayPath (line 163) | @SuppressWarnings("CheckReturnValue")
method multipleTopLevelValuesInOneDocument (line 195) | @Test
method skipArrayElements (line 209) | @Test
method skipObjectNames (line 218) | @Test
method skipObjectValues (line 226) | @SuppressWarnings("CheckReturnValue")
method skipNestedStructures (line 238) | @Test
FILE: moshi/src/test/java/com/squareup/moshi/JsonReaderTest.java
class JsonReaderTest (line 41) | @RunWith(Parameterized.class)
method parameters (line 46) | @Parameters(name = "{0}")
method newReader (line 51) | JsonReader newReader(String json) throws IOException {
method readArray (line 55) | @Test
method readEmptyArray (line 65) | @Test
method readObject (line 74) | @Test
method readEmptyObject (line 86) | @Test
method skipArray (line 95) | @Test
method skipArrayAfterPeek (line 107) | @Test
method skipTopLevelObject (line 120) | @Test
method skipObject (line 127) | @Test
method skipObjectAfterPeek (line 140) | @Test
method skipInteger (line 162) | @Test
method skipDouble (line 174) | @Test
method failOnUnknownFailsOnUnknownObjectValue (line 186) | @Test
method failOnUnknownFailsOnUnknownArrayElement (line 205) | @Test
method helloWorld (line 224) | @Test
method emptyString (line 239) | @Test
method characterUnescaping (line 253) | @Test
method integersWithFractionalPartSpecified (line 301) | @Test
method doubles (line 310) | @Test
method strictNonFiniteDoubles (line 337) | @Test
method strictQuotedNonFiniteDoubles (line 349) | @Test
method lenientNonFiniteDoubles (line 362) | @Test
method lenientQuotedNonFiniteDoubles (line 374) | @Test
method longs (line 386) | @Test
method booleans (line 419) | @Test
method nextFailuresDoNotAdvance (line 429) | @Test
method integerMismatchWithDoubleDoesNotAdvance (line 490) | @Test
method integerMismatchWithLongDoesNotAdvance (line 505) | @Test
method longMismatchWithDoubleDoesNotAdvance (line 520) | @Test
method stringNullIsNotNull (line 535) | @Test
method nullLiteralIsNotAString (line 546) | @Test
method topLevelValueTypes (line 557) | @Test
method topLevelValueTypeWithSkipValue (line 584) | @Test
method deeplyNestedArrays (line 591) | @Test
method deeplyNestedObjects (line 607) | @Test
method skipVeryLongUnquotedString (line 630) | @Test
method skipTopLevelUnquotedString (line 639) | @Test
method skipVeryLongQuotedString (line 647) | @Test
method skipTopLevelQuotedString (line 655) | @Test
method stringAsNumberWithTruncatedExponent (line 663) | @Test
method stringAsNumberWithDigitAndNonDigitExponent (line 671) | @Test
method stringAsNumberWithNonDigitExponent (line 679) | @Test
method emptyStringName (line 687) | @Test
method validEscapes (line 702) | @Test
method selectName (line 709) | @Test
method selectNameNecessaryEscaping (line 746) | @Test
method selectNameUnnecessaryEscaping (line 765) | @Test
method selectNameUnquoted (line 789) | @Test
method selectNameSingleQuoted (line 805) | @Test
method selectString (line 821) | @Test
method selectStringNecessaryEscaping (line 849) | @Test
method selectStringUnnecessaryEscaping (line 862) | @Test
method selectStringUnquoted (line 874) | @Test
method selectStringSingleQuoted (line 887) | @Test
method selectStringMaintainsReaderState (line 900) | @Test
method selectStringWithoutString (line 914) | @Test
method stringToNumberCoersion (line 930) | @Test
method unnecessaryPrecisionNumberCoersion (line 940) | @Test
method nanInfinityDoubleCoersion (line 949) | @Test
method intMismatchWithStringDoesNotAdvance (line 960) | @Test
method longMismatchWithStringDoesNotAdvance (line 973) | @Test
method doubleMismatchWithStringDoesNotAdvance (line 986) | @Test
method readJsonValueInt (line 999) | @Test
method readJsonValueMap (line 1006) | @Test
method readJsonValueList (line 1013) | @Test
method readJsonValueListMultipleTypes (line 1020) | @Test
method readJsonValueNestedListInMap (line 1027) | @Test
method skipName (line 1035) | @Test
method skipNameFailUnknown (line 1045) | @Test
method skipNameOnValueFails (line 1060) | @Test
method emptyDocumentHasNextReturnsFalse (line 1071) | @Test
method skipValueAtEndOfObjectFails (line 1078) | @Test
method skipValueAtEndOfArrayFails (line 1094) | @Test
method skipValueAtEndOfDocumentFails (line 1110) | @Test
method basicPeekJson (line 1125) | @Test
method peekJsonReader (line 1158) | @Test
method readPeek12Steps (line 1171) | private void readPeek12Steps(JsonReader reader, int from, int until) t...
method peekAfterPeek (line 1225) | @Test
method peekAfterPromoteNameToValue (line 1234) | @Test
method promoteStringNameToValue (line 1246) | @Test
method promoteDoubleNameToValue (line 1256) | @Test
method promoteLongNameToValue (line 1266) | @Test
method promoteNullNameToValue (line 1276) | @Test
method promoteBooleanNameToValue (line 1289) | @Test
method promoteBooleanNameToValueCannotBeReadAsName (line 1302) | @Test
method promoteSkippedNameToValue (line 1315) | @Test
method promoteNameToValueAtEndOfObject (line 1324) | @Test
method optionsStrings (line 1333) | @Test
method nextSourceString (line 1348) | @Test
method nextSourceLong (line 1359) | @Test
method nextSourceNull (line 1370) | @Test
method nextSourceBoolean (line 1381) | @Test
method nextSourceObject (line 1392) | @Test
method nextSourceArray (line 1403) | @Test
method nextSourceStringBuffered (line 1418) | @Test
method nextSourceNotConsumed (line 1431) | @Test
method tags (line 1442) | @SuppressWarnings("rawtypes")
method readValue (line 1470) | private void readValue(JsonReader reader, boolean peekJsonFirst) throw...
FILE: moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java
class JsonUtf8ReaderTest (line 45) | public final class JsonUtf8ReaderTest {
method readingDoesNotBuffer (line 46) | @Test
method readObjectBuffer (line 61) | @Test
method readObjectSource (line 74) | @Test
method nullSource (line 87) | @Test
method unescapingInvalidCharacters (line 96) | @Test
method unescapingTruncatedCharacters (line 108) | @Test
method unescapingTruncatedSequence (line 120) | @Test
method strictNonFiniteDoublesWithSkipValue (line 132) | @Test
method numberWithOctalPrefix (line 144) | @Test
method peekingUnquotedStringsPrefixedWithBooleans (line 175) | @Test
method malformedNumbers (line 190) | @Test
method assertNotANumber (line 228) | private void assertNotANumber(String s) throws IOException {
method peekingUnquotedStringsPrefixedWithIntegers (line 237) | @Test
method peekLongMinValue (line 251) | @Test
method peekLongMaxValue (line 260) | @Test
method longLargerThanMaxLongThatWrapsAround (line 269) | @Test
method longLargerThanMinLongThatWrapsAround (line 282) | @Test
method peekLargerThanLongMaxValue (line 295) | @Test
method precisionNotDiscarded (line 308) | @Test
method peekLargerThanLongMinValue (line 321) | @Test
method highPrecisionLong (line 335) | @Test
method peekMuchLargerThanLongMinValue (line 344) | @Test
method negativeZeroIsANumber (line 358) | @Test
method numberToStringCoersion (line 365) | @Test
method quotedNumberWithEscape (line 378) | @Test
method mixedCaseLiterals (line 387) | @Test
method missingValue (line 401) | @Test
method prematureEndOfInput (line 413) | @Test
method prematurelyClosed (line 426) | @SuppressWarnings("CheckReturnValue")
method strictNameValueSeparator (line 458) | @Test
method lenientNameValueSeparator (line 479) | @Test
method strictNameValueSeparatorWithSkipValue (line 494) | @Test
method commentsInStringValue (line 515) | @Test
method strictComments (line 535) | @Test
method lenientComments (line 562) | @Test
method strictCommentsWithSkipValue (line 585) | @Test
method strictUnquotedNames (line 612) | @Test
method lenientUnquotedNames (line 623) | @Test
method jsonIsSingleUnquotedString (line 631) | @Test
method strictUnquotedNamesWithSkipValue (line 639) | @Test
method strictSingleQuotedNames (line 650) | @Test
method lenientSingleQuotedNames (line 661) | @Test
method strictSingleQuotedNamesWithSkipValue (line 669) | @Test
method strictUnquotedStrings (line 680) | @Test
method strictUnquotedStringsWithSkipValue (line 691) | @Test
method lenientUnquotedStrings (line 702) | @Test
method lenientUnquotedStringsDelimitedByComment (line 710) | @Test
method strictSingleQuotedStrings (line 719) | @Test
method lenientSingleQuotedStrings (line 730) | @Test
method strictSingleQuotedStringsWithSkipValue (line 738) | @Test
method strictSemicolonDelimitedArray (line 749) | @Test
method lenientSemicolonDelimitedArray (line 761) | @Test
method strictSemicolonDelimitedArrayWithSkipValue (line 770) | @Test
method strictSemicolonDelimitedNameValuePair (line 782) | @Test
method lenientSemicolonDelimitedNameValuePair (line 795) | @Test
method strictSemicolonDelimitedNameValuePairWithSkipValue (line 805) | @Test
method strictUnnecessaryArraySeparators (line 818) | @Test
method lenientUnnecessaryArraySeparators (line 855) | @Test
method strictUnnecessaryArraySeparatorsWithSkipValue (line 887) | @Test
method strictMultipleTopLevelValues (line 924) | @Test
method lenientMultipleTopLevelValues (line 936) | @Test
method strictMultipleTopLevelValuesWithSkipValue (line 948) | @Test
method bomIgnoredAsFirstCharacterOfDocument (line 960) | @Test
method bomForbiddenAsOtherCharacterInDocument (line 968) | @Test
method failWithPosition (line 979) | @Test
method failWithPositionGreaterThanBufferSize (line 984) | @Test
method failWithPositionOverSlashSlashEndOfLineComment (line 990) | @Test
method failWithPositionOverHashEndOfLineComment (line 995) | @Test
method failWithPositionOverCStyleComment (line 1000) | @Test
method failWithPositionOverQuotedString (line 1005) | @Test
method failWithPositionOverUnquotedString (line 1010) | @Test
method failWithEscapedNewlineCharacter (line 1015) | @Test
method failWithPositionIsOffsetByBom (line 1020) | @Test
method testFailWithPosition (line 1026) | private void testFailWithPosition(String message, String json) throws ...
method failWithPositionDeepPath (line 1052) | @SuppressWarnings("CheckReturnValue")
method failureMessagePathFromSkipName (line 1071) | @Test
method strictVeryLongNumber (line 1086) | @Test
method lenientVeryLongNumber (line 1098) | @Test
method veryLongUnquotedLiteral (line 1110) | @Test
method tooDeeplyNestedArrays (line 1120) | @Test
method tooDeeplyNestedObjects (line 1136) | @Test
method stringEndingInSlash (line 1161) | @Test
method documentWithCommentEndingInSlash (line 1172) | @Test
method stringWithLeadingSlash (line 1183) | @Test
method unterminatedObject (line 1194) | @Test
method veryLongQuotedString (line 1208) | @Test
method veryLongUnquotedString (line 1220) | @Test
method veryLongUnterminatedString (line 1233) | @Test
method strictExtraCommasInMaps (line 1250) | @Test
method lenientExtraCommasInMaps (line 1263) | @Test
method malformedDocuments (line 1277) | @Test
method unterminatedStringFailure (line 1326) | @Test
method invalidEscape (line 1339) | @Test
method lenientInvalidEscape (line 1351) | @Test
method assertDocument (line 1359) | private void assertDocument(String document, Object... expectations) t...
method nextSourceObject_withWhitespace (line 1395) | @Test
method nextSourceLong_WithWhitespace (line 1406) | @Test
method nextSourceStreams (line 1425) | @Test
method nextSourceObjectAfterSelect (line 1445) | @Test
method nextSourceObjectAfterPromoteNameToValue (line 1456) | @Test
method nextSourcePath (line 1469) | @Test
FILE: moshi/src/test/java/com/squareup/moshi/JsonUtf8WriterTest.java
class JsonUtf8WriterTest (line 24) | public final class JsonUtf8WriterTest {
method prettyPrintObject (line 25) | @Test
method prettyPrintArray (line 65) | @Test
method repeatedNameIgnored (line 104) | @Test
method valueFromSource (line 116) | @Test
FILE: moshi/src/test/java/com/squareup/moshi/JsonValueReaderTest.java
class JsonValueReaderTest (line 35) | public final class JsonValueReaderTest {
method array (line 36) | @Test
method object (line 72) | @Test
method nesting (line 116) | @Test
method promoteNameToValue (line 169) | @Test
method endArrayTooEarly (line 186) | @Test
method endObjectTooEarly (line 201) | @Test
method unsupportedType (line 214) | @Test
method unsupportedKeyType (line 229) | @Test
method nullKey (line 244) | @Test
method unexpectedIntType (line 257) | @Test
method unexpectedLongType (line 271) | @Test
method unexpectedDoubleType (line 285) | @Test
method unexpectedStringType (line 299) | @Test
method unexpectedBooleanType (line 313) | @Test
method unexpectedNullType (line 327) | @Test
method skipRoot (line 341) | @Test
method skipListValue (line 348) | @Test
method skipObjectName (line 370) | @Test
method skipObjectValue (line 398) | @Test
method failOnUnknown (line 426) | @Test
method close (line 440) | @Test
method numberToStringCoersion (line 460) | @Test
method tooDeeplyNestedArrays (line 474) | @Test
method tooDeeplyNestedObjects (line 494) | @Test
FILE: moshi/src/test/java/com/squareup/moshi/JsonValueWriterTest.java
class JsonValueWriterTest (line 35) | public final class JsonValueWriterTest {
method array (line 36) | @SuppressWarnings("unchecked")
method object (line 51) | @Test
method repeatedNameThrows (line 67) | @Test
method valueLongEmitsLong (line 82) | @Test
method valueDoubleEmitsDouble (line 97) | @Test
method primitiveIntegerTypesEmitLong (line 153) | @Test
method primitiveFloatingPointTypesEmitDouble (line 168) | @Test
method otherNumberTypesEmitBigDecimal (line 180) | @Test
method valueCustomNumberTypeEmitsLongOrBigDecimal (line 229) | @Test
method valueFromSource (line 248) | @Test
method stringNumber (line 270) | private Number stringNumber(final String s) {
FILE: moshi/src/test/java/com/squareup/moshi/JsonWriterPathTest.java
class JsonWriterPathTest (line 30) | @RunWith(Parameterized.class)
method parameters (line 34) | @Parameters(name = "{0}")
method path (line 39) | @Test
method arrayOfObjects (line 79) | @Test
method arrayOfArrays (line 100) | @Test
method objectPath (line 121) | @Test
method nestedObjects (line 141) | @Test
method arrayPath (line 167) | @Test
method nestedArrays (line 189) | @Test
method multipleTopLevelValuesInOneDocument (line 211) | @Test
method skipNulls (line 225) | @Test
FILE: moshi/src/test/java/com/squareup/moshi/JsonWriterTest.java
class JsonWriterTest (line 39) | @RunWith(Parameterized.class)
method parameters (line 43) | @Parameters(name = "{0}")
method nullsValuesNotSerializedByDefault (line 48) | @Test
method nullsValuesSerializedWhenConfigured (line 59) | @Test
method topLevelBoolean (line 71) | @Test
method topLevelNull (line 79) | @Test
method topLevelInt (line 87) | @Test
method topLevelDouble (line 95) | @Test
method topLevelString (line 103) | @Test
method invalidTopLevelTypes (line 111) | @Test
method twoNames (line 121) | @Test
method nameWithoutValue (line 133) | @Test
method valueWithoutName (line 145) | @Test
method multipleTopLevelValues (line 156) | @Test
method badNestingObject (line 167) | @Test
method badNestingArray (line 179) | @Test
method nullName (line 191) | @Test
method nullStringValue (line 202) | @Test
method nonFiniteDoubles (line 213) | @Test
method nonFiniteBoxedDoubles (line 234) | @Test
method doubles (line 255) | @Test
method longs (line 283) | @Test
method numbers (line 298) | @Test
method nullNumbers (line 318) | @Test
method booleans (line 328) | @Test
method boxedBooleans (line 338) | @Test
method nulls (line 349) | @Test
method strings (line 358) | @Test
method unicodeLineBreaksEscaped (line 403) | @Test
method emptyArray (line 412) | @Test
method emptyObject (line 420) | @Test
method objectsInArrays (line 428) | @Test
method arraysInObjects (line 444) | @Test
method deepNestingArrays (line 462) | @Test
method tooDeeplyNestingArrays (line 474) | @Test
method deepNestingObjects (line 490) | @Test
method tooDeeplyNestingObjects (line 505) | @Test
method lenientWriterPermitsMultipleTopLevelValues (line 522) | @Test
method strictWriterDoesNotPermitMultipleTopLevelValues (line 536) | @Test
method closedWriterThrowsOnStructure (line 548) | @Test
method closedWriterThrowsOnName (line 576) | @Test
method closedWriterThrowsOnValue (line 589) | @Test
method closedWriterThrowsOnFlush (line 602) | @Test
method writerCloseIsIdempotent (line 615) | @Test
method nameNotInObjectFails (line 624) | @Test
method missingValueInObjectIsANestingProblem (line 635) | @Test
method nameInArrayIsANestingProblem (line 648) | @Test
method danglingNameFails (line 660) | @Test
method streamingValueInObject (line 673) | @Test
method streamingValueInArray (line 689) | @Test
method streamingValueTopLevel (line 700) | @Test
method streamingValueTwiceBeforeCloseFails (line 707) | @Test
method streamingValueTwiceAfterCloseFails (line 721) | @Test
method streamingValueAndScalarValueFails (line 736) | @Test
method streamingValueAndNameFails (line 750) | @Test
method streamingValueInteractionAfterCloseFails (line 764) | @Test
method streamingValueCloseIsIdempotent (line 780) | @Test
method jsonValueTypes (line 795) | @Test
method jsonValueIllegalTypes (line 832) | @Test
method promoteStringNameToValue (line 869) | @Test
method promoteDoubleNameToValue (line 880) | @Test
method promoteLongNameToValue (line 891) | @Test
method promoteNumberNameToValue (line 902) | @Test
method promoteNullNameToValue (line 913) | @Test
method promoteBooleanNameToValue (line 928) | @Test
method promoteNameToValueCannotBeWrittenAsName (line 943) | @Test
method promoteNameToValueAtEndOfObject (line 956) | @Test
method tags (line 965) | @SuppressWarnings("rawtypes")
FILE: moshi/src/test/java/com/squareup/moshi/MoshiTest.java
class MoshiTest (line 53) | @SuppressWarnings({"CheckReturnValue", "ResultOfMethodCallIgnored"})
method booleanAdapter (line 55) | @Test
method BooleanAdapter (line 81) | @Test
method byteAdapter (line 94) | @Test
method ByteAdapter (line 141) | @Test
method charAdapter (line 152) | @Test
method CharacterAdapter (line 232) | @Test
method doubleAdapter (line 253) | @Test
method DoubleAdapter (line 314) | @Test
method floatAdapter (line 327) | @Test
method FloatAdapter (line 388) | @Test
method intAdapter (line 401) | @Test
method IntegerAdapter (line 447) | @Test
method longAdapter (line 458) | @Test
method LongAdapter (line 504) | @Test
method shortAdapter (line 515) | @Test
method ShortAdapter (line 557) | @Test
method stringAdapter (line 568) | @Test
method upperBoundedWildcardsAreHandled (line 578) | @Test
method lowerBoundedWildcardsAreNotHandled (line 588) | @Test
method addNullFails (line 601) | @Test
method customJsonAdapter (line 650) | @Test
method classAdapterToObjectAndFromObject (line 661) | @Test
method customJsonAdapterToObjectAndFromObject (line 676) | @Test
method indent (line 691) | @Test
method unindent (line 701) | @Test
method composingJsonAdapterFactory (line 723) | @Test
class Message (line 738) | static class Message {
method registerJsonAdapterForAnnotatedType (line 743) | @Test
method adapterLookupDisallowsNullType (line 770) | @Test
method adapterLookupDisallowsNullAnnotations (line 781) | @Test
method nextJsonAdapterDisallowsNullAnnotations (line 798) | @Test
method delegatingJsonAdapterFactory (line 820) | @Test
method listJsonAdapter (line 831) | @Test
method setJsonAdapter (line 840) | @Test
method collectionJsonAdapter (line 853) | @Test
method collectionsDoNotKeepAnnotations (line 868) | @Test
method noTypeAdapterForQualifiedPlatformType (line 886) | @Test
method objectArray (line 903) | @Test
method primitiveArray (line 911) | @Test
method enumAdapter (line 919) | @Test
method annotatedEnum (line 927) | @Test
method invalidEnum (line 935) | @Test
method invalidEnumHasCorrectPathInExceptionMessage (line 949) | @Test
method nullEnum (line 967) | @Test
method byDefaultUnknownFieldsAreIgnored (line 975) | @Test
method failOnUnknownThrowsOnUnknownFields (line 984) | @Test
method platformTypeThrows (line 996) | @Test
method collectionClassesHaveClearErrorMessage (line 1028) | @Test
method noCollectionErrorIfAdapterExplicitlyProvided (line 1060) | @Test
class HasPlatformType (line 1079) | static final class HasPlatformType {
class Wrapper (line 1082) | static final class Wrapper {
class ListWrapper (line 1086) | static final class ListWrapper {
method reentrantFieldErrorMessagesTopLevelMap (line 1091) | @Test
method reentrantFieldErrorMessagesWrapper (line 1115) | @Test
method reentrantFieldErrorMessagesListWrapper (line 1138) | @Test
method qualifierWithElementsMayNotBeDirectlyRegistered (line 1162) | @Test
method qualifierWithElements (line 1178) | @Test
method adaptersRegisteredInOrderOfPrecedence (line 1196) | @Test
method cachingJsonAdapters (line 1230) | @Test
method newBuilder (line 1239) | @Test
method referenceCyclesOnArrays (line 1249) | @Test
method referenceCyclesOnObjects (line 1264) | @Test
method referenceCyclesOnMixedTypes (line 1279) | @Test
method duplicateKeyDisallowedInObjectType (line 1296) | @Test
method duplicateKeysAllowedInCustomType (line 1311) | @Test
method precedence (line 1319) | @Test
method precedenceWithNewBuilder (line 1332) | @Test
class AppendingAdapterFactory (line 1355) | static final class AppendingAdapterFactory implements JsonAdapter.Fact...
method AppendingAdapterFactory (line 1358) | AppendingAdapterFactory(String suffix) {
method create (line 1362) | @Override
class Pizza (line 1381) | static class Pizza {
method Pizza (line 1385) | Pizza(int diameter, boolean extraCheese) {
method equals (line 1390) | @Override
method hashCode (line 1397) | @Override
class MealDeal (line 1403) | static class MealDeal {
method MealDeal (line 1407) | MealDeal(Pizza pizza, String drink) {
method equals (line 1412) | @Override
method hashCode (line 1419) | @Override
class PizzaAdapter (line 1425) | static class PizzaAdapter extends JsonAdapter<Pizza> {
method fromJson (line 1426) | @Override
method toJson (line 1445) | @Override
class MealDealAdapterFactory (line 1454) | static class MealDealAdapterFactory implements JsonAdapter.Factory {
method create (line 1455) | @Override
class UppercaseAdapterFactory (line 1485) | static class UppercaseAdapterFactory implements JsonAdapter.Factory {
method create (line 1486) | @Override
type Roshambo (line 1508) | enum Roshambo {
class Baguette (line 1521) | static class Baguette {
class LocalizedBooleanAdapter (line 1529) | static class LocalizedBooleanAdapter extends JsonAdapter<Boolean> {
method create (line 1532) | @Override
method LocalizedBooleanAdapter (line 1549) | public LocalizedBooleanAdapter(String language) {
method fromJson (line 1559) | @Override
method toJson (line 1564) | @Override
FILE: moshi/src/test/java/com/squareup/moshi/ObjectAdapterTest.java
class ObjectAdapterTest (line 43) | public final class ObjectAdapterTest {
method toJsonUsesRuntimeType (line 44) | @Test
method toJsonJavaLangObject (line 66) | @Test
method fromJsonReturnsMapsAndLists (line 73) | @Test
method fromJsonUsesDoublesForNumbers (line 96) | @Test
method fromJsonDoesNotFailOnNullValues (line 103) | @Test
method toJsonCoercesRuntimeTypeForCollections (line 114) | @Test
method toJsonCoercesRuntimeTypeForLists (line 134) | @Test
method toJsonCoercesRuntimeTypeForSets (line 154) | @Test
method toJsonCoercesRuntimeTypeForMaps (line 174) | @Test
method toJsonUsesTypeAdapters (line 189) | @Test
method objectAdapterDelegatesStringNamesAndValues (line 212) | @Test
method objectAdapterDelegatesObjects (line 238) | @Test
method objectAdapterDelegatesLists (line 279) | @Test
method objectAdapterDelegatesMaps (line 302) | @Test
class Delivery (line 324) | static class Delivery {
class Pizza (line 329) | static class Pizza {
FILE: moshi/src/test/java/com/squareup/moshi/PromoteNameToValueTest.java
class PromoteNameToValueTest (line 29) | @RunWith(Parameterized.class)
method parameters (line 33) | @Parameters(name = "{0}")
method readerStringValue (line 38) | @Test
method readerIntegerValue (line 53) | @Test
method readerDoubleValue (line 68) | @Test
method readerBooleanValue (line 83) | @Test
method readerLongValue (line 108) | @Test
method readerNullValue (line 123) | @Test
method readerMultipleValueObject (line 148) | @Test
method readerEmptyValueObject (line 165) | @Test
method readerUnusedPromotionDoesntPersist (line 176) | @Test
method readerUnquotedIntegerValue (line 192) | @Test
method readerUnquotedLongValue (line 203) | @Test
method readerUnquotedDoubleValue (line 214) | @Test
method writerStringValue (line 225) | @Test
method writerIntegerValue (line 239) | @Test
method writerDoubleValue (line 253) | @Test
method writerBooleanValue (line 267) | @Test
method writerLongValue (line 288) | @Test
method writerNullValue (line 302) | @Test
method writerMultipleValueObject (line 324) | @Test
method writerEmptyValueObject (line 340) | @Test
method writerUnusedPromotionDoesntPersist (line 351) | @Test
method writerSourceValueFails (line 367) | @Test
method writerValueSinkFails (line 386) | @Test
FILE: moshi/src/test/java/com/squareup/moshi/RecursiveTypesResolveTest.java
class RecursiveTypesResolveTest (line 37) | public final class RecursiveTypesResolveTest {
class Foo1 (line 39) | private static class Foo1<A> {
class Foo2 (line 43) | private static class Foo2<B> {
method recursiveResolveSimple (line 48) | @Test
method doubleSupertype (line 58) | @Test
method doubleSubtype (line 64) | @Test
method superSubtype (line 69) | @Test
method subSupertype (line 74) | @Test
FILE: moshi/src/test/java/com/squareup/moshi/TestUtil.java
class TestUtil (line 21) | public final class TestUtil {
method newReader (line 24) | public static JsonReader newReader(String json) {
method repeat (line 29) | public static String repeat(char c, int count) {
method repeat (line 35) | public static String repeat(String s, int count) {
method TestUtil (line 43) | private TestUtil() {
FILE: moshi/src/test/java/com/squareup/moshi/TypesTest.java
class TypesTest (line 39) | public final class TypesTest {
method nextAnnotationsRequiresJsonAnnotation (line 53) | @Test
method nextAnnotationsDoesNotContainReturnsNull (line 66) | @Test
method nextAnnotationsReturnsDelegateAnnotations (line 75) | @Test
method newParameterizedType (line 86) | @Test
method newParameterizedType_missingTypeVars (line 97) | @Test
method parameterizedTypeWithRequiredOwnerMissing (line 114) | @Test
method parameterizedTypeWithUnnecessaryOwnerProvided (line 126) | @Test
method parameterizedTypeWithIncorrectOwnerProvided (line 138) | @Test
method arrayOf (line 150) | @Test
method subtypeOf (line 160) | @Test
method supertypeOf (line 167) | @Test
method getFirstTypeArgument (line 174) | @Test
method newParameterizedTypeObjectMethods (line 182) | @Test
class A (line 200) | private static final class A {}
class B (line 202) | private static final class B {}
class C (line 204) | private static final class C {}
class D (line 206) | private static final class D<T> {}
class E (line 208) | private static final class E<T extends A, T2 extends B> {}
method getFirstTypeArgument (line 214) | public static Type getFirstTypeArgument(Type type) throws Exception {
type StringIntegerMap (line 226) | interface StringIntegerMap extends Map<String, Integer> {}
method arrayComponentType (line 228) | @Test
method collectionElementType (line 241) | @Test
method mapKeyAndValueTypes (line 251) | @Test
method propertiesTypes (line 261) | @Test
method fixedVariablesTypes (line 269) | @Test
method createJsonQualifierImplementation (line 277) | @SuppressWarnings("GetClassOnAnnotation") // Explicitly checking for p...
method arrayEqualsGenericTypeArray (line 290) | @Test
method parameterizedTypeMatchesClassWithGenericInfoFromReturn (line 298) | @Test
method parameterizedAndWildcardTypesCannotHavePrimitiveArguments (line 317) | @Test
method getFieldJsonQualifierAnnotations_privateFieldTest (line 345) | @Test
method getFieldJsonQualifierAnnotations_publicFieldTest (line 354) | @Test
method getFieldJsonQualifierAnnotations_unannotatedTest (line 363) | @Test
method generatedJsonAdapterName_strings (line 371) | @Test
method generatedJsonAdapterName_class (line 378) | @Test
method generatedJsonAdapterName_class_missingJsonClass (line 384) | @Test
class RecursiveTypeVars (line 400) | private static final class RecursiveTypeVars<T> {
method recursiveTypeVariablesResolve (line 404) | @Test
method recursiveTypeVariablesResolve1 (line 415) | @Test
method recursiveTypeVariablesResolve2 (line 421) | @Test
class TestType (line 427) | private static class TestType<X> {
class TestType2 (line 431) | private static class TestType2<X, Y> {
class TestJsonClass (line 435) | @JsonClass(generateAdapter = false)
class TestNonJsonClass (line 438) | static class TestNonJsonClass {}
class ClassWithAnnotatedFields (line 449) | static class ClassWithAnnotatedFields {
FILE: moshi/src/test/java/com/squareup/moshi/internal/ClassJsonAdapterTest.java
class ClassJsonAdapterTest (line 38) | public final class ClassJsonAdapterTest {
class BasicPizza (line 41) | static class BasicPizza {
method basicClassAdapter (line 46) | @Test
class PrivateFieldsPizza (line 59) | static class PrivateFieldsPizza {
method privateFields (line 63) | @Test
class BasePizza (line 75) | static class BasePizza {
class DessertPizza (line 79) | static class DessertPizza extends BasePizza {
method typeHierarchy (line 83) | @Test
class BaseAbcde (line 96) | static class BaseAbcde {
class ExtendsBaseAbcde (line 102) | static class ExtendsBaseAbcde extends BaseAbcde {
method fieldsAreAlphabeticalAcrossFlattenedHierarchy (line 107) | @Test
class StaticFields (line 127) | static class StaticFields {
method staticFieldsOmitted (line 132) | @Test
class TransientFields (line 144) | static class TransientFields {
method transientFieldsOmitted (line 149) | @Test
class IgnoredFields (line 162) | static class IgnoredFields {
method ignoredFieldsOmitted (line 169) | @Test
class BaseA (line 182) | static class BaseA {
class ExtendsBaseA (line 186) | static class ExtendsBaseA extends BaseA {
method fieldNameCollision (line 190) | @Test
class NameCollision (line 205) | static class NameCollision {
method jsonAnnotationNameCollision (line 212) | @Test
class TransientBaseA (line 227) | static class TransientBaseA {
class ExtendsTransientBaseA (line 231) | static class ExtendsTransientBaseA extends TransientBaseA {
method fieldNameCollisionWithTransientFieldIsOkay (line 235) | @Test
class NoArgConstructor (line 248) | static class NoArgConstructor {
method NoArgConstructor (line 252) | NoArgConstructor() {
method noArgConstructor (line 257) | @Test
class NoArgConstructorThrowsCheckedException (line 264) | static class NoArgConstructorThrowsCheckedException {
method NoArgConstructorThrowsCheckedException (line 265) | NoArgConstructorThrowsCheckedException() throws Exception {
method noArgConstructorThrowsCheckedException (line 270) | @Test
class NoArgConstructorThrowsUncheckedException (line 280) | static class NoArgConstructorThrowsUncheckedException {
method NoArgConstructorThrowsUncheckedException (line 281) | NoArgConstructorThrowsUncheckedException() throws Exception {
method noArgConstructorThrowsUncheckedException (line 286) | @Test
class NoArgConstructorWithDefaultField (line 296) | static class NoArgConstructorWithDefaultField {
method noArgConstructorFieldDefaultsHonored (line 301) | @Test
class MagicConstructor (line 309) | static class MagicConstructor {
method MagicConstructor (line 312) | public MagicConstructor(Void argument) {
method magicConstructor (line 317) | @Test
class MagicConstructorWithDefaultField (line 323) | static class MagicConstructorWithDefaultField {
method MagicConstructorWithDefaultField (line 327) | public MagicConstructorWithDefaultField(Void argument) {
method magicConstructorFieldDefaultsNotHonored (line 332) | @Test
class NullRootObject (line 340) | static class NullRootObject {
method nullRootObject (line 344) | @Test
class NullFieldValue (line 353) | static class NullFieldValue {
method nullFieldValues (line 357) | @Test
class NonStatic (line 368) | class NonStatic {}
method nonStaticNestedClassNotSupported (line 370) | @Test
method anonymousClassNotSupported (line 384) | @Test
method localClassNotSupported (line 403) | @Test
type Interface (line 418) | interface Interface {}
method interfaceNotSupported (line 420) | @Test
class Abstract (line 425) | abstract static class Abstract {}
method abstractClassNotSupported (line 427) | @Test
class ExtendsPlatformClassWithPrivateField (line 441) | static class ExtendsPlatformClassWithPrivateField extends SimpleTimeZo...
method ExtendsPlatformClassWithPrivateField (line 444) | public ExtendsPlatformClassWithPrivateField() {
method platformSuperclassPrivateFieldIsExcluded (line 449) | @Test
class ExtendsPlatformClassWithProtectedField (line 462) | static class ExtendsPlatformClassWithProtectedField extends ByteArrayO...
method ExtendsPlatformClassWithProtectedField (line 465) | public ExtendsPlatformClassWithProtectedField() {
method platformSuperclassProtectedFieldIsIncluded (line 470) | @Test
class NamedFields (line 486) | static class NamedFields {
method jsonAnnotationHonored (line 497) | @Test
class Box (line 526) | static final class Box<T> {
method Box (line 529) | Box(T data) {
method parameterizedType (line 534) | @Test
method toJson (line 548) | private <T> String toJson(Class<T> type, T value) throws IOException {
method fromJson (line 566) | private <T> T fromJson(Class<T> type, String json) throws IOException {
FILE: moshi/src/test/java/com/squareup/moshi/internal/JsonValueSourceTest.java
class JsonValueSourceTest (line 26) | public final class JsonValueSourceTest {
method simpleValues (line 27) | @Test
method braceMatching (line 34) | @Test
method stringEscapes (line 41) | @Test
method bracesInStrings (line 51) | @Test
method unterminatedString (line 58) | @Test
method unterminatedObject (line 67) | @Test
method unterminatedArray (line 81) | @Test
method lenientUnterminatedSingleQuotedString (line 95) | @Test
method emptyStream (line 104) | @Test
method lenientSingleQuotedStrings (line 123) | @Test
method lenientCStyleComments (line 129) | @Test
method lenientEndOfLineComments (line 138) | @Test
method lenientSlashInToken (line 146) | @Test
method lenientUnterminatedEndOfLineComment (line 151) | @Test
method lenientUnterminatedCStyleComment (line 160) | @Test
method discard (line 179) | @Test
method jsonPrefix (line 191) | private String jsonPrefix(String string) throws IOException {
FILE: moshi/src/test/java/com/squareup/moshi/internal/LinkedHashTreeMapTest.java
class LinkedHashTreeMapTest (line 27) | @SuppressWarnings("KotlinInternalInJava")
method iterationOrder (line 29) | @Test
method removeRootDoesNotDoubleUnlink (line 39) | @Test
method putNullKeyFails (line 53) | @Test
method putNonComparableKeyFails (line 63) | @Test
method ContainsNonComparableKeyReturnsFalse (line 73) | @Test
method containsNullKeyIsAlwaysFalse (line 80) | @Test
method putOverrides (line 87) | @Test
method emptyStringValues (line 100) | @Test
method forceDoublingAndRehash (line 111) | @Test
method clear (line 128) | @Test
method equalsAndHashCode (line 139) | @Test
method avlWalker (line 157) | @Test
method assertAvlWalker (line 177) | private void assertAvlWalker(Node<String, String> root, String... valu...
method avlBuilder (line 186) | @Test
method assertAvlBuilder (line 214) | private void assertAvlBuilder(int size, String expected) {
method doubleCapacity (line 224) | @Test
method doubleCapacityAllNodesOnLeft (line 235) | @Test
method node (line 254) | private Node<String, String> node(String value) {
method node (line 258) | private Node<String, String> node(
method assertTree (line 272) | private void assertTree(String expected, Node<?, ?> root) {
method assertConsistent (line 277) | private void assertConsistent(Node<?, ?> node) {
method toString (line 298) | private String toString(Node<?, ?> root) {
FILE: moshi/src/test/java/com/squareup/moshi/internal/MapJsonAdapterTest.java
class MapJsonAdapterTest (line 38) | public final class MapJsonAdapterTest {
method map (line 41) | @Test
method mapWithNullKeyFailsToEmit (line 60) | @Test
method emptyMap (line 73) | @Test
method nullMap (line 84) | @Test
method covariantValue (line 99) | @Test
method orderIsRetained (line 121) | @Test
method duplicatesAreForbidden (line 138) | @Test
method mapWithNonStringKeys (line 151) | @Test
method mapWithNonStringKeysToJsonObject (line 170) | @Test
method booleanKeyTypeHasCoherentErrorMessage (line 187) | @Test
class Key (line 210) | static final class Key {}
method objectKeyTypeHasCoherentErrorMessage (line 212) | @Test
method arrayKeyTypeHasCoherentErrorMessage (line 235) | @Test
method toJson (line 259) | private <K, V> String toJson(Type keyType, Type valueType, Map<K, V> v...
method mapAdapter (line 268) | @SuppressWarnings("unchecked") // It's the caller's responsibility to ...
method fromJson (line 275) | private <K, V> Map<K, V> fromJson(Type keyType, Type valueType, String...
Condensed preview — 183 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,291K chars).
[
{
"path": ".editorconfig",
"chars": 174,
"preview": "root = true\n\n[*]\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nmax_line_le"
},
{
"path": ".gitattributes",
"chars": 52,
"preview": "* text=auto eol=lf\n\n*.bat text eol=crlf\n*.jar binary"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 420,
"preview": "---\nname: Bug report\nabout: A reproducible problem\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\nGood bug reports include a "
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 198,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: Question?\n url: https://stackoverflow.com/questions/tagged/moshi"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 345,
"preview": "---\nname: Feature request\nabout: Suggest an idea\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\nStart by telling us w"
},
{
"path": ".github/renovate.json5",
"chars": 657,
"preview": "{\n $schema: 'https://docs.renovatebot.com/renovate-schema.json',\n extends: [\n 'config:recommended',\n ],\n ignorePr"
},
{
"path": ".github/workflows/.java-version",
"chars": 3,
"preview": "25\n"
},
{
"path": ".github/workflows/build.yml",
"chars": 1202,
"preview": "name: CI\n\non: [push, pull_request]\n\njobs:\n build:\n name: 'Test Mode ${{ matrix.kotlin-test-mode }}'\n runs-on: ubu"
},
{
"path": ".github/workflows/release.yml",
"chars": 1392,
"preview": "name: release\n\non:\n push:\n tags:\n - '**'\n\njobs:\n release:\n runs-on: macos-latest\n\n steps:\n - uses: "
},
{
"path": ".gitignore",
"chars": 232,
"preview": ".classpath\n.project\n.settings\neclipsebin\n\nbin\ngen\nbuild\nout\nlib\n\ntarget\npom.xml.*\nrelease.properties\ndependency-reduced-"
},
{
"path": "CHANGELOG.md",
"chars": 31796,
"preview": "# Change Log\n\n## Unreleased\n\n* None yet.\n\n\n## [2.0.0-alpha.1] - 2026-01-28\n\n* Refuse `j$.*` types from Android library d"
},
{
"path": "CONTRIBUTING.md",
"chars": 676,
"preview": "Contributing\n============\n\nIf you would like to contribute code to Moshi you can do so through GitHub by\nforking the rep"
},
{
"path": "LICENSE.txt",
"chars": 11358,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 29762,
"preview": "Moshi\n=====\n\nMoshi is a modern JSON library for Android, Java and Kotlin. It makes it easy to parse JSON into Java and K"
},
{
"path": "build.gradle.kts",
"chars": 5701,
"preview": "import com.diffplug.gradle.spotless.JavaExtension\nimport com.vanniktech.maven.publish.MavenPublishBaseExtension\nimport j"
},
{
"path": "examples/build.gradle.kts",
"chars": 410,
"preview": "import org.jetbrains.kotlin.gradle.tasks.KotlinCompile\n\nplugins {\n kotlin(\"jvm\")\n alias(libs.plugins.ksp)\n}\n\ndependenc"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/ByteStrings.java",
"chars": 1940,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/CardAdapter.java",
"chars": 1499,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/CustomAdapterFactory.java",
"chars": 4000,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/CustomAdapterWithDelegate.java",
"chars": 2194,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/CustomFieldName.java",
"chars": 1229,
"preview": "/*\n * Copyright (C) 2016 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/CustomQualifier.java",
"chars": 2053,
"preview": "/*\n * Copyright (C) 2016 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/CustomTypeAdapter.java",
"chars": 1441,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/DefaultOnDataMismatchAdapter.java",
"chars": 2479,
"preview": "/*\n * Copyright (C) 2017 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/FallbackEnum.java",
"chars": 4241,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/FromJsonWithoutStrings.java",
"chars": 2710,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/IncludeNullsForAnnotatedTypes.java",
"chars": 2518,
"preview": "/*\n * Copyright (C) 2020 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/IncludeNullsForOneType.java",
"chars": 2145,
"preview": "/*\n * Copyright (C) 2020 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/JsonString.kt",
"chars": 2219,
"preview": "/*\n * Copyright (C) 2020 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/MultipleFormats.java",
"chars": 3408,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/ReadAndWriteRfc3339Dates.java",
"chars": 2359,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/ReadJson.java",
"chars": 1708,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/ReadJsonList.java",
"chars": 1750,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/ReadJsonListKt.kt",
"chars": 1287,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/RecoverFromTypeMismatch.java",
"chars": 1419,
"preview": "/*\n * Copyright (C) 2017 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/Unwrap.java",
"chars": 3291,
"preview": "/*\n * Copyright (C) 2017 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/WriteJson.java",
"chars": 1559,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/models/BlackjackHand.java",
"chars": 1037,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/models/Card.java",
"chars": 903,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/models/Player.java",
"chars": 1026,
"preview": "/*\n * Copyright (C) 2016 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/models/Suit.java",
"chars": 787,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/models/Tournament.java",
"chars": 1034,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "examples/src/main/java/com/squareup/moshi/recipes/package-info.java",
"chars": 111,
"preview": "/** Moshi code samples. */\n@javax.annotation.ParametersAreNonnullByDefault\npackage com.squareup.moshi.recipes;\n"
},
{
"path": "gradle/libs.versions.toml",
"chars": 2111,
"preview": "[versions]\nautoService = \"1.1.1\"\njdk = \"21\"\njvmTarget = \"1.8\"\nkotlin = \"2.3.20\"\nkotlinCompileTesting = \"0.12.1\"\nkotlinpo"
},
{
"path": "gradle/wrapper/gradle-wrapper.properties",
"chars": 252,
"preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributi"
},
{
"path": "gradle.properties",
"chars": 143,
"preview": "# Memory for Dokka https://github.com/Kotlin/dokka/issues/1405\norg.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8\n\nVERSI"
},
{
"path": "gradlew",
"chars": 8631,
"preview": "#!/bin/sh\n\n#\n# Copyright © 2015 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\")"
},
{
"path": "gradlew.bat",
"chars": 2896,
"preview": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (th"
},
{
"path": "moshi/build.gradle.kts",
"chars": 1936,
"preview": "import org.gradle.jvm.tasks.Jar\nimport org.jetbrains.kotlin.gradle.dsl.JvmTarget\nimport org.jetbrains.kotlin.gradle.dsl."
},
{
"path": "moshi/gradle.properties",
"chars": 52,
"preview": "kotlin.build.archivesTaskOutputAsFriendModule=false\n"
},
{
"path": "moshi/japicmp/build.gradle.kts",
"chars": 2608,
"preview": "import me.champeau.gradle.japicmp.JapicmpTask\n\nplugins {\n `java-library`\n id(\"me.champeau.gradle.japicmp\")\n}\n\nval base"
},
{
"path": "moshi/records-tests/build.gradle.kts",
"chars": 376,
"preview": "plugins { `java-library` }\n\njava { toolchain { languageVersion.set(JavaLanguageVersion.of(17)) } }\n\ntasks.withType<JavaC"
},
{
"path": "moshi/records-tests/src/test/java/com/squareup/moshi/records/RecordsTest.java",
"chars": 10047,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/-JsonUtf8Reader.kt",
"chars": 36424,
"preview": "/*\n * Copyright (C) 2010 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/-JsonUtf8Writer.kt",
"chars": 11911,
"preview": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/-JsonValueReader.kt",
"chars": 12325,
"preview": "/*\n * Copyright (C) 2017 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/-JsonValueWriter.kt",
"chars": 8878,
"preview": "/*\n * Copyright (C) 2017 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/-MoshiKotlinExtensions.kt",
"chars": 2138,
"preview": "/*\n * Copyright (C) 2019 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/-MoshiKotlinTypesExtensions.kt",
"chars": 3125,
"preview": "/*\n * Copyright (C) 2020 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/FromJson.kt",
"chars": 804,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/Json.kt",
"chars": 1760,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/JsonAdapter.kt",
"chars": 9901,
"preview": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/JsonClass.kt",
"chars": 3395,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/JsonDataException.kt",
"chars": 1605,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/JsonEncodingException.kt",
"chars": 803,
"preview": "/*\n * Copyright (C) 2016 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/JsonQualifier.kt",
"chars": 941,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/JsonReader.kt",
"chars": 23249,
"preview": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/JsonWriter.kt",
"chars": 16577,
"preview": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/Moshi.kt",
"chars": 15089,
"preview": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/ToJson.kt",
"chars": 802,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/Types.kt",
"chars": 11164,
"preview": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/AdapterMethodsFactory.kt",
"chars": 14877,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/ArrayJsonAdapter.kt",
"chars": 3307,
"preview": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/ClassFactory.kt",
"chars": 4861,
"preview": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/ClassJsonAdapter.kt",
"chars": 8015,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/CollectionJsonAdapter.kt",
"chars": 3077,
"preview": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/JsonScope.kt",
"chars": 2931,
"preview": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/JsonValueSource.kt",
"chars": 7045,
"preview": "/*\n * Copyright (C) 2020 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/KotlinReflectTypes.kt",
"chars": 4806,
"preview": "/*\n * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.\n * Use of this source code is g"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/LinkedHashTreeMap.kt",
"chars": 23461,
"preview": "package com.squareup.moshi.internal\n\nimport com.squareup.moshi.internal.LinkedHashTreeMap.Node\nimport java.io.Serializab"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/MapJsonAdapter.kt",
"chars": 2895,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/NonNullJsonAdapter.kt",
"chars": 1405,
"preview": "/*\n * Copyright (C) 2019 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/NullSafeJsonAdapter.kt",
"chars": 1259,
"preview": "/*\n * Copyright (C) 2019 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/RecordJsonAdapter.kt",
"chars": 1327,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/StandardJsonAdapters.kt",
"chars": 11374,
"preview": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/internal/Util.kt",
"chars": 24728,
"preview": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/java/com/squareup/moshi/package-info.java",
"chars": 134,
"preview": "/** Moshi is modern JSON library for Android and Java. */\n@javax.annotation.ParametersAreNonnullByDefault\npackage com.sq"
},
{
"path": "moshi/src/main/java16/com/squareup/moshi/internal/RecordJsonAdapter.kt",
"chars": 5798,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/main/resources/META-INF/proguard/moshi.pro",
"chars": 954,
"preview": "# JSR 305 annotations are for embedding nullability information.\n-dontwarn javax.annotation.**\n\n-keepclasseswithmembers "
},
{
"path": "moshi/src/test/java/android/util/Pair.java",
"chars": 650,
"preview": "/*\n * Copyright (C) 2020 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/AdapterMethodsTest.java",
"chars": 30642,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/CircularAdaptersTest.java",
"chars": 5539,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/DeferredAdapterTest.java",
"chars": 4152,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/FlattenTest.java",
"chars": 8967,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/JsonAdapterTest.java",
"chars": 11136,
"preview": "/*\n * Copyright (C) 2017 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/JsonCodecFactory.java",
"chars": 5898,
"preview": "/*\n * Copyright (C) 2017 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/JsonQualifiersTest.java",
"chars": 14412,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/JsonReaderPathTest.java",
"chars": 7871,
"preview": "/*\n * Copyright (C) 2014 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/JsonReaderTest.java",
"chars": 48867,
"preview": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java",
"chars": 44584,
"preview": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/JsonUtf8WriterTest.java",
"chars": 3828,
"preview": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/JsonValueReaderTest.java",
"chars": 16215,
"preview": "/*\n * Copyright (C) 2017 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/JsonValueWriterTest.java",
"chars": 9518,
"preview": "/*\n * Copyright (C) 2017 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/JsonWriterPathTest.java",
"chars": 8304,
"preview": "/*\n * Copyright (C) 2014 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/JsonWriterTest.java",
"chars": 27121,
"preview": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/KotlinExtensionsTest.kt",
"chars": 2928,
"preview": "/*\n * Copyright (C) 2020 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/MoshiTest.java",
"chars": 54127,
"preview": "/*\n * Copyright (C) 2014 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/MoshiTesting.kt",
"chars": 899,
"preview": "/*\n * Copyright (C) 2025 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/ObjectAdapterTest.java",
"chars": 11027,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/PromoteNameToValueTest.java",
"chars": 13227,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/RecursiveTypesResolveTest.java",
"chars": 2479,
"preview": "/*\n * Copyright (C) 2017 Gson Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/TestUtil.java",
"chars": 1330,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/TypesTest.java",
"chars": 16530,
"preview": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/internal/ClassJsonAdapterTest.java",
"chars": 17647,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/internal/JsonValueSourceTest.java",
"chars": 6149,
"preview": "/*\n * Copyright (C) 2020 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/internal/KotlinReflectTypesTest.kt",
"chars": 6448,
"preview": "/*\n * Copyright (C) 2025 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/internal/LinkedHashTreeMapTest.java",
"chars": 10052,
"preview": "/*\n * Copyright (C) 2012 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi/src/test/java/com/squareup/moshi/internal/MapJsonAdapterTest.java",
"chars": 9194,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-adapters/README.md",
"chars": 1084,
"preview": "Adapters\n===================\n\nPrebuilt Moshi `JsonAdapter`s for various things, such as `Rfc3339DateJsonAdapter` for par"
},
{
"path": "moshi-adapters/build.gradle.kts",
"chars": 388,
"preview": "import org.gradle.jvm.tasks.Jar\n\nplugins {\n kotlin(\"jvm\")\n id(\"com.vanniktech.maven.publish\")\n id(\"org.jetbrains.dokk"
},
{
"path": "moshi-adapters/japicmp/build.gradle.kts",
"chars": 796,
"preview": "import me.champeau.gradle.japicmp.JapicmpTask\n\nplugins {\n `java-library`\n id(\"me.champeau.gradle.japicmp\")\n}\n\nval base"
},
{
"path": "moshi-adapters/src/main/java/com/squareup/moshi/Rfc3339DateJsonAdapter.kt",
"chars": 1402,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-adapters/src/main/java/com/squareup/moshi/adapters/EnumJsonAdapter.kt",
"chars": 3492,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-adapters/src/main/java/com/squareup/moshi/adapters/Iso8601Utils.kt",
"chars": 9710,
"preview": "/*\n * Copyright (C) 2011 FasterXML, LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may"
},
{
"path": "moshi-adapters/src/main/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactory.kt",
"chars": 9453,
"preview": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
},
{
"path": "moshi-adapters/src/main/java/com/squareup/moshi/adapters/Rfc3339DateJsonAdapter.kt",
"chars": 1958,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-adapters/src/test/java/com/squareup/moshi/adapters/EnumJsonAdapterTest.java",
"chars": 2951,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-adapters/src/test/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactoryTest.java",
"chars": 19254,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-adapters/src/test/java/com/squareup/moshi/adapters/Rfc3339DateJsonAdapterTest.java",
"chars": 5223,
"preview": "/*\n * Copyright (C) 2015 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin/build.gradle.kts",
"chars": 435,
"preview": "import org.gradle.jvm.tasks.Jar\n\nplugins {\n kotlin(\"jvm\")\n id(\"com.vanniktech.maven.publish\")\n id(\"org.jetbrains.dokk"
},
{
"path": "moshi-kotlin/src/main/java/com/squareup/moshi/KotlinJsonAdapterFactory.kt",
"chars": 986,
"preview": "/*\n * Copyright (C) 2017 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin/src/main/java/com/squareup/moshi/kotlin/reflect/IndexedParameterMap.kt",
"chars": 941,
"preview": "package com.squareup.moshi.kotlin.reflect\n\n/** A simple [Map] that uses parameter indexes instead of sorting or hashing."
},
{
"path": "moshi-kotlin/src/main/java/com/squareup/moshi/kotlin/reflect/Invokable.kt",
"chars": 2647,
"preview": "package com.squareup.moshi.kotlin.reflect\n\nimport com.squareup.moshi.internal.DEFAULT_CONSTRUCTOR_MARKER\nimport java.lan"
},
{
"path": "moshi-kotlin/src/main/java/com/squareup/moshi/kotlin/reflect/JvmDescriptors.kt",
"chars": 4815,
"preview": "/*\n * Copyright (C) 2025 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin/src/main/java/com/squareup/moshi/kotlin/reflect/JvmSignatureSearcher.kt",
"chars": 2133,
"preview": "package com.squareup.moshi.kotlin.reflect\n\nimport java.lang.reflect.Field\nimport java.lang.reflect.Method\nimport kotlin."
},
{
"path": "moshi-kotlin/src/main/java/com/squareup/moshi/kotlin/reflect/KmExecutable.kt",
"chars": 6872,
"preview": "package com.squareup.moshi.kotlin.reflect\n\nimport java.lang.reflect.Constructor\nimport java.lang.reflect.Method\nimport j"
},
{
"path": "moshi-kotlin/src/main/java/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterFactory.kt",
"chars": 15773,
"preview": "/*\n * Copyright (C) 2017 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin/src/main/java/com/squareup/moshi/kotlin/reflect/KtTypes.kt",
"chars": 6889,
"preview": "/*\n * Copyright (C) 2025 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin/src/main/resources/META-INF/com.android.tools/proguard/moshi-metadata-reflect.pro",
"chars": 816,
"preview": "# When editing this file, update the following files as well:\n# - META-INF/com.android.tools/r8-from-1.6.0/moshi-metadat"
},
{
"path": "moshi-kotlin/src/main/resources/META-INF/com.android.tools/r8-from-1.6.0/moshi-metadata-reflect.pro",
"chars": 661,
"preview": "# When editing this file, update the following files as well:\n# - META-INF/com.android.tools/proguard/moshi-kotlin.pro\n#"
},
{
"path": "moshi-kotlin/src/main/resources/META-INF/com.android.tools/r8-upto-1.6.0/moshi-metadata-reflect.pro",
"chars": 941,
"preview": "# When editing this file, update the following files as well:\n# - META-INF/com.android.tools/proguard/moshi-kotlin.pro\n#"
},
{
"path": "moshi-kotlin/src/test/java/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterTest.kt",
"chars": 1212,
"preview": "/*\n * Copyright (C) 2020 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/build.gradle.kts",
"chars": 1605,
"preview": "import org.jetbrains.kotlin.gradle.tasks.KotlinCompile\n\nplugins {\n kotlin(\"jvm\")\n id(\"com.google.devtools.ksp\")\n id(\""
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/AdapterGenerator.kt",
"chars": 32750,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/DelegateKey.kt",
"chars": 3974,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/InternalMoshiCodegenApi.kt",
"chars": 921,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/Options.kt",
"chars": 2193,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/ProguardRules.kt",
"chars": 4226,
"preview": "/*\n * Copyright (C) 2020 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/PropertyGenerator.kt",
"chars": 2990,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/TargetConstructor.kt",
"chars": 993,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/TargetParameter.kt",
"chars": 1073,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/TargetProperty.kt",
"chars": 1312,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/TargetType.kt",
"chars": 1235,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/TypeRenderer.kt",
"chars": 4259,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/kotlintypes.kt",
"chars": 8796,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/api/typeAliasUnwrapping.kt",
"chars": 2598,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/ksp/AppliedType.kt",
"chars": 2446,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/ksp/JsonClassSymbolProcessorProvider.kt",
"chars": 7294,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/ksp/KspUtil.kt",
"chars": 5026,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/ksp/MoshiApiUtil.kt",
"chars": 3263,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/ksp/TargetTypes.kt",
"chars": 11366,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/main/java/com/squareup/moshi/kotlin/codegen/ksp/shadedUtil.kt",
"chars": 9999,
"preview": "/*\n * Copyright 2020 Google LLC\n * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.\n *"
},
{
"path": "moshi-kotlin-codegen/src/test/java/com/squareup/moshi/kotlin/codegen/JavaSuperclass.java",
"chars": 836,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-codegen/src/test/java/com/squareup/moshi/kotlin/codegen/ksp/JsonClassSymbolProcessorTest.kt",
"chars": 29291,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-tests/build.gradle.kts",
"chars": 1348,
"preview": "import TestMode.KSP\nimport TestMode.REFLECT\nimport org.jetbrains.kotlin.gradle.tasks.KotlinCompile\n\nplugins {\n kotlin(\""
},
{
"path": "moshi-kotlin-tests/codegen-only/build.gradle.kts",
"chars": 1510,
"preview": "import TestMode.KSP\nimport TestMode.REFLECT\nimport org.jetbrains.kotlin.gradle.tasks.KotlinCompile\n\nplugins {\n kotlin(\""
},
{
"path": "moshi-kotlin-tests/codegen-only/src/test/kotlin/com/squareup/moshi/kotlin/codegen/CompileOnlyTests.kt",
"chars": 4649,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-tests/codegen-only/src/test/kotlin/com/squareup/moshi/kotlin/codegen/ComplexGenericsInheritanceTest.kt",
"chars": 4281,
"preview": "/*\n * Copyright (C) 2020 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-tests/codegen-only/src/test/kotlin/com/squareup/moshi/kotlin/codegen/DefaultConstructorTest.kt",
"chars": 2317,
"preview": "/*\n * Copyright (C) 2020 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-tests/codegen-only/src/test/kotlin/com/squareup/moshi/kotlin/codegen/GeneratedAdaptersTest.kt",
"chars": 42319,
"preview": "/*\n * Copyright (C) 2018 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-tests/codegen-only/src/test/kotlin/com/squareup/moshi/kotlin/codegen/GeneratedAdaptersTest_CustomGeneratedClassJsonAdapter.kt",
"chars": 1226,
"preview": "/*\n * Copyright (C) 2019 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-tests/codegen-only/src/test/kotlin/com/squareup/moshi/kotlin/codegen/LooksLikeAClass/ClassInPackageThatLooksLikeAClass.kt",
"chars": 874,
"preview": "/*\n * Copyright (C) 2020 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-tests/codegen-only/src/test/kotlin/com/squareup/moshi/kotlin/codegen/MixingReflectAndCodeGen.kt",
"chars": 1664,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-tests/codegen-only/src/test/kotlin/com/squareup/moshi/kotlin/codegen/MoshiKspTest.kt",
"chars": 1640,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-tests/codegen-only/src/test/kotlin/com/squareup/moshi/kotlin/codegen/MultipleMasksTest.kt",
"chars": 3601,
"preview": "/*\n * Copyright (C) 2019 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-tests/codegen-only/src/test/kotlin/com/squareup/moshi/kotlin/codegen/annotation/UppercaseInAnnotationPackage.kt",
"chars": 1130,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-tests/extra-moshi-test-module/build.gradle.kts",
"chars": 78,
"preview": "plugins { kotlin(\"jvm\") }\n\ndependencies { implementation(project(\":moshi\")) }\n"
},
{
"path": "moshi-kotlin-tests/extra-moshi-test-module/src/main/kotlin/com/squareup/moshi/kotlin/codegen/test/extra/AbstractClassInModuleA.kt",
"chars": 1254,
"preview": "/*\n * Copyright (C) 2021 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-tests/src/test/kotlin/com/squareup/moshi/kotlin/DualKotlinTest.kt",
"chars": 26160,
"preview": "/*\n * Copyright (C) 2020 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "moshi-kotlin-tests/src/test/kotlin/com/squareup/moshi/kotlin/reflect/KotlinJsonAdapterTest.kt",
"chars": 36165,
"preview": "/*\n * Copyright (C) 2017 Square, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
},
{
"path": "releasing.md",
"chars": 1123,
"preview": "# Releasing\n\nCutting a Release\n-----------------\n\n1. Update the `CHANGELOG.md`:\n 1. Change the `Unreleased` header to "
},
{
"path": "settings.gradle.kts",
"chars": 477,
"preview": "pluginManagement {\n repositories {\n mavenCentral()\n gradlePluginPortal()\n }\n}\n\nrootProject.name = \"moshi-root\"\n\n"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the square/moshi GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 183 files (1.2 MB), approximately 299.4k tokens, and a symbol index with 1070 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.