Change the directory structure to match our modules (#1451)

This commit is contained in:
Jesse Wilson
2021-12-08 23:52:51 -05:00
committed by GitHub
parent d5d172c3bb
commit 7578984f25
68 changed files with 24 additions and 265 deletions

View File

@@ -0,0 +1,69 @@
import Build_gradle.TestMode.KAPT
import Build_gradle.TestMode.KSP
import Build_gradle.TestMode.REFLECT
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm")
kotlin("kapt") apply false
id("com.google.devtools.ksp") apply false
}
enum class TestMode {
REFLECT, KAPT, KSP
}
val testMode = findProperty("kotlinTestMode")?.toString()
?.let(TestMode::valueOf)
?: REFLECT
when (testMode) {
REFLECT -> {
// Do nothing!
}
KAPT -> {
apply(plugin = "org.jetbrains.kotlin.kapt")
}
KSP -> {
apply(plugin = "com.google.devtools.ksp")
}
}
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")
}
val useWError = findProperty("kotlinLanguageVersion")?.toString()
?.startsWith("1.5")
?: false
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
allWarningsAsErrors = useWError
@Suppress("SuspiciousCollectionReassignment")
freeCompilerArgs += listOf(
"-Xopt-in=kotlin.ExperimentalStdlibApi"
)
}
}
dependencies {
when (testMode) {
REFLECT -> {
// Do nothing
}
KAPT -> {
"kaptTest"(project(":moshi-kotlin-codegen"))
}
KSP -> {
"kspTest"(project(":moshi-kotlin-codegen"))
}
}
testImplementation(project(":moshi"))
testImplementation(project(":moshi-kotlin"))
testImplementation(project(":moshi-kotlin-tests:extra-moshi-test-module"))
testImplementation(kotlin("reflect"))
testImplementation(libs.junit)
testImplementation(libs.assertj)
testImplementation(libs.truth)
}

View File

@@ -0,0 +1,71 @@
import Build_gradle.TestMode.KAPT
import Build_gradle.TestMode.KSP
import Build_gradle.TestMode.REFLECT
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm")
kotlin("kapt") apply false
id("com.google.devtools.ksp") apply false
}
enum class TestMode {
REFLECT, KAPT, KSP
}
val testMode = findProperty("kotlinTestMode")?.toString()
?.let(TestMode::valueOf)
?: KSP
when (testMode) {
REFLECT -> {
// Default to KSP. This is a CI-only thing
apply(plugin = "com.google.devtools.ksp")
}
KAPT -> {
apply(plugin = "org.jetbrains.kotlin.kapt")
}
KSP -> {
apply(plugin = "com.google.devtools.ksp")
}
}
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")
}
val useWError = findProperty("kotlinLanguageVersion")?.toString()
?.startsWith("1.5")
?: false
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
allWarningsAsErrors = useWError
@Suppress("SuspiciousCollectionReassignment")
freeCompilerArgs += listOf(
"-Xopt-in=kotlin.ExperimentalStdlibApi"
)
}
}
dependencies {
when (testMode) {
REFLECT -> {
// Default to KSP in this case, this is a CI-only thing
"kspTest"(project(":moshi-kotlin-codegen"))
}
KAPT -> {
"kaptTest"(project(":moshi-kotlin-codegen"))
}
KSP -> {
"kspTest"(project(":moshi-kotlin-codegen"))
}
}
testImplementation(project(":moshi"))
testImplementation(project(":moshi-kotlin"))
testImplementation(project(":moshi-kotlin-tests:extra-moshi-test-module"))
testImplementation(kotlin("reflect"))
testImplementation(libs.junit)
testImplementation(libs.assertj)
testImplementation(libs.truth)
}

View File

@@ -0,0 +1,142 @@
/*
* 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.kotlin.codegen
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.squareup.moshi.JsonQualifier
import com.squareup.moshi.kotlin.codegen.test.extra.AbstractClassInModuleA
import kotlin.annotation.AnnotationRetention.RUNTIME
import kotlin.annotation.AnnotationTarget.TYPE
/*
* These are classes that need only compile.
*/
// Regression test for https://github.com/square/moshi/issues/905
@JsonClass(generateAdapter = true)
data class GenericTestClassWithDefaults<T>(
val input: String = "",
val genericInput: T
)
@Target(TYPE)
annotation class TypeAnnotation
/**
* Compilation-only test to ensure we don't render types with their annotations.
* Regression test for https://github.com/square/moshi/issues/1033
*/
@JsonClass(generateAdapter = true)
data class TypeAnnotationClass(
val propertyWithAnnotatedType: @TypeAnnotation String = "",
val generic: List<@TypeAnnotation String>
)
// Regression test for https://github.com/square/moshi/issues/1277
@JsonClass(generateAdapter = true)
data class OtherTestModel(val TestModel: TestModel? = null)
@JsonClass(generateAdapter = true)
data class TestModel(
val someVariable: Int,
val anotherVariable: String
)
// Regression test for https://github.com/square/moshi/issues/1022
@JsonClass(generateAdapter = true)
internal data class MismatchParentAndNestedClassVisibility(
val type: Int,
val name: String? = null
) {
@JsonClass(generateAdapter = true)
data class NestedClass(
val nestedProperty: String
)
}
// Regression test for https://github.com/square/moshi/issues/1052
@JsonClass(generateAdapter = true)
data class KeysWithSpaces(
@Json(name = "1. Information") val information: String,
@Json(name = "2. Symbol") val symbol: String,
@Json(name = "3. Last Refreshed") val lastRefreshed: String,
@Json(name = "4. Interval") val interval: String,
@Json(name = "5. Output Size") val size: String,
@Json(name = "6. Time Zone") val timeZone: String
)
// Regression test for https://github.com/square/moshi/issues/848
@JsonClass(generateAdapter = true)
data class Hotwords(
val `class`: List<String>?
)
/**
* This is here mostly just to ensure it still compiles. Covers variance, @Json, default values,
* nullability, primitive arrays, and some wacky generics.
*/
@JsonClass(generateAdapter = true)
data class SmokeTestType(
@Json(name = "first_name") val firstName: String,
@Json(name = "last_name") val lastName: String,
val age: Int,
val nationalities: List<String> = emptyList(),
val weight: Float,
val tattoos: Boolean = false,
val race: String?,
val hasChildren: Boolean = false,
val favoriteFood: String? = null,
val favoriteDrink: String? = "Water",
val wildcardOut: MutableList<out String> = mutableListOf(),
val nullableWildcardOut: MutableList<out String?> = mutableListOf(),
val wildcardIn: Array<in String>,
val any: List<*>,
val anyTwo: List<Any>,
val anyOut: MutableList<out Any>,
val nullableAnyOut: MutableList<out Any?>,
val favoriteThreeNumbers: IntArray,
val favoriteArrayValues: Array<String>,
val favoriteNullableArrayValues: Array<String?>,
val nullableSetListMapArrayNullableIntWithDefault: Set<List<Map<String, Array<IntArray?>>>>? = null,
val aliasedName: TypeAliasName = "Woah",
val genericAlias: GenericTypeAlias = listOf("Woah"),
// Regression test for https://github.com/square/moshi/issues/1272
val nestedArray: Array<Map<String, Any>>? = null
)
typealias TypeAliasName = String
typealias GenericTypeAlias = List<String>
// Regression test for enum constants in annotations and array types
// https://github.com/ZacSweers/MoshiX/issues/103
@Retention(RUNTIME)
@JsonQualifier
annotation class UpperCase(val foo: Array<Foo>)
enum class Foo { BAR }
@JsonClass(generateAdapter = true)
data class ClassWithQualifier(
@UpperCase(foo = [Foo.BAR])
val a: Int
)
// Regression for https://github.com/ZacSweers/MoshiX/issues/120
@JsonClass(generateAdapter = true)
data class DataClassInModuleB(
val id: String
) : AbstractClassInModuleA()

View File

@@ -0,0 +1,151 @@
/*
* 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.
*/
@file:Suppress("UNUSED", "UNUSED_PARAMETER")
package com.squareup.moshi.kotlin.codegen
import com.google.common.truth.Truth.assertThat
import com.squareup.moshi.JsonClass
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapter
import org.intellij.lang.annotations.Language
import org.junit.Test
class ComplexGenericsInheritanceTest {
private val moshi = Moshi.Builder().build()
@Test
fun simple() {
val adapter = moshi.adapter<PersonResponse>()
@Language("JSON")
val json =
"""{"data":{"name":"foo"},"data2":"bar","data3":"baz"}"""
val instance = adapter.fromJson(json)!!
val testInstance = PersonResponse().apply {
data = Person("foo")
}
assertThat(instance).isEqualTo(testInstance)
assertThat(adapter.toJson(instance)).isEqualTo(json)
}
@Test
fun nested() {
val adapter = moshi.adapter<NestedPersonResponse>()
@Language("JSON")
val json =
"""{"data":{"name":"foo"},"data2":"bar","data3":"baz"}"""
val instance = adapter.fromJson(json)!!
val testInstance = NestedPersonResponse().apply {
data = Person("foo")
}
assertThat(instance).isEqualTo(testInstance)
assertThat(adapter.toJson(instance)).isEqualTo(json)
}
@Test
fun untyped() {
val adapter = moshi.adapter<UntypedNestedPersonResponse<Person>>()
@Language("JSON")
val json =
"""{"data":{"name":"foo"},"data2":"bar","data3":"baz"}"""
val instance = adapter.fromJson(json)!!
val testInstance = UntypedNestedPersonResponse<Person>().apply {
data = Person("foo")
}
assertThat(instance).isEqualTo(testInstance)
assertThat(adapter.toJson(instance)).isEqualTo(json)
}
@Test
fun complex() {
val adapter = moshi.adapter<Layer4<Person, UntypedNestedPersonResponse<Person>>>()
@Language("JSON")
val json =
"""{"layer4E":{"name":"layer4E"},"layer4F":{"data":{"name":"layer4F"},"data2":"layer4F","data3":"layer4F"},"layer3C":[1,2,3],"layer3D":"layer3D","layer2":"layer2","layer1":"layer1"}"""
val instance = adapter.fromJson(json)!!
val testInstance = Layer4(
layer4E = Person("layer4E"),
layer4F = UntypedNestedPersonResponse<Person>().apply {
data = Person("layer4F")
data2 = "layer4F"
data3 = "layer4F"
}
).apply {
layer3C = listOf(1, 2, 3)
layer3D = "layer3D"
layer2 = "layer2"
layer1 = "layer1"
}
assertThat(instance).isEqualTo(testInstance)
assertThat(adapter.toJson(testInstance)).isEqualTo(json)
}
}
open class ResponseWithSettableProperty<T, R> {
var data: T? = null
var data2: R? = null
var data3: R? = null
}
interface Personable
@JsonClass(generateAdapter = true)
data class Person(val name: String) : Personable
@JsonClass(generateAdapter = true)
data class PersonResponse(
val extra: String? = null
) : ResponseWithSettableProperty<Person, String>()
abstract class NestedResponse<T : Personable> : ResponseWithSettableProperty<T, String>()
@JsonClass(generateAdapter = true)
data class NestedPersonResponse(val extra: String? = null) : NestedResponse<Person>()
@JsonClass(generateAdapter = true)
data class UntypedNestedPersonResponse<T : Personable>(
val extra: String? = null
) : NestedResponse<T>()
interface LayerInterface<I>
abstract class Layer1<A> {
var layer1: A? = null
}
abstract class Layer2<B> : Layer1<B>(), LayerInterface<B> {
var layer2: B? = null
}
abstract class Layer3<C, D> : Layer2<D>() {
var layer3C: C? = null
var layer3D: D? = null
}
@JsonClass(generateAdapter = true)
data class Layer4<E : Personable, F>(
val layer4E: E,
val layer4F: F? = null
) : Layer3<List<Int>, String>(), LayerInterface<String>

View File

@@ -0,0 +1,76 @@
/*
* 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.kotlin.codegen
import com.squareup.moshi.JsonClass
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapter
import org.junit.Test
class DefaultConstructorTest {
@Test fun minimal() {
val expected = TestClass("requiredClass")
val json =
"""{"required":"requiredClass"}"""
val instance = Moshi.Builder().build().adapter<TestClass>()
.fromJson(json)!!
check(instance == expected) {
"No match:\nActual : $instance\nExpected: $expected"
}
}
@Test fun allSet() {
val expected = TestClass("requiredClass", "customOptional", 4, "setDynamic", 5, 6)
val json =
"""{"required":"requiredClass","optional":"customOptional","optional2":4,"dynamicSelfReferenceOptional":"setDynamic","dynamicOptional":5,"dynamicInlineOptional":6}"""
val instance = Moshi.Builder().build().adapter<TestClass>()
.fromJson(json)!!
check(instance == expected) {
"No match:\nActual : $instance\nExpected: $expected"
}
}
@Test fun customDynamic() {
val expected = TestClass("requiredClass", "customOptional")
val json =
"""{"required":"requiredClass","optional":"customOptional"}"""
val instance = Moshi.Builder().build().adapter<TestClass>()
.fromJson(json)!!
check(instance == expected) {
"No match:\nActual : $instance\nExpected: $expected"
}
}
}
@JsonClass(generateAdapter = true)
data class TestClass(
val required: String,
val optional: String = "optional",
val optional2: Int = 2,
val dynamicSelfReferenceOptional: String = required,
val dynamicOptional: Int = createInt(),
val dynamicInlineOptional: Int = createInlineInt()
)
private fun createInt(): Int {
return 3
}
@Suppress("NOTHING_TO_INLINE")
private inline fun createInlineInt(): Int {
return 3
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2019 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.kotlin.codegen
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import com.squareup.moshi.kotlin.codegen.GeneratedAdaptersTest.CustomGeneratedClass
// This also tests custom generated types with no moshi constructor
class GeneratedAdaptersTest_CustomGeneratedClassJsonAdapter : JsonAdapter<CustomGeneratedClass>() {
override fun fromJson(reader: JsonReader): CustomGeneratedClass? {
TODO()
}
override fun toJson(writer: JsonWriter, value: CustomGeneratedClass?) {
TODO()
}
}

View File

@@ -0,0 +1,24 @@
/*
* 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.kotlin.codegen.LooksLikeAClass
import com.squareup.moshi.JsonClass
/**
* https://github.com/square/moshi/issues/783
*/
@JsonClass(generateAdapter = true)
data class ClassInPackageThatLooksLikeAClass(val foo: String)

View File

@@ -0,0 +1,48 @@
/*
* 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.kotlin.codegen
import com.google.common.truth.Truth.assertThat
import com.squareup.moshi.JsonClass
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapter
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import org.junit.Test
class MixingReflectAndCodeGen {
@Test
fun mixingReflectionAndCodegen() {
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val generatedAdapter = moshi.adapter<UsesGeneratedAdapter>()
val reflectionAdapter = moshi.adapter<UsesReflectionAdapter>()
assertThat(generatedAdapter.toString())
.isEqualTo("GeneratedJsonAdapter(MixingReflectAndCodeGen.UsesGeneratedAdapter).nullSafe()")
assertThat(reflectionAdapter.toString())
.isEqualTo(
"KotlinJsonAdapter(com.squareup.moshi.kotlin.codegen.MixingReflectAndCodeGen" +
".UsesReflectionAdapter).nullSafe()"
)
}
@JsonClass(generateAdapter = true)
class UsesGeneratedAdapter(var a: Int, var b: Int)
@JsonClass(generateAdapter = false)
class UsesReflectionAdapter(var a: Int, var b: Int)
}

View File

@@ -0,0 +1,49 @@
/*
* 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.kotlin.codegen
import com.google.common.truth.Truth.assertThat
import com.squareup.moshi.JsonClass
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapter
import org.junit.Test
// Regression tests specific to Moshi-KSP
class MoshiKspTest {
private val moshi = Moshi.Builder().build()
// Regression test for https://github.com/ZacSweers/MoshiX/issues/44
@Test
fun onlyInterfaceSupertypes() {
val adapter = moshi.adapter<SimpleImpl>()
//language=JSON
val json = """{"a":"aValue","b":"bValue"}"""
val expected = SimpleImpl("aValue", "bValue")
val instance = adapter.fromJson(json)!!
assertThat(instance).isEqualTo(expected)
val encoded = adapter.toJson(instance)
assertThat(encoded).isEqualTo(json)
}
interface SimpleInterface {
val a: String
}
// NOTE the Any() superclass is important to test that we're detecting the farthest parent class
// correct.y
@JsonClass(generateAdapter = true)
data class SimpleImpl(override val a: String, val b: String) : Any(), SimpleInterface
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2019 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.kotlin.codegen
import com.squareup.moshi.JsonClass
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapter
import org.intellij.lang.annotations.Language
import org.junit.Assert.assertEquals
import org.junit.Test
/**
* This test explicitly tests mask generation for classes with more than 32 parameters. Each mask
* can only indicate up to 32 parameters, so constructors with more than 32 parameters have to use
* multiple masks.
*
* This covers a few cases of this:
* - Ensuring values from json are matched to properties correctly
* - Some `@Transient` parameters (which participate in the constructor signature and mask indices)
* - This example has 3 total masks generated.
*
* Regression test for https://github.com/square/moshi/issues/977
*/
class MultipleMasksTest {
@Test fun testMultipleMasks() {
// Set some arbitrary values to make sure offsets are aligning correctly
@Language("JSON")
val json =
"""{"arg50":500,"arg3":34,"arg11":11,"arg65":67}"""
val instance = Moshi.Builder().build().adapter<MultipleMasks>()
.fromJson(json)!!
assertEquals(instance.arg2, 2)
assertEquals(instance.arg3, 34)
assertEquals(instance.arg11, 11)
assertEquals(instance.arg49, 49)
assertEquals(instance.arg50, 500)
assertEquals(instance.arg65, 67)
assertEquals(instance.arg64, 64)
}
}
@JsonClass(generateAdapter = true)
class MultipleMasks(
val arg0: Long = 0,
val arg1: Long = 1,
val arg2: Long = 2,
val arg3: Long = 3,
val arg4: Long = 4,
val arg5: Long = 5,
val arg6: Long = 6,
val arg7: Long = 7,
val arg8: Long = 8,
val arg9: Long = 9,
val arg10: Long = 10,
val arg11: Long,
val arg12: Long = 12,
val arg13: Long = 13,
val arg14: Long = 14,
val arg15: Long = 15,
val arg16: Long = 16,
val arg17: Long = 17,
val arg18: Long = 18,
val arg19: Long = 19,
@Suppress("UNUSED_PARAMETER") arg20: Long = 20,
val arg21: Long = 21,
val arg22: Long = 22,
val arg23: Long = 23,
val arg24: Long = 24,
val arg25: Long = 25,
val arg26: Long = 26,
val arg27: Long = 27,
val arg28: Long = 28,
val arg29: Long = 29,
val arg30: Long = 30,
val arg31: Long = 31,
val arg32: Long = 32,
val arg33: Long = 33,
val arg34: Long = 34,
val arg35: Long = 35,
val arg36: Long = 36,
val arg37: Long = 37,
val arg38: Long = 38,
@Transient val arg39: Long = 39,
val arg40: Long = 40,
val arg41: Long = 41,
val arg42: Long = 42,
val arg43: Long = 43,
val arg44: Long = 44,
val arg45: Long = 45,
val arg46: Long = 46,
val arg47: Long = 47,
val arg48: Long = 48,
val arg49: Long = 49,
val arg50: Long = 50,
val arg51: Long = 51,
val arg52: Long = 52,
@Transient val arg53: Long = 53,
val arg54: Long = 54,
val arg55: Long = 55,
val arg56: Long = 56,
val arg57: Long = 57,
val arg58: Long = 58,
val arg59: Long = 59,
val arg60: Long = 60,
val arg61: Long = 61,
val arg62: Long = 62,
val arg63: Long = 63,
val arg64: Long = 64,
val arg65: Long = 65
)

View File

@@ -0,0 +1,36 @@
/*
* 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.kotlin.codegen.annotation
import com.squareup.moshi.FromJson
import com.squareup.moshi.JsonQualifier
import com.squareup.moshi.ToJson
import java.util.Locale
@JsonQualifier
annotation class UppercaseInAnnotationPackage
class UppercaseInAnnotationPackageJsonAdapter {
@ToJson
fun toJson(@UppercaseInAnnotationPackage s: String): String {
return s.uppercase(Locale.US)
}
@FromJson
@UppercaseInAnnotationPackage
fun fromJson(s: String): String {
return s.lowercase(Locale.US)
}
}

View File

@@ -0,0 +1,7 @@
plugins {
kotlin("jvm")
}
dependencies {
implementation(project(":moshi"))
}

View File

@@ -0,0 +1,28 @@
/*
* 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.kotlin.codegen.test.extra
import com.squareup.moshi.Json
public abstract class AbstractClassInModuleA {
// Ignored/transient to ensure processor sees them across module boundaries.
@Transient private lateinit var lateinitTransient: String
@Transient private var regularTransient: String = "regularTransient"
// Note that we target the field because otherwise it is stored on the synthetic holder method for
// annotations, which isn't visible from kapt
@field:Json(ignore = true) private lateinit var lateinitIgnored: String
@field:Json(ignore = true) private var regularIgnored: String = "regularIgnored"
}

View File

@@ -0,0 +1,782 @@
/*
* 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.kotlin
import com.google.common.truth.Truth.assertThat
import com.squareup.moshi.FromJson
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.squareup.moshi.JsonDataException
import com.squareup.moshi.Moshi
import com.squareup.moshi.ToJson
import com.squareup.moshi.Types
import com.squareup.moshi.adapter
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import org.intellij.lang.annotations.Language
import org.junit.Assert.fail
import org.junit.Test
import kotlin.annotation.AnnotationRetention.RUNTIME
class DualKotlinTest {
@Suppress("UNCHECKED_CAST")
private val moshi = Moshi.Builder()
// If code gen ran, the generated adapter will be tried first. If it can't find it, it will
// gracefully fall back to the KotlinJsonAdapter. This allows us to easily test both.
.addLast(KotlinJsonAdapterFactory())
.build()
@Test fun requiredValueAbsent() {
val jsonAdapter = moshi.adapter<RequiredValueAbsent>()
try {
//language=JSON
jsonAdapter.fromJson("""{"a":4}""")
fail()
} catch (expected: JsonDataException) {
assertThat(expected).hasMessageThat().isEqualTo("Required value 'b' missing at $")
}
}
@JsonClass(generateAdapter = true)
class RequiredValueAbsent(var a: Int = 3, var b: Int)
@Test fun requiredValueWithDifferentJsonNameAbsent() {
val jsonAdapter = moshi.adapter<RequiredValueWithDifferentJsonNameAbsent>()
try {
//language=JSON
jsonAdapter.fromJson("""{"a":4}""")
fail()
} catch (expected: JsonDataException) {
assertThat(expected).hasMessageThat().isEqualTo("Required value 'b' (JSON name 'bPrime') missing at \$")
}
}
@JsonClass(generateAdapter = true)
class RequiredValueWithDifferentJsonNameAbsent(var a: Int = 3, @Json(name = "bPrime") var b: Int)
@Test fun nonNullPropertySetToNullFailsWithJsonDataException() {
val jsonAdapter = moshi.adapter<HasNonNullProperty>()
try {
//language=JSON
jsonAdapter.fromJson("{\"a\":null}")
fail()
} catch (expected: JsonDataException) {
assertThat(expected).hasMessageThat().isEqualTo("Non-null value 'a' was null at \$.a")
}
}
@Test fun nonNullPropertySetToNullFromAdapterFailsWithJsonDataException() {
val jsonAdapter = moshi.newBuilder()
.add(
object {
@Suppress("UNUSED_PARAMETER")
@FromJson
fun fromJson(string: String): String? = null
}
)
.build()
.adapter<HasNonNullProperty>()
try {
//language=JSON
jsonAdapter.fromJson("{\"a\":\"hello\"}")
fail()
} catch (expected: JsonDataException) {
assertThat(expected).hasMessageThat().isEqualTo("Non-null value 'a' was null at \$.a")
}
}
@JsonClass(generateAdapter = true)
class HasNonNullProperty {
var a: String = ""
}
@Test fun nonNullPropertyWithJsonNameSetToNullFailsWithJsonDataException() {
val jsonAdapter = moshi.adapter<HasNonNullPropertyDifferentJsonName>()
try {
//language=JSON
jsonAdapter.fromJson("{\"aPrime\":null}")
fail()
} catch (expected: JsonDataException) {
assertThat(expected).hasMessageThat().isEqualTo("Non-null value 'a' (JSON name 'aPrime') was null at \$.aPrime")
}
}
@Test fun nonNullPropertyWithJsonNameSetToNullFromAdapterFailsWithJsonDataException() {
val jsonAdapter = moshi.newBuilder()
.add(
object {
@Suppress("UNUSED_PARAMETER")
@FromJson
fun fromJson(string: String): String? = null
}
)
.build()
.adapter<HasNonNullPropertyDifferentJsonName>()
try {
//language=JSON
jsonAdapter.fromJson("{\"aPrime\":\"hello\"}")
fail()
} catch (expected: JsonDataException) {
assertThat(expected).hasMessageThat().isEqualTo("Non-null value 'a' (JSON name 'aPrime') was null at \$.aPrime")
}
}
@JsonClass(generateAdapter = true)
class HasNonNullPropertyDifferentJsonName {
@Json(name = "aPrime") var a: String = ""
}
@Test fun nonNullConstructorParameterCalledWithNullFailsWithJsonDataException() {
val jsonAdapter = moshi.adapter<HasNonNullConstructorParameter>()
try {
//language=JSON
jsonAdapter.fromJson("{\"a\":null}")
fail()
} catch (expected: JsonDataException) {
assertThat(expected).hasMessageThat().isEqualTo("Non-null value 'a' was null at \$.a")
}
}
@Test fun nonNullConstructorParameterCalledWithNullFromAdapterFailsWithJsonDataException() {
val jsonAdapter = moshi.newBuilder()
.add(
object {
@Suppress("UNUSED_PARAMETER")
@FromJson
fun fromJson(string: String): String? = null
}
)
.build()
.adapter<HasNonNullConstructorParameter>()
try {
//language=JSON
jsonAdapter.fromJson("{\"a\":\"hello\"}")
fail()
} catch (expected: JsonDataException) {
assertThat(expected).hasMessageThat().isEqualTo("Non-null value 'a' was null at \$.a")
}
}
@Retention(RUNTIME)
annotation class Nullable
@JsonClass(generateAdapter = true)
data class HasNonNullConstructorParameter(val a: String)
@JsonClass(generateAdapter = true)
data class HasNullableConstructorParameter(val a: String?)
@Test fun delegatesToInstalledAdaptersBeforeNullChecking() {
val localMoshi = moshi.newBuilder()
.add(
object {
@FromJson
fun fromJson(@Nullable string: String?): String {
return string ?: "fallback"
}
@ToJson
fun toJson(@Nullable value: String?): String {
return value ?: "fallback"
}
}
)
.build()
val hasNonNullConstructorParameterAdapter =
localMoshi.adapter<HasNonNullConstructorParameter>()
assertThat(
//language=JSON
hasNonNullConstructorParameterAdapter
.fromJson("{\"a\":null}")
).isEqualTo(HasNonNullConstructorParameter("fallback"))
val hasNullableConstructorParameterAdapter =
localMoshi.adapter<HasNullableConstructorParameter>()
assertThat(
//language=JSON
hasNullableConstructorParameterAdapter
.fromJson("{\"a\":null}")
).isEqualTo(HasNullableConstructorParameter("fallback"))
//language=JSON
assertThat(
hasNullableConstructorParameterAdapter
.toJson(HasNullableConstructorParameter(null))
).isEqualTo("{\"a\":\"fallback\"}")
}
@JsonClass(generateAdapter = true)
data class HasNullableTypeWithGeneratedAdapter(val a: HasNonNullConstructorParameter?)
@Test fun delegatesToInstalledAdaptersBeforeNullCheckingWithGeneratedAdapter() {
val adapter = moshi.adapter<HasNullableTypeWithGeneratedAdapter>()
val encoded = HasNullableTypeWithGeneratedAdapter(null)
//language=JSON
assertThat(adapter.toJson(encoded)).isEqualTo("""{}""")
//language=JSON
assertThat(adapter.serializeNulls().toJson(encoded)).isEqualTo("""{"a":null}""")
//language=JSON
val decoded = adapter.fromJson("""{"a":null}""")!!
assertThat(decoded.a).isEqualTo(null)
}
@Test fun valueClass() {
val adapter = moshi.adapter<ValueClass>()
val inline = ValueClass(5)
val expectedJson =
"""{"i":5}"""
assertThat(adapter.toJson(inline)).isEqualTo(expectedJson)
val testJson =
"""{"i":6}"""
val result = adapter.fromJson(testJson)!!
assertThat(result.i).isEqualTo(6)
// TODO doesn't work yet. https://github.com/square/moshi/issues/1170
// need to invoke the constructor_impl$default static method, invoke constructor with result
// val testEmptyJson =
// """{}"""
// val result2 = adapter.fromJson(testEmptyJson)!!
// assertThat(result2.i).isEqualTo(0)
}
@JsonClass(generateAdapter = true)
data class InlineConsumer(val inline: ValueClass)
@Test fun inlineClassConsumer() {
val adapter = moshi.adapter<InlineConsumer>()
val consumer = InlineConsumer(ValueClass(23))
@Language("JSON")
val expectedJson =
"""{"inline":{"i":23}}"""
assertThat(adapter.toJson(consumer)).isEqualTo(expectedJson)
@Language("JSON")
val testJson =
"""{"inline":{"i":42}}"""
val result = adapter.fromJson(testJson)!!
assertThat(result.inline.i).isEqualTo(42)
}
// Regression test for https://github.com/square/moshi/issues/955
@Test fun backwardReferencingTypeVars() {
val adapter = moshi.adapter<TextAssetMetaData>()
@Language("JSON")
val testJson =
"""{"text":"text"}"""
assertThat(adapter.toJson(TextAssetMetaData("text"))).isEqualTo(testJson)
val result = adapter.fromJson(testJson)!!
assertThat(result.text).isEqualTo("text")
}
@JsonClass(generateAdapter = true)
class TextAssetMetaData(val text: String) : AssetMetaData<TextAsset>()
class TextAsset : Asset<TextAsset>()
abstract class Asset<A : Asset<A>>
abstract class AssetMetaData<A : Asset<A>>
// Regression test for https://github.com/ZacSweers/MoshiX/issues/125
@Test fun selfReferencingTypeVars() {
val adapter = moshi.adapter<StringNodeNumberNode>()
val data = StringNodeNumberNode().also {
it.t = StringNodeNumberNode().also {
it.text = "child 1"
}
it.text = "root"
it.r = NumberStringNode().also {
it.number = 0
it.t = NumberStringNode().also {
it.number = 1
}
it.r = StringNodeNumberNode().also {
it.text = "grand child 1"
}
}
}
assertThat(adapter.toJson(data))
//language=JSON
.isEqualTo(
"""
{"text":"root","r":{"number":0,"r":{"text":"grand child 1"},"t":{"number":1}},"t":{"text":"child 1"}}
""".trimIndent()
)
}
@JsonClass(generateAdapter = true)
open class Node<T : Node<T, R>, R : Node<R, T>> {
// kotlin-reflect doesn't preserve ordering, so put these in alphabetical order so that
// both reflective and code gen tests work the same
var r: R? = null
var t: T? = null
}
@JsonClass(generateAdapter = true)
class StringNodeNumberNode : Node<StringNodeNumberNode, NumberStringNode>() {
var text: String = ""
}
@JsonClass(generateAdapter = true)
class NumberStringNode : Node<NumberStringNode, StringNodeNumberNode>() {
var number: Int = 0
}
// Regression test for https://github.com/square/moshi/issues/968
@Test fun abstractSuperProperties() {
val adapter = moshi.adapter<InternalAbstractProperty>()
@Language("JSON")
val testJson =
"""{"test":"text"}"""
assertThat(adapter.toJson(InternalAbstractProperty("text"))).isEqualTo(testJson)
val result = adapter.fromJson(testJson)!!
assertThat(result.test).isEqualTo("text")
}
abstract class InternalAbstractPropertyBase {
internal abstract val test: String
// Regression for https://github.com/square/moshi/issues/974
abstract fun abstractFun(): String
}
@JsonClass(generateAdapter = true)
class InternalAbstractProperty(override val test: String) : InternalAbstractPropertyBase() {
override fun abstractFun(): String {
return test
}
}
// Regression test for https://github.com/square/moshi/issues/975
@Test fun multipleConstructors() {
val adapter = moshi.adapter<MultipleConstructorsB>()
//language=JSON
assertThat(adapter.toJson(MultipleConstructorsB(6))).isEqualTo("""{"f":{"f":6},"b":6}""")
@Language("JSON")
val testJson =
"""{"b":6}"""
val result = adapter.fromJson(testJson)!!
assertThat(result.b).isEqualTo(6)
}
@JsonClass(generateAdapter = true)
class MultipleConstructorsA(val f: Int)
@JsonClass(generateAdapter = true)
class MultipleConstructorsB(val f: MultipleConstructorsA = MultipleConstructorsA(5), val b: Int) {
constructor(f: Int, b: Int = 6) : this(MultipleConstructorsA(f), b)
}
@Test fun `multiple non-property parameters`() {
val adapter = moshi.adapter<MultipleNonPropertyParameters>()
@Language("JSON")
val testJson =
"""{"prop":7}"""
assertThat(adapter.toJson(MultipleNonPropertyParameters(7))).isEqualTo(testJson)
val result = adapter.fromJson(testJson)!!
assertThat(result.prop).isEqualTo(7)
}
@JsonClass(generateAdapter = true)
class MultipleNonPropertyParameters(
val prop: Int,
param1: Int = 1,
param2: Int = 2
) {
init {
// Ensure the params always uses their default value
require(param1 == 1)
require(param2 == 2)
}
}
// Tests the case of multiple parameters with no parameter properties.
@Test fun `only multiple non-property parameters`() {
val adapter = moshi.adapter<OnlyMultipleNonPropertyParameters>()
@Language("JSON")
val testJson =
"""{"prop":7}"""
assertThat(adapter.toJson(OnlyMultipleNonPropertyParameters().apply { prop = 7 }))
.isEqualTo(testJson)
val result = adapter.fromJson(testJson)!!
assertThat(result.prop).isEqualTo(7)
}
@JsonClass(generateAdapter = true)
class OnlyMultipleNonPropertyParameters(
param1: Int = 1,
param2: Int = 2
) {
init {
// Ensure the params always uses their default value
require(param1 == 1)
require(param2 == 2)
}
var prop: Int = 0
}
@Test fun typeAliasUnwrapping() {
val adapter = moshi
.newBuilder()
.add(Types.supertypeOf(Int::class.javaObjectType), moshi.adapter<Int>())
.build()
.adapter<TypeAliasUnwrapping>()
@Language("JSON")
val testJson =
"""{"simpleClass":6,"parameterized":{"value":6},"wildcardIn":{"value":6},"wildcardOut":{"value":6},"complex":{"value":[{"value":6}]}}"""
val testValue = TypeAliasUnwrapping(
simpleClass = 6,
parameterized = GenericClass(6),
wildcardIn = GenericClass(6),
wildcardOut = GenericClass(6),
complex = GenericClass(listOf(GenericClass(6)))
)
assertThat(adapter.toJson(testValue)).isEqualTo(testJson)
val result = adapter.fromJson(testJson)!!
assertThat(result).isEqualTo(testValue)
}
@JsonClass(generateAdapter = true)
data class TypeAliasUnwrapping(
val simpleClass: TypeAlias,
val parameterized: GenericClass<TypeAlias>,
val wildcardIn: GenericClass<in TypeAlias>,
val wildcardOut: GenericClass<out TypeAlias>,
val complex: GenericClass<GenericTypeAlias>?
)
// Regression test for https://github.com/square/moshi/issues/991
@Test fun nullablePrimitiveProperties() {
val adapter = moshi.adapter<NullablePrimitives>()
@Language("JSON")
val testJson =
"""{"objectType":"value","boolean":true,"byte":3,"char":"a","short":3,"int":3,"long":3,"float":3.2,"double":3.2}"""
val instance = NullablePrimitives(
objectType = "value",
boolean = true,
byte = 3,
char = 'a',
short = 3,
int = 3,
long = 3,
float = 3.2f,
double = 3.2
)
assertThat(adapter.toJson(instance))
.isEqualTo(testJson)
val result = adapter.fromJson(testJson)!!
assertThat(result).isEqualTo(instance)
}
@JsonClass(generateAdapter = true)
data class NullablePrimitives(
val objectType: String = "",
val boolean: Boolean,
val nullableBoolean: Boolean? = null,
val byte: Byte,
val nullableByte: Byte? = null,
val char: Char,
val nullableChar: Char? = null,
val short: Short,
val nullableShort: Short? = null,
val int: Int,
val nullableInt: Int? = null,
val long: Long,
val nullableLong: Long? = null,
val float: Float,
val nullableFloat: Float? = null,
val double: Double,
val nullableDouble: Double? = null
)
// Regression test for https://github.com/square/moshi/issues/990
@Test fun nullableProperties() {
val adapter = moshi.adapter<NullableList>()
@Language("JSON")
val testJson =
"""{"nullableList":null}"""
assertThat(adapter.serializeNulls().toJson(NullableList(null)))
.isEqualTo(testJson)
val result = adapter.fromJson(testJson)!!
assertThat(result.nullableList).isNull()
}
@JsonClass(generateAdapter = true)
data class NullableList(val nullableList: List<Any>?)
@Test fun typeAliasNullability() {
val adapter = moshi.adapter<TypeAliasNullability>()
@Language("JSON")
val testJson =
"""{"aShouldBeNonNull":3,"nullableAShouldBeNullable":null,"redundantNullableAShouldBeNullable":null,"manuallyNullableAShouldBeNullable":null,"convolutedMultiNullableShouldBeNullable":null,"deepNestedNullableShouldBeNullable":null}"""
val instance = TypeAliasNullability(3, null, null, null, null, null)
assertThat(adapter.serializeNulls().toJson(instance))
.isEqualTo(testJson)
val result = adapter.fromJson(testJson)!!
assertThat(result).isEqualTo(instance)
}
@Suppress("REDUNDANT_NULLABLE")
@JsonClass(generateAdapter = true)
data class TypeAliasNullability(
val aShouldBeNonNull: A,
val nullableAShouldBeNullable: NullableA,
val redundantNullableAShouldBeNullable: NullableA?,
val manuallyNullableAShouldBeNullable: A?,
val convolutedMultiNullableShouldBeNullable: NullableB?,
val deepNestedNullableShouldBeNullable: E
)
// Regression test for https://github.com/square/moshi/issues/1009
@Test fun outDeclaration() {
val adapter = moshi.adapter<OutDeclaration<Int>>()
@Language("JSON")
val testJson =
"""{"input":3}"""
val instance = OutDeclaration(3)
assertThat(adapter.serializeNulls().toJson(instance))
.isEqualTo(testJson)
val result = adapter.fromJson(testJson)!!
assertThat(result).isEqualTo(instance)
}
@JsonClass(generateAdapter = true)
data class OutDeclaration<out T>(val input: T)
@Test fun intersectionTypes() {
val adapter = moshi.adapter<IntersectionTypes<IntersectionTypesEnum>>()
@Language("JSON")
val testJson =
"""{"value":"VALUE"}"""
val instance = IntersectionTypes(IntersectionTypesEnum.VALUE)
assertThat(adapter.serializeNulls().toJson(instance))
.isEqualTo(testJson)
val result = adapter.fromJson(testJson)!!
assertThat(result).isEqualTo(instance)
}
interface IntersectionTypeInterface<E : Enum<E>>
enum class IntersectionTypesEnum : IntersectionTypeInterface<IntersectionTypesEnum> {
VALUE
}
@JsonClass(generateAdapter = true)
data class IntersectionTypes<E>(
val value: E
) where E : Enum<E>, E : IntersectionTypeInterface<E>
@Test fun transientConstructorParameter() {
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
val jsonAdapter = moshi.adapter<TransientConstructorParameter>()
val encoded = TransientConstructorParameter(3, 5)
assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"b":5}""")
val decoded = jsonAdapter.fromJson("""{"a":4,"b":6}""")!!
assertThat(decoded.a).isEqualTo(-1)
assertThat(decoded.b).isEqualTo(6)
}
class TransientConstructorParameter(@Transient var a: Int = -1, var b: Int = -1)
@Test fun multipleTransientConstructorParameters() {
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
val jsonAdapter = moshi.adapter(MultipleTransientConstructorParameters::class.java)
val encoded = MultipleTransientConstructorParameters(3, 5, 7)
assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"b":5}""")
val decoded = jsonAdapter.fromJson("""{"a":4,"b":6}""")!!
assertThat(decoded.a).isEqualTo(-1)
assertThat(decoded.b).isEqualTo(6)
assertThat(decoded.c).isEqualTo(-1)
}
class MultipleTransientConstructorParameters(@Transient var a: Int = -1, var b: Int = -1, @Transient var c: Int = -1)
@Test fun transientProperty() {
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
val jsonAdapter = moshi.adapter<TransientProperty>()
val encoded = TransientProperty()
encoded.a = 3
encoded.setB(4)
encoded.c = 5
assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"c":5}""")
val decoded = jsonAdapter.fromJson("""{"a":4,"b":5,"c":6}""")!!
assertThat(decoded.a).isEqualTo(-1)
assertThat(decoded.getB()).isEqualTo(-1)
assertThat(decoded.c).isEqualTo(6)
}
class TransientProperty {
@Transient var a: Int = -1
@Transient private var b: Int = -1
var c: Int = -1
fun getB() = b
fun setB(b: Int) {
this.b = b
}
}
@Test fun ignoredConstructorParameter() {
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
val jsonAdapter = moshi.adapter<IgnoredConstructorParameter>()
val encoded = IgnoredConstructorParameter(3, 5)
assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"b":5}""")
val decoded = jsonAdapter.fromJson("""{"a":4,"b":6}""")!!
assertThat(decoded.a).isEqualTo(-1)
assertThat(decoded.b).isEqualTo(6)
}
class IgnoredConstructorParameter(@Json(ignore = true) var a: Int = -1, var b: Int = -1)
@Test fun multipleIgnoredConstructorParameters() {
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
val jsonAdapter = moshi.adapter(MultipleIgnoredConstructorParameters::class.java)
val encoded = MultipleIgnoredConstructorParameters(3, 5, 7)
assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"b":5}""")
val decoded = jsonAdapter.fromJson("""{"a":4,"b":6}""")!!
assertThat(decoded.a).isEqualTo(-1)
assertThat(decoded.b).isEqualTo(6)
assertThat(decoded.c).isEqualTo(-1)
}
class MultipleIgnoredConstructorParameters(
@Json(ignore = true) var a: Int = -1,
var b: Int = -1,
@Json(ignore = true) var c: Int = -1
)
@Test fun ignoredProperty() {
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
val jsonAdapter = moshi.adapter<IgnoredProperty>()
val encoded = IgnoredProperty()
encoded.a = 3
encoded.setB(4)
encoded.c = 5
assertThat(jsonAdapter.toJson(encoded)).isEqualTo("""{"c":5}""")
val decoded = jsonAdapter.fromJson("""{"a":4,"b":5,"c":6}""")!!
assertThat(decoded.a).isEqualTo(-1)
assertThat(decoded.getB()).isEqualTo(-1)
assertThat(decoded.c).isEqualTo(6)
}
class IgnoredProperty {
@Json(ignore = true) var a: Int = -1
@Json(ignore = true) private var b: Int = -1
var c: Int = -1
fun getB() = b
fun setB(b: Int) {
this.b = b
}
}
@Test fun propertyNameHasDollarSign() {
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
val jsonAdapter = moshi.adapter<PropertyWithDollarSign>()
val value = PropertyWithDollarSign("apple", "banana")
val json = """{"${'$'}a":"apple","${'$'}b":"banana"}"""
assertThat(jsonAdapter.toJson(value)).isEqualTo(json)
assertThat(jsonAdapter.fromJson(json)).isEqualTo(value)
}
@JsonClass(generateAdapter = true)
data class PropertyWithDollarSign(
val `$a`: String,
@Json(name = "\$b") val b: String
)
}
typealias TypeAlias = Int
@Suppress("REDUNDANT_PROJECTION")
typealias GenericTypeAlias = List<out GenericClass<in TypeAlias>?>?
@JsonClass(generateAdapter = true)
data class GenericClass<T>(val value: T)
// Has to be outside since value classes are only allowed on top level
@JvmInline
@JsonClass(generateAdapter = true)
value class ValueClass(val i: Int = 0)
typealias A = Int
typealias NullableA = A?
typealias B = NullableA
typealias NullableB = B?
typealias C = NullableA
typealias D = C
typealias E = D