mirror of
https://github.com/fankes/moshi.git
synced 2025-10-20 00:19:21 +08:00
Use JsonAdapter.nonNull() in generated adapters.
Also extract a type for the delegate key. Also fix the generator to reject inner classes, abstract classes, and local classes.
This commit is contained in:
@@ -81,11 +81,11 @@ internal class AdapterGenerator(
|
|||||||
.joinToString(", ") { "\"$it\"" }})", JsonReader.Options::class.asTypeName())
|
.joinToString(", ") { "\"$it\"" }})", JsonReader.Options::class.asTypeName())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val delegateAdapters = propertyList.distinctBy { it.delegateKey() }
|
val delegateAdapters = propertyList.distinctBy { it.delegateKey }
|
||||||
|
|
||||||
fun generateFile(generatedOption: TypeElement?): FileSpec {
|
fun generateFile(generatedOption: TypeElement?): FileSpec {
|
||||||
for (property in delegateAdapters) {
|
for (property in delegateAdapters) {
|
||||||
property.reserveDelegateNames(nameAllocator)
|
property.delegateKey.reserveName(nameAllocator)
|
||||||
}
|
}
|
||||||
for (property in propertyList) {
|
for (property in propertyList) {
|
||||||
property.allocateNames(nameAllocator)
|
property.allocateNames(nameAllocator)
|
||||||
@@ -125,7 +125,7 @@ internal class AdapterGenerator(
|
|||||||
|
|
||||||
result.addProperty(optionsProperty)
|
result.addProperty(optionsProperty)
|
||||||
for (uniqueAdapter in delegateAdapters) {
|
for (uniqueAdapter in delegateAdapters) {
|
||||||
result.addProperty(uniqueAdapter.generateDelegateProperty(this))
|
result.addProperty(uniqueAdapter.delegateKey.generateProperty(nameAllocator, this))
|
||||||
}
|
}
|
||||||
|
|
||||||
result.addFunction(generateToStringFun())
|
result.addFunction(generateToStringFun())
|
||||||
@@ -178,12 +178,12 @@ internal class AdapterGenerator(
|
|||||||
if (property.differentiateAbsentFromNull) {
|
if (property.differentiateAbsentFromNull) {
|
||||||
result.beginControlFlow("%L -> ", index)
|
result.beginControlFlow("%L -> ", index)
|
||||||
result.addStatement("%N = %N.fromJson(%N)",
|
result.addStatement("%N = %N.fromJson(%N)",
|
||||||
property.localName, property.delegateName, readerParam)
|
property.localName, nameAllocator.get(property.delegateKey), readerParam)
|
||||||
result.addStatement("%N = true", property.localIsPresentName)
|
result.addStatement("%N = true", property.localIsPresentName)
|
||||||
result.endControlFlow()
|
result.endControlFlow()
|
||||||
} else {
|
} else {
|
||||||
result.addStatement("%L -> %N = %N.fromJson(%N)",
|
result.addStatement("%L -> %N = %N.fromJson(%N)",
|
||||||
index, property.localName, property.delegateName, readerParam)
|
index, property.localName, nameAllocator.get(property.delegateKey), readerParam)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,7 +281,7 @@ internal class AdapterGenerator(
|
|||||||
propertyList.forEach { property ->
|
propertyList.forEach { property ->
|
||||||
result.addStatement("%N.name(%S)", writerParam, property.serializedName)
|
result.addStatement("%N.name(%S)", writerParam, property.serializedName)
|
||||||
result.addStatement("%N.toJson(%N, %N.%L)",
|
result.addStatement("%N.toJson(%N, %N.%L)",
|
||||||
property.delegateName, writerParam, valueParam, property.name)
|
nameAllocator.get(property.delegateKey), writerParam, valueParam, property.name)
|
||||||
}
|
}
|
||||||
result.addStatement("%N.endObject()", writerParam)
|
result.addStatement("%N.endObject()", writerParam)
|
||||||
|
|
||||||
|
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package com.squareup.moshi
|
||||||
|
|
||||||
|
import com.squareup.kotlinpoet.ClassName
|
||||||
|
import com.squareup.kotlinpoet.CodeBlock
|
||||||
|
import com.squareup.kotlinpoet.KModifier
|
||||||
|
import com.squareup.kotlinpoet.NameAllocator
|
||||||
|
import com.squareup.kotlinpoet.ParameterizedTypeName
|
||||||
|
import com.squareup.kotlinpoet.PropertySpec
|
||||||
|
import com.squareup.kotlinpoet.TypeName
|
||||||
|
import com.squareup.kotlinpoet.TypeVariableName
|
||||||
|
import com.squareup.kotlinpoet.WildcardTypeName
|
||||||
|
import com.squareup.kotlinpoet.asTypeName
|
||||||
|
import javax.lang.model.element.AnnotationMirror
|
||||||
|
|
||||||
|
/** A JsonAdapter that can be used to encode and decode a particular field. */
|
||||||
|
internal data class DelegateKey(
|
||||||
|
val type: TypeName,
|
||||||
|
val jsonQualifiers: Set<AnnotationMirror>
|
||||||
|
) {
|
||||||
|
val nullable
|
||||||
|
get() = type.nullable || type is TypeVariableName
|
||||||
|
|
||||||
|
fun reserveName(nameAllocator: NameAllocator) {
|
||||||
|
val qualifierNames = jsonQualifiers.joinToString("") {
|
||||||
|
"At${it.annotationType.asElement().simpleName}"
|
||||||
|
}
|
||||||
|
nameAllocator.newName("${type.toVariableName().decapitalize()}${qualifierNames}Adapter", this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns an adapter to use when encoding and decoding this property. */
|
||||||
|
fun generateProperty(nameAllocator: NameAllocator, enclosing: AdapterGenerator): PropertySpec {
|
||||||
|
val adapterTypeName = ParameterizedTypeName.get(
|
||||||
|
JsonAdapter::class.asTypeName(), type)
|
||||||
|
val qualifiers = jsonQualifiers
|
||||||
|
val standardArgs = arrayOf(enclosing.moshiParam,
|
||||||
|
if (type is ClassName && qualifiers.isEmpty()) {
|
||||||
|
""
|
||||||
|
} else {
|
||||||
|
CodeBlock.of("<%T>", type)
|
||||||
|
},
|
||||||
|
type.makeType(
|
||||||
|
enclosing.elements, enclosing.typesParam, enclosing.genericTypeNames ?: emptyList()))
|
||||||
|
val standardArgsSize = standardArgs.size + 1
|
||||||
|
val (initializerString, args) = when {
|
||||||
|
qualifiers.isEmpty() -> "" to emptyArray()
|
||||||
|
qualifiers.size == 1 -> {
|
||||||
|
", %${standardArgsSize}T::class.java" to arrayOf(
|
||||||
|
qualifiers.first().annotationType.asTypeName())
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val initString = qualifiers
|
||||||
|
.mapIndexed { index, _ ->
|
||||||
|
val annoClassIndex = standardArgsSize + index
|
||||||
|
return@mapIndexed "%${annoClassIndex}T::class.java"
|
||||||
|
}
|
||||||
|
.joinToString()
|
||||||
|
val initArgs = qualifiers
|
||||||
|
.map { it.annotationType.asTypeName() }
|
||||||
|
.toTypedArray()
|
||||||
|
", $initString" to initArgs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val finalArgs = arrayOf(*standardArgs, *args)
|
||||||
|
|
||||||
|
val nullModifier = if (nullable) ".nullSafe()" else ".nonNull()"
|
||||||
|
|
||||||
|
return PropertySpec.builder(nameAllocator.get(this), adapterTypeName, KModifier.PRIVATE)
|
||||||
|
.initializer("%1N.adapter%2L(%3L$initializerString)$nullModifier", *finalArgs)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a suggested variable name derived from a list of type names. This just concatenates,
|
||||||
|
* yielding types like MapOfStringLong.
|
||||||
|
*/
|
||||||
|
private fun List<TypeName>.toVariableNames(): String {
|
||||||
|
return joinToString("") { it.toVariableName() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a suggested variable name derived from a type name, like nullableListOfString. */
|
||||||
|
private fun TypeName.toVariableName(): String {
|
||||||
|
val base = when (this) {
|
||||||
|
is ClassName -> simpleName()
|
||||||
|
is ParameterizedTypeName -> rawType.simpleName() + "Of" + typeArguments.toVariableNames()
|
||||||
|
is WildcardTypeName -> (lowerBounds + upperBounds).toVariableNames()
|
||||||
|
is TypeVariableName -> name + bounds.toVariableNames()
|
||||||
|
else -> throw IllegalArgumentException("Unrecognized type! $this")
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (nullable) {
|
||||||
|
"Nullable$base"
|
||||||
|
} else {
|
||||||
|
base
|
||||||
|
}
|
||||||
|
}
|
@@ -29,14 +29,18 @@ import me.eugeniomarletti.kotlin.metadata.classKind
|
|||||||
import me.eugeniomarletti.kotlin.metadata.declaresDefaultValue
|
import me.eugeniomarletti.kotlin.metadata.declaresDefaultValue
|
||||||
import me.eugeniomarletti.kotlin.metadata.getPropertyOrNull
|
import me.eugeniomarletti.kotlin.metadata.getPropertyOrNull
|
||||||
import me.eugeniomarletti.kotlin.metadata.isDataClass
|
import me.eugeniomarletti.kotlin.metadata.isDataClass
|
||||||
|
import me.eugeniomarletti.kotlin.metadata.isInnerClass
|
||||||
import me.eugeniomarletti.kotlin.metadata.isPrimary
|
import me.eugeniomarletti.kotlin.metadata.isPrimary
|
||||||
import me.eugeniomarletti.kotlin.metadata.jvm.getJvmConstructorSignature
|
import me.eugeniomarletti.kotlin.metadata.jvm.getJvmConstructorSignature
|
||||||
import me.eugeniomarletti.kotlin.metadata.kotlinMetadata
|
import me.eugeniomarletti.kotlin.metadata.kotlinMetadata
|
||||||
|
import me.eugeniomarletti.kotlin.metadata.modality
|
||||||
import me.eugeniomarletti.kotlin.metadata.visibility
|
import me.eugeniomarletti.kotlin.metadata.visibility
|
||||||
import me.eugeniomarletti.kotlin.processing.KotlinAbstractProcessor
|
import me.eugeniomarletti.kotlin.processing.KotlinAbstractProcessor
|
||||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
import org.jetbrains.kotlin.serialization.ProtoBuf.Class
|
||||||
|
import org.jetbrains.kotlin.serialization.ProtoBuf.Modality
|
||||||
import org.jetbrains.kotlin.serialization.ProtoBuf.Property
|
import org.jetbrains.kotlin.serialization.ProtoBuf.Property
|
||||||
import org.jetbrains.kotlin.serialization.ProtoBuf.ValueParameter
|
import org.jetbrains.kotlin.serialization.ProtoBuf.ValueParameter
|
||||||
|
import org.jetbrains.kotlin.serialization.ProtoBuf.Visibility
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.annotation.processing.ProcessingEnvironment
|
import javax.annotation.processing.ProcessingEnvironment
|
||||||
import javax.annotation.processing.Processor
|
import javax.annotation.processing.Processor
|
||||||
@@ -118,16 +122,35 @@ class JsonClassCodeGenProcessor : KotlinAbstractProcessor(), KotlinMetadataUtils
|
|||||||
val metadata = element.kotlinMetadata
|
val metadata = element.kotlinMetadata
|
||||||
|
|
||||||
if (metadata !is KotlinClassMetadata) {
|
if (metadata !is KotlinClassMetadata) {
|
||||||
errorMustBeKotlinClass(element)
|
messager.printMessage(
|
||||||
|
ERROR, "@JsonClass can't be applied to $element: must be a Kotlin class", element)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val classData = metadata.data
|
val classData = metadata.data
|
||||||
val (nameResolver, classProto) = classData
|
val (nameResolver, classProto) = classData
|
||||||
|
|
||||||
if (classProto.classKind != ProtoBuf.Class.Kind.CLASS) {
|
when {
|
||||||
errorMustBeKotlinClass(element)
|
classProto.classKind != Class.Kind.CLASS -> {
|
||||||
return null
|
messager.printMessage(
|
||||||
|
ERROR, "@JsonClass can't be applied to $element: must be a Kotlin class", element)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
classProto.isInnerClass -> {
|
||||||
|
messager.printMessage(
|
||||||
|
ERROR, "@JsonClass can't be applied to $element: must not be an inner class", element)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
classProto.modality == Modality.ABSTRACT -> {
|
||||||
|
messager.printMessage(
|
||||||
|
ERROR, "@JsonClass can't be applied to $element: must not be abstract", element)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
classProto.visibility == Visibility.LOCAL -> {
|
||||||
|
messager.printMessage(
|
||||||
|
ERROR, "@JsonClass can't be applied to $element: must not be local", element)
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val typeName = element.asType().asTypeName()
|
val typeName = element.asType().asTypeName()
|
||||||
@@ -187,9 +210,9 @@ class JsonClassCodeGenProcessor : KotlinAbstractProcessor(), KotlinMetadataUtils
|
|||||||
|
|
||||||
val annotatedElement = annotatedElements[property]
|
val annotatedElement = annotatedElements[property]
|
||||||
|
|
||||||
if (property.visibility != ProtoBuf.Visibility.INTERNAL
|
if (property.visibility != Visibility.INTERNAL
|
||||||
&& property.visibility != ProtoBuf.Visibility.PROTECTED
|
&& property.visibility != Visibility.PROTECTED
|
||||||
&& property.visibility != ProtoBuf.Visibility.PUBLIC) {
|
&& property.visibility != Visibility.PUBLIC) {
|
||||||
messager.printMessage(ERROR, "property $name is not visible", enclosedElement)
|
messager.printMessage(ERROR, "property $name is not visible", enclosedElement)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -203,15 +226,17 @@ class JsonClassCodeGenProcessor : KotlinAbstractProcessor(), KotlinMetadataUtils
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val delegateKey = DelegateKey(
|
||||||
|
property.returnType.asTypeName(nameResolver, classProto::getTypeParameter, true),
|
||||||
|
jsonQualifiers(enclosedElement, annotatedElement, parameterElement))
|
||||||
|
|
||||||
propertyGenerators += PropertyGenerator(
|
propertyGenerators += PropertyGenerator(
|
||||||
|
delegateKey,
|
||||||
name,
|
name,
|
||||||
jsonName(name, enclosedElement, annotatedElement, parameterElement),
|
jsonName(name, enclosedElement, annotatedElement, parameterElement),
|
||||||
parameter != null,
|
parameter != null,
|
||||||
hasDefault,
|
hasDefault,
|
||||||
property.returnType.nullable,
|
property.returnType.asTypeName(nameResolver, classProto::getTypeParameter))
|
||||||
property.returnType.asTypeName(nameResolver, classProto::getTypeParameter),
|
|
||||||
property.returnType.asTypeName(nameResolver, classProto::getTypeParameter, true),
|
|
||||||
jsonQualifiers(enclosedElement, annotatedElement, parameterElement))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort properties so that those with constructor parameters come first.
|
// Sort properties so that those with constructor parameters come first.
|
||||||
|
@@ -16,97 +16,32 @@
|
|||||||
package com.squareup.moshi
|
package com.squareup.moshi
|
||||||
|
|
||||||
import com.squareup.kotlinpoet.BOOLEAN
|
import com.squareup.kotlinpoet.BOOLEAN
|
||||||
import com.squareup.kotlinpoet.ClassName
|
|
||||||
import com.squareup.kotlinpoet.CodeBlock
|
|
||||||
import com.squareup.kotlinpoet.KModifier
|
|
||||||
import com.squareup.kotlinpoet.NameAllocator
|
import com.squareup.kotlinpoet.NameAllocator
|
||||||
import com.squareup.kotlinpoet.ParameterizedTypeName
|
|
||||||
import com.squareup.kotlinpoet.PropertySpec
|
import com.squareup.kotlinpoet.PropertySpec
|
||||||
import com.squareup.kotlinpoet.TypeName
|
import com.squareup.kotlinpoet.TypeName
|
||||||
import com.squareup.kotlinpoet.TypeVariableName
|
|
||||||
import com.squareup.kotlinpoet.WildcardTypeName
|
|
||||||
import com.squareup.kotlinpoet.asTypeName
|
|
||||||
import javax.lang.model.element.AnnotationMirror
|
|
||||||
|
|
||||||
/** Generates functions to encode and decode a property as JSON. */
|
/** Generates functions to encode and decode a property as JSON. */
|
||||||
internal class PropertyGenerator(
|
internal class PropertyGenerator(
|
||||||
|
val delegateKey: DelegateKey,
|
||||||
val name: String,
|
val name: String,
|
||||||
val serializedName: String,
|
val serializedName: String,
|
||||||
val hasConstructorParameter: Boolean,
|
val hasConstructorParameter: Boolean,
|
||||||
val hasDefault: Boolean,
|
val hasDefault: Boolean,
|
||||||
val nullable: Boolean,
|
val typeName: TypeName
|
||||||
val typeName: TypeName,
|
|
||||||
val unaliasedName: TypeName,
|
|
||||||
val jsonQualifiers: Set<AnnotationMirror>
|
|
||||||
) {
|
) {
|
||||||
lateinit var delegateName: String
|
|
||||||
lateinit var localName: String
|
lateinit var localName: String
|
||||||
lateinit var localIsPresentName: String
|
lateinit var localIsPresentName: String
|
||||||
|
|
||||||
val isRequired
|
val isRequired
|
||||||
get() = !nullable && !hasDefault
|
get() = !delegateKey.nullable && !hasDefault
|
||||||
|
|
||||||
/** We prefer to use 'null' to mean absent, but for some properties those are distinct. */
|
/** We prefer to use 'null' to mean absent, but for some properties those are distinct. */
|
||||||
val differentiateAbsentFromNull
|
val differentiateAbsentFromNull
|
||||||
get() = hasDefault && nullable
|
get() = delegateKey.nullable && hasDefault
|
||||||
|
|
||||||
fun reserveDelegateNames(nameAllocator: NameAllocator) {
|
|
||||||
val qualifierNames = jsonQualifiers.joinToString("") {
|
|
||||||
"At${it.annotationType.asElement().simpleName.toString().capitalize()}"
|
|
||||||
}
|
|
||||||
nameAllocator.newName("${unaliasedName.toVariableName()}${qualifierNames}Adapter",
|
|
||||||
delegateKey())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun allocateNames(nameAllocator: NameAllocator) {
|
fun allocateNames(nameAllocator: NameAllocator) {
|
||||||
localName = nameAllocator.newName(name)
|
localName = nameAllocator.newName(name)
|
||||||
localIsPresentName = nameAllocator.newName("${name}Set")
|
localIsPresentName = nameAllocator.newName("${name}Set")
|
||||||
delegateName = nameAllocator.get(delegateKey())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a key that matches keys of properties that can share an adapter. */
|
|
||||||
fun delegateKey() = unaliasedName to jsonQualifiers
|
|
||||||
|
|
||||||
/** Returns an adapter to use when encoding and decoding this property. */
|
|
||||||
fun generateDelegateProperty(enclosing: AdapterGenerator): PropertySpec {
|
|
||||||
val adapterTypeName = ParameterizedTypeName.get(
|
|
||||||
JsonAdapter::class.asTypeName(), unaliasedName)
|
|
||||||
val qualifiers = jsonQualifiers.toList()
|
|
||||||
val standardArgs = arrayOf(enclosing.moshiParam,
|
|
||||||
if (unaliasedName is ClassName && qualifiers.isEmpty()) {
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
CodeBlock.of("<%T>", unaliasedName)
|
|
||||||
},
|
|
||||||
unaliasedName.makeType(
|
|
||||||
enclosing.elements, enclosing.typesParam, enclosing.genericTypeNames ?: emptyList()))
|
|
||||||
val standardArgsSize = standardArgs.size + 1
|
|
||||||
val (initializerString, args) = when {
|
|
||||||
qualifiers.isEmpty() -> "" to emptyArray()
|
|
||||||
qualifiers.size == 1 -> {
|
|
||||||
", %${standardArgsSize}T::class.java" to arrayOf(
|
|
||||||
qualifiers.first().annotationType.asTypeName())
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
val initString = qualifiers
|
|
||||||
.mapIndexed { index, _ ->
|
|
||||||
val annoClassIndex = standardArgsSize + index
|
|
||||||
return@mapIndexed "%${annoClassIndex}T::class.java"
|
|
||||||
}
|
|
||||||
.joinToString()
|
|
||||||
val initArgs = qualifiers
|
|
||||||
.map { it.annotationType.asTypeName() }
|
|
||||||
.toTypedArray()
|
|
||||||
", $initString" to initArgs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val finalArgs = arrayOf(*standardArgs, *args)
|
|
||||||
|
|
||||||
return PropertySpec.builder(delegateName, adapterTypeName,
|
|
||||||
KModifier.PRIVATE)
|
|
||||||
.initializer("%1N.adapter%2L(%3L$initializerString)${if (nullable) ".nullSafe()" else ""}",
|
|
||||||
*finalArgs)
|
|
||||||
.build()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateLocalProperty(): PropertySpec {
|
fun generateLocalProperty(): PropertySpec {
|
||||||
@@ -123,25 +58,3 @@ internal class PropertyGenerator(
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a suggested variable name derived from a list of type names.
|
|
||||||
*/
|
|
||||||
private fun List<TypeName>.toVariableNames(): String {
|
|
||||||
return joinToString("_") { it.toVariableName() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a suggested variable name derived from a type name.
|
|
||||||
*/
|
|
||||||
private fun TypeName.toVariableName(): String {
|
|
||||||
return when (this) {
|
|
||||||
is ClassName -> simpleName().decapitalize()
|
|
||||||
is ParameterizedTypeName -> {
|
|
||||||
rawType.simpleName().decapitalize() + if (typeArguments.isEmpty()) "" else "__" + typeArguments.toVariableNames()
|
|
||||||
}
|
|
||||||
is WildcardTypeName -> "wildcard__" + (lowerBounds + upperBounds).toVariableNames()
|
|
||||||
is TypeVariableName -> name.decapitalize() + if (bounds.isEmpty()) "" else "__" + bounds.toVariableNames()
|
|
||||||
else -> throw IllegalArgumentException("Unrecognized type! $this")
|
|
||||||
}.let { if (nullable) "${it}_nullable" else it }
|
|
||||||
}
|
|
||||||
|
@@ -17,6 +17,7 @@ package com.squareup.moshi
|
|||||||
|
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||||
|
import org.junit.Ignore
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.rules.TemporaryFolder
|
import org.junit.rules.TemporaryFolder
|
||||||
@@ -26,8 +27,7 @@ import javax.annotation.processing.Processor
|
|||||||
class CompilerTest {
|
class CompilerTest {
|
||||||
@Rule @JvmField var temporaryFolder: TemporaryFolder = TemporaryFolder()
|
@Rule @JvmField var temporaryFolder: TemporaryFolder = TemporaryFolder()
|
||||||
|
|
||||||
@Test
|
@Test fun privateProperty() {
|
||||||
fun test() {
|
|
||||||
val call = KotlinCompilerCall(temporaryFolder.root)
|
val call = KotlinCompilerCall(temporaryFolder.root)
|
||||||
call.inheritClasspath = true
|
call.inheritClasspath = true
|
||||||
call.addService(Processor::class, JsonClassCodeGenProcessor::class)
|
call.addService(Processor::class, JsonClassCodeGenProcessor::class)
|
||||||
@@ -42,4 +42,116 @@ class CompilerTest {
|
|||||||
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
|
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
|
||||||
assertThat(result.systemErr).contains("property a is not visible")
|
assertThat(result.systemErr).contains("property a is not visible")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun interfacesNotSupported() {
|
||||||
|
val call = KotlinCompilerCall(temporaryFolder.root)
|
||||||
|
call.inheritClasspath = true
|
||||||
|
call.addService(Processor::class, JsonClassCodeGenProcessor::class)
|
||||||
|
call.addKt("source.kt", """
|
||||||
|
|import com.squareup.moshi.JsonClass
|
||||||
|
|
|
||||||
|
|@JsonClass(generateAdapter = true)
|
||||||
|
|interface Interface
|
||||||
|
|""".trimMargin())
|
||||||
|
|
||||||
|
val result = call.execute()
|
||||||
|
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
|
||||||
|
assertThat(result.systemErr).contains(
|
||||||
|
"error: @JsonClass can't be applied to Interface: must be a Kotlin class")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun abstractClassesNotSupported() {
|
||||||
|
val call = KotlinCompilerCall(temporaryFolder.root)
|
||||||
|
call.inheritClasspath = true
|
||||||
|
call.addService(Processor::class, JsonClassCodeGenProcessor::class)
|
||||||
|
call.addKt("source.kt", """
|
||||||
|
|import com.squareup.moshi.JsonClass
|
||||||
|
|
|
||||||
|
|@JsonClass(generateAdapter = true)
|
||||||
|
|abstract class AbstractClass(val a: Int)
|
||||||
|
|""".trimMargin())
|
||||||
|
|
||||||
|
val result = call.execute()
|
||||||
|
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
|
||||||
|
assertThat(result.systemErr).contains(
|
||||||
|
"error: @JsonClass can't be applied to AbstractClass: must not be abstract")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun innerClassesNotSupported() {
|
||||||
|
val call = KotlinCompilerCall(temporaryFolder.root)
|
||||||
|
call.inheritClasspath = true
|
||||||
|
call.addService(Processor::class, JsonClassCodeGenProcessor::class)
|
||||||
|
call.addKt("source.kt", """
|
||||||
|
|import com.squareup.moshi.JsonClass
|
||||||
|
|
|
||||||
|
|class Outer {
|
||||||
|
| @JsonClass(generateAdapter = true)
|
||||||
|
| inner class InnerClass(val a: Int)
|
||||||
|
|}
|
||||||
|
|""".trimMargin())
|
||||||
|
|
||||||
|
val result = call.execute()
|
||||||
|
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
|
||||||
|
assertThat(result.systemErr).contains(
|
||||||
|
"error: @JsonClass can't be applied to Outer.InnerClass: must not be an inner class")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Annotation processors don't get called for local classes, so we don't have the opportunity to
|
||||||
|
// print an error message. Instead local classes will fail at runtime.
|
||||||
|
@Ignore
|
||||||
|
@Test fun localClassesNotSupported() {
|
||||||
|
val call = KotlinCompilerCall(temporaryFolder.root)
|
||||||
|
call.inheritClasspath = true
|
||||||
|
call.addService(Processor::class, JsonClassCodeGenProcessor::class)
|
||||||
|
call.addKt("source.kt", """
|
||||||
|
|import com.squareup.moshi.JsonClass
|
||||||
|
|
|
||||||
|
|fun outer() {
|
||||||
|
| @JsonClass(generateAdapter = true)
|
||||||
|
| class LocalClass(val a: Int)
|
||||||
|
|}
|
||||||
|
|""".trimMargin())
|
||||||
|
|
||||||
|
val result = call.execute()
|
||||||
|
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
|
||||||
|
assertThat(result.systemErr).contains(
|
||||||
|
"error: @JsonClass can't be applied to LocalClass: must not be local")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun objectDeclarationsNotSupported() {
|
||||||
|
val call = KotlinCompilerCall(temporaryFolder.root)
|
||||||
|
call.inheritClasspath = true
|
||||||
|
call.addService(Processor::class, JsonClassCodeGenProcessor::class)
|
||||||
|
call.addKt("source.kt", """
|
||||||
|
|import com.squareup.moshi.JsonClass
|
||||||
|
|
|
||||||
|
|@JsonClass(generateAdapter = true)
|
||||||
|
|object ObjectDeclaration {
|
||||||
|
| var a = 5
|
||||||
|
|}
|
||||||
|
|""".trimMargin())
|
||||||
|
val result = call.execute()
|
||||||
|
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
|
||||||
|
assertThat(result.systemErr).contains(
|
||||||
|
"error: @JsonClass can't be applied to ObjectDeclaration: must be a Kotlin class")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun objectExpressionsNotSupported() {
|
||||||
|
val call = KotlinCompilerCall(temporaryFolder.root)
|
||||||
|
call.inheritClasspath = true
|
||||||
|
call.addService(Processor::class, JsonClassCodeGenProcessor::class)
|
||||||
|
call.addKt("source.kt", """
|
||||||
|
|import com.squareup.moshi.JsonClass
|
||||||
|
|
|
||||||
|
|@JsonClass(generateAdapter = true)
|
||||||
|
|val expression = object : Any() {
|
||||||
|
| var a = 5
|
||||||
|
|}
|
||||||
|
|""".trimMargin())
|
||||||
|
|
||||||
|
val result = call.execute()
|
||||||
|
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
|
||||||
|
assertThat(result.systemErr).contains(
|
||||||
|
"error: @JsonClass can't be applied to expression\$annotations(): must be a Kotlin class")
|
||||||
|
}
|
||||||
}
|
}
|
@@ -378,7 +378,7 @@ class GeneratedAdaptersTest {
|
|||||||
jsonAdapter.fromJson("{\"a\":null}")
|
jsonAdapter.fromJson("{\"a\":null}")
|
||||||
fail()
|
fail()
|
||||||
} catch (expected: JsonDataException) {
|
} catch (expected: JsonDataException) {
|
||||||
assertThat(expected).hasMessage("Required property 'a' missing at \$")
|
assertThat(expected).hasMessage("Unexpected null at \$.a")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,6 +526,106 @@ class GeneratedAdaptersTest {
|
|||||||
var b: Int = -1
|
var b: Int = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun nonNullPropertySetToNullFailsWithJsonDataException() {
|
||||||
|
val moshi = Moshi.Builder().build()
|
||||||
|
val jsonAdapter = moshi.adapter(HasNonNullProperty::class.java)
|
||||||
|
|
||||||
|
try {
|
||||||
|
jsonAdapter.fromJson("{\"a\":null}")
|
||||||
|
fail()
|
||||||
|
} catch (expected: JsonDataException) {
|
||||||
|
assertThat(expected).hasMessage("Unexpected null at \$.a")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
class HasNonNullProperty {
|
||||||
|
var a: String = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun manyProperties32() {
|
||||||
|
val moshi = Moshi.Builder().build()
|
||||||
|
val jsonAdapter = moshi.adapter(ManyProperties32::class.java)
|
||||||
|
|
||||||
|
val encoded = ManyProperties32(
|
||||||
|
101, 102, 103, 104, 105,
|
||||||
|
106, 107, 108, 109, 110,
|
||||||
|
111, 112, 113, 114, 115,
|
||||||
|
116, 117, 118, 119, 120,
|
||||||
|
121, 122, 123, 124, 125,
|
||||||
|
126, 127, 128, 129, 130,
|
||||||
|
131, 132)
|
||||||
|
val json = ("""
|
||||||
|
|{
|
||||||
|
|"v01":101,"v02":102,"v03":103,"v04":104,"v05":105,
|
||||||
|
|"v06":106,"v07":107,"v08":108,"v09":109,"v10":110,
|
||||||
|
|"v11":111,"v12":112,"v13":113,"v14":114,"v15":115,
|
||||||
|
|"v16":116,"v17":117,"v18":118,"v19":119,"v20":120,
|
||||||
|
|"v21":121,"v22":122,"v23":123,"v24":124,"v25":125,
|
||||||
|
|"v26":126,"v27":127,"v28":128,"v29":129,"v30":130,
|
||||||
|
|"v31":131,"v32":132
|
||||||
|
|}
|
||||||
|
|""").trimMargin().replace("\n", "")
|
||||||
|
|
||||||
|
assertThat(jsonAdapter.toJson(encoded)).isEqualTo(json)
|
||||||
|
|
||||||
|
val decoded = jsonAdapter.fromJson(json)!!
|
||||||
|
assertThat(decoded.v01).isEqualTo(101)
|
||||||
|
assertThat(decoded.v32).isEqualTo(132)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
class ManyProperties32(
|
||||||
|
var v01: Int, var v02: Int, var v03: Int, var v04: Int, var v05: Int,
|
||||||
|
var v06: Int, var v07: Int, var v08: Int, var v09: Int, var v10: Int,
|
||||||
|
var v11: Int, var v12: Int, var v13: Int, var v14: Int, var v15: Int,
|
||||||
|
var v16: Int, var v17: Int, var v18: Int, var v19: Int, var v20: Int,
|
||||||
|
var v21: Int, var v22: Int, var v23: Int, var v24: Int, var v25: Int,
|
||||||
|
var v26: Int, var v27: Int, var v28: Int, var v29: Int, var v30: Int,
|
||||||
|
var v31: Int, var v32: Int)
|
||||||
|
|
||||||
|
@Test fun manyProperties33() {
|
||||||
|
val moshi = Moshi.Builder().build()
|
||||||
|
val jsonAdapter = moshi.adapter(ManyProperties33::class.java)
|
||||||
|
|
||||||
|
val encoded = ManyProperties33(
|
||||||
|
101, 102, 103, 104, 105,
|
||||||
|
106, 107, 108, 109, 110,
|
||||||
|
111, 112, 113, 114, 115,
|
||||||
|
116, 117, 118, 119, 120,
|
||||||
|
121, 122, 123, 124, 125,
|
||||||
|
126, 127, 128, 129, 130,
|
||||||
|
131, 132, 133)
|
||||||
|
val json = ("""
|
||||||
|
|{
|
||||||
|
|"v01":101,"v02":102,"v03":103,"v04":104,"v05":105,
|
||||||
|
|"v06":106,"v07":107,"v08":108,"v09":109,"v10":110,
|
||||||
|
|"v11":111,"v12":112,"v13":113,"v14":114,"v15":115,
|
||||||
|
|"v16":116,"v17":117,"v18":118,"v19":119,"v20":120,
|
||||||
|
|"v21":121,"v22":122,"v23":123,"v24":124,"v25":125,
|
||||||
|
|"v26":126,"v27":127,"v28":128,"v29":129,"v30":130,
|
||||||
|
|"v31":131,"v32":132,"v33":133
|
||||||
|
|}
|
||||||
|
|""").trimMargin().replace("\n", "")
|
||||||
|
|
||||||
|
assertThat(jsonAdapter.toJson(encoded)).isEqualTo(json)
|
||||||
|
|
||||||
|
val decoded = jsonAdapter.fromJson(json)!!
|
||||||
|
assertThat(decoded.v01).isEqualTo(101)
|
||||||
|
assertThat(decoded.v32).isEqualTo(132)
|
||||||
|
assertThat(decoded.v33).isEqualTo(133)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
class ManyProperties33(
|
||||||
|
var v01: Int, var v02: Int, var v03: Int, var v04: Int, var v05: Int,
|
||||||
|
var v06: Int, var v07: Int, var v08: Int, var v09: Int, var v10: Int,
|
||||||
|
var v11: Int, var v12: Int, var v13: Int, var v14: Int, var v15: Int,
|
||||||
|
var v16: Int, var v17: Int, var v18: Int, var v19: Int, var v20: Int,
|
||||||
|
var v21: Int, var v22: Int, var v23: Int, var v24: Int, var v25: Int,
|
||||||
|
var v26: Int, var v27: Int, var v28: Int, var v29: Int, var v30: Int,
|
||||||
|
var v31: Int, var v32: Int, var v33: Int)
|
||||||
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
@JsonQualifier
|
@JsonQualifier
|
||||||
annotation class Uppercase
|
annotation class Uppercase
|
||||||
|
@@ -39,22 +39,6 @@ class KotlinCodeGenTest {
|
|||||||
|
|
||||||
class DuplicateValue(var a: Int = -1, var b: Int = -2)
|
class DuplicateValue(var a: Int = -1, var b: Int = -2)
|
||||||
|
|
||||||
@Ignore @Test fun nonNullPropertySetToNullFailsWithJsonDataException() {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
val jsonAdapter = moshi.adapter(HasNonNullProperty::class.java)
|
|
||||||
|
|
||||||
try {
|
|
||||||
jsonAdapter.fromJson("{\"a\":null}")
|
|
||||||
fail()
|
|
||||||
} catch (expected: JsonDataException) {
|
|
||||||
assertThat(expected).hasMessage("Non-null value a was null at \$")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class HasNonNullProperty {
|
|
||||||
var a: String = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore @Test fun repeatedValue() {
|
@Ignore @Test fun repeatedValue() {
|
||||||
val moshi = Moshi.Builder().build()
|
val moshi = Moshi.Builder().build()
|
||||||
val jsonAdapter = moshi.adapter(RepeatedValue::class.java)
|
val jsonAdapter = moshi.adapter(RepeatedValue::class.java)
|
||||||
@@ -323,167 +307,6 @@ class KotlinCodeGenTest {
|
|||||||
A, B
|
A, B
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test fun interfacesNotSupported() {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
try {
|
|
||||||
moshi.adapter(Interface::class.java)
|
|
||||||
fail()
|
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
assertThat(e).hasMessage("No JsonAdapter for interface " +
|
|
||||||
"com.squareup.moshi.KotlinJsonAdapterTest\$Interface (with no annotations)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Interface
|
|
||||||
|
|
||||||
@Ignore @Test fun abstractClassesNotSupported() {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
try {
|
|
||||||
moshi.adapter(AbstractClass::class.java)
|
|
||||||
fail()
|
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
assertThat(e).hasMessage(
|
|
||||||
"Cannot serialize abstract class com.squareup.moshi.KotlinJsonAdapterTest\$AbstractClass")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class AbstractClass(val a: Int)
|
|
||||||
|
|
||||||
@Ignore @Test fun innerClassesNotSupported() {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
try {
|
|
||||||
moshi.adapter(InnerClass::class.java)
|
|
||||||
fail()
|
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
assertThat(e).hasMessage(
|
|
||||||
"Cannot serialize non-static nested class com.squareup.moshi.KotlinCodeGenTest\$InnerClass")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class InnerClass(val a: Int)
|
|
||||||
|
|
||||||
@Ignore @Test fun localClassesNotSupported() {
|
|
||||||
class LocalClass(val a: Int)
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
try {
|
|
||||||
moshi.adapter(LocalClass::class.java)
|
|
||||||
fail()
|
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
assertThat(e).hasMessage("Cannot serialize local class or object expression " +
|
|
||||||
"com.squareup.moshi.KotlinJsonAdapterTest\$localClassesNotSupported\$LocalClass")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore @Test fun objectDeclarationsNotSupported() {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
try {
|
|
||||||
moshi.adapter(ObjectDeclaration.javaClass)
|
|
||||||
fail()
|
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
assertThat(e).hasMessage("Cannot serialize object declaration " +
|
|
||||||
"com.squareup.moshi.KotlinJsonAdapterTest\$ObjectDeclaration")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object ObjectDeclaration {
|
|
||||||
var a = 5
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore @Test fun objectExpressionsNotSupported() {
|
|
||||||
val expression = object : Any() {
|
|
||||||
var a = 5
|
|
||||||
}
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
try {
|
|
||||||
moshi.adapter(expression.javaClass)
|
|
||||||
fail()
|
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
assertThat(e).hasMessage("Cannot serialize local class or object expression " +
|
|
||||||
"com.squareup.moshi.KotlinJsonAdapterTest\$objectExpressionsNotSupported\$expression$1")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore @Test fun manyProperties32() {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
val jsonAdapter = moshi.adapter(ManyProperties32::class.java)
|
|
||||||
|
|
||||||
val encoded = ManyProperties32(
|
|
||||||
101, 102, 103, 104, 105,
|
|
||||||
106, 107, 108, 109, 110,
|
|
||||||
111, 112, 113, 114, 115,
|
|
||||||
116, 117, 118, 119, 120,
|
|
||||||
121, 122, 123, 124, 125,
|
|
||||||
126, 127, 128, 129, 130,
|
|
||||||
131, 132)
|
|
||||||
val json = ("""
|
|
||||||
|{
|
|
||||||
|"v01":101,"v02":102,"v03":103,"v04":104,"v05":105,
|
|
||||||
|"v06":106,"v07":107,"v08":108,"v09":109,"v10":110,
|
|
||||||
|"v11":111,"v12":112,"v13":113,"v14":114,"v15":115,
|
|
||||||
|"v16":116,"v17":117,"v18":118,"v19":119,"v20":120,
|
|
||||||
|"v21":121,"v22":122,"v23":123,"v24":124,"v25":125,
|
|
||||||
|"v26":126,"v27":127,"v28":128,"v29":129,"v30":130,
|
|
||||||
|"v31":131,"v32":132
|
|
||||||
|}
|
|
||||||
|""").trimMargin().replace("\n", "")
|
|
||||||
|
|
||||||
assertThat(jsonAdapter.toJson(encoded)).isEqualTo(json)
|
|
||||||
|
|
||||||
val decoded = jsonAdapter.fromJson(json)!!
|
|
||||||
assertThat(decoded.v01).isEqualTo(101)
|
|
||||||
assertThat(decoded.v32).isEqualTo(132)
|
|
||||||
}
|
|
||||||
|
|
||||||
class ManyProperties32(
|
|
||||||
var v01: Int, var v02: Int, var v03: Int, var v04: Int, var v05: Int,
|
|
||||||
var v06: Int, var v07: Int, var v08: Int, var v09: Int, var v10: Int,
|
|
||||||
var v11: Int, var v12: Int, var v13: Int, var v14: Int, var v15: Int,
|
|
||||||
var v16: Int, var v17: Int, var v18: Int, var v19: Int, var v20: Int,
|
|
||||||
var v21: Int, var v22: Int, var v23: Int, var v24: Int, var v25: Int,
|
|
||||||
var v26: Int, var v27: Int, var v28: Int, var v29: Int, var v30: Int,
|
|
||||||
var v31: Int, var v32: Int)
|
|
||||||
|
|
||||||
@Ignore @Test fun manyProperties33() {
|
|
||||||
val moshi = Moshi.Builder().build()
|
|
||||||
val jsonAdapter = moshi.adapter(ManyProperties33::class.java)
|
|
||||||
|
|
||||||
val encoded = ManyProperties33(
|
|
||||||
101, 102, 103, 104, 105,
|
|
||||||
106, 107, 108, 109, 110,
|
|
||||||
111, 112, 113, 114, 115,
|
|
||||||
116, 117, 118, 119, 120,
|
|
||||||
121, 122, 123, 124, 125,
|
|
||||||
126, 127, 128, 129, 130,
|
|
||||||
131, 132, 133)
|
|
||||||
val json = ("""
|
|
||||||
|{
|
|
||||||
|"v01":101,"v02":102,"v03":103,"v04":104,"v05":105,
|
|
||||||
|"v06":106,"v07":107,"v08":108,"v09":109,"v10":110,
|
|
||||||
|"v11":111,"v12":112,"v13":113,"v14":114,"v15":115,
|
|
||||||
|"v16":116,"v17":117,"v18":118,"v19":119,"v20":120,
|
|
||||||
|"v21":121,"v22":122,"v23":123,"v24":124,"v25":125,
|
|
||||||
|"v26":126,"v27":127,"v28":128,"v29":129,"v30":130,
|
|
||||||
|"v31":131,"v32":132,"v33":133
|
|
||||||
|}
|
|
||||||
|""").trimMargin().replace("\n", "")
|
|
||||||
|
|
||||||
assertThat(jsonAdapter.toJson(encoded)).isEqualTo(json)
|
|
||||||
|
|
||||||
val decoded = jsonAdapter.fromJson(json)!!
|
|
||||||
assertThat(decoded.v01).isEqualTo(101)
|
|
||||||
assertThat(decoded.v32).isEqualTo(132)
|
|
||||||
assertThat(decoded.v33).isEqualTo(133)
|
|
||||||
}
|
|
||||||
|
|
||||||
class ManyProperties33(
|
|
||||||
var v01: Int, var v02: Int, var v03: Int, var v04: Int, var v05: Int,
|
|
||||||
var v06: Int, var v07: Int, var v08: Int, var v09: Int, var v10: Int,
|
|
||||||
var v11: Int, var v12: Int, var v13: Int, var v14: Int, var v15: Int,
|
|
||||||
var v16: Int, var v17: Int, var v18: Int, var v19: Int, var v20: Int,
|
|
||||||
var v21: Int, var v22: Int, var v23: Int, var v24: Int, var v25: Int,
|
|
||||||
var v26: Int, var v27: Int, var v28: Int, var v29: Int, var v30: Int,
|
|
||||||
var v31: Int, var v32: Int, var v33: Int)
|
|
||||||
|
|
||||||
// TODO(jwilson): resolve generic types?
|
// TODO(jwilson): resolve generic types?
|
||||||
|
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
|
Reference in New Issue
Block a user