Update dependency com.pinterest.ktlint:ktlint-cli to v1.2.0 (#1814)

* Update dependency com.pinterest.ktlint:ktlint-cli to v1.2.0

* Appease ktlint

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jake Wharton <jw@squareup.com>
This commit is contained in:
renovate[bot]
2024-02-28 21:59:39 +00:00
committed by GitHub
parent 04ebd09b7c
commit 516c005952
29 changed files with 325 additions and 25 deletions

View File

@@ -37,4 +37,4 @@ kotlinCompileTesting = { module = "dev.zacsweers.kctfork:core", version.ref = "k
kotlinCompileTesting-ksp = { module = "dev.zacsweers.kctfork:ksp", version.ref ="kotlinCompileTesting" } kotlinCompileTesting-ksp = { module = "dev.zacsweers.kctfork:ksp", version.ref ="kotlinCompileTesting" }
truth = "com.google.truth:truth:1.4.1" truth = "com.google.truth:truth:1.4.1"
googleJavaFormat = "com.google.googlejavaformat:google-java-format:1.20.0" googleJavaFormat = "com.google.googlejavaformat:google-java-format:1.20.0"
ktlint = "com.pinterest.ktlint:ktlint-cli:1.1.1" ktlint = "com.pinterest.ktlint:ktlint-cli:1.2.0"

View File

@@ -200,7 +200,9 @@ public class AdapterGenerator(
private fun TypeSpec.createProguardRule(): ProguardConfig { private fun TypeSpec.createProguardRule(): ProguardConfig {
val adapterConstructorParams = when (requireNotNull(primaryConstructor).parameters.size) { val adapterConstructorParams = when (requireNotNull(primaryConstructor).parameters.size) {
1 -> listOf(CN_MOSHI.reflectionName()) 1 -> listOf(CN_MOSHI.reflectionName())
2 -> listOf(CN_MOSHI.reflectionName(), "${CN_TYPE.reflectionName()}[]") 2 -> listOf(CN_MOSHI.reflectionName(), "${CN_TYPE.reflectionName()}[]")
// Should never happen // Should never happen
else -> error("Unexpected number of arguments on primary constructor: $primaryConstructor") else -> error("Unexpected number of arguments on primary constructor: $primaryConstructor")
} }
@@ -726,16 +728,26 @@ public data class PreparedAdapter(val spec: FileSpec, val proguardConfig: Progua
private fun AsmType.toReflectionString(): String { private fun AsmType.toReflectionString(): String {
return when (this) { return when (this) {
AsmType.VOID_TYPE -> "void" AsmType.VOID_TYPE -> "void"
AsmType.BOOLEAN_TYPE -> "boolean" AsmType.BOOLEAN_TYPE -> "boolean"
AsmType.CHAR_TYPE -> "char" AsmType.CHAR_TYPE -> "char"
AsmType.BYTE_TYPE -> "byte" AsmType.BYTE_TYPE -> "byte"
AsmType.SHORT_TYPE -> "short" AsmType.SHORT_TYPE -> "short"
AsmType.INT_TYPE -> "int" AsmType.INT_TYPE -> "int"
AsmType.FLOAT_TYPE -> "float" AsmType.FLOAT_TYPE -> "float"
AsmType.LONG_TYPE -> "long" AsmType.LONG_TYPE -> "long"
AsmType.DOUBLE_TYPE -> "double" AsmType.DOUBLE_TYPE -> "double"
else -> when (sort) { else -> when (sort) {
AsmType.ARRAY -> "${elementType.toReflectionString()}[]" AsmType.ARRAY -> "${elementType.toReflectionString()}[]"
// Object type // Object type
else -> className else -> className
} }

View File

@@ -64,6 +64,7 @@ public data class DelegateKey(
val (initializerString, args) = when { val (initializerString, args) = when {
jsonQualifiers.isEmpty() -> ", %M()" to arrayOf(MemberName("kotlin.collections", "emptySet")) jsonQualifiers.isEmpty() -> ", %M()" to arrayOf(MemberName("kotlin.collections", "emptySet"))
else -> { else -> {
", setOf(%L)" to arrayOf(jsonQualifiers.map { it.asInstantiationExpression() }.joinToCode()) ", setOf(%L)" to arrayOf(jsonQualifiers.map { it.asInstantiationExpression() }.joinToCode())
} }

View File

@@ -92,10 +92,12 @@ internal abstract class TypeRenderer {
target = typeName.inTypes[0] target = typeName.inTypes[0]
method = "supertypeOf" method = "supertypeOf"
} }
typeName.outTypes.size == 1 -> { typeName.outTypes.size == 1 -> {
target = typeName.outTypes[0] target = typeName.outTypes[0]
method = "subtypeOf" method = "subtypeOf"
} }
else -> throw IllegalArgumentException( else -> throw IllegalArgumentException(
"Unrepresentable wildcard type. Cannot have more than one bound: $typeName", "Unrepresentable wildcard type. Cannot have more than one bound: $typeName",
) )

View File

@@ -49,7 +49,9 @@ internal fun TypeName.rawType(): ClassName {
internal fun TypeName.findRawType(): ClassName? { internal fun TypeName.findRawType(): ClassName? {
return when (this) { return when (this) {
is ClassName -> this is ClassName -> this
is ParameterizedTypeName -> rawType is ParameterizedTypeName -> rawType
is LambdaTypeName -> { is LambdaTypeName -> {
var count = parameters.size var count = parameters.size
if (receiver != null) { if (receiver != null) {
@@ -62,6 +64,7 @@ internal fun TypeName.findRawType(): ClassName? {
} }
ClassName("kotlin.jvm.functions", functionSimpleName) ClassName("kotlin.jvm.functions", functionSimpleName)
} }
else -> null else -> null
} }
} }
@@ -104,11 +107,14 @@ internal fun TypeName.asTypeBlock(): CodeBlock {
rawType.asTypeBlock() rawType.asTypeBlock()
} }
} }
is TypeVariableName -> { is TypeVariableName -> {
val bound = bounds.firstOrNull() ?: ANY val bound = bounds.firstOrNull() ?: ANY
return bound.asTypeBlock() return bound.asTypeBlock()
} }
is LambdaTypeName -> return rawType().asTypeBlock() is LambdaTypeName -> return rawType().asTypeBlock()
is ClassName -> { is ClassName -> {
// Check against the non-nullable version for equality, but we'll keep the nullability in // Check against the non-nullable version for equality, but we'll keep the nullability in
// consideration when creating the CodeBlock if needed. // consideration when creating the CodeBlock if needed.
@@ -121,10 +127,13 @@ internal fun TypeName.asTypeBlock(): CodeBlock {
CodeBlock.of("%T::class.javaPrimitiveType!!", this) CodeBlock.of("%T::class.javaPrimitiveType!!", this)
} }
} }
UNIT, Void::class.asTypeName(), NOTHING -> throw IllegalStateException("Parameter with void, Unit, or Nothing type is illegal") UNIT, Void::class.asTypeName(), NOTHING -> throw IllegalStateException("Parameter with void, Unit, or Nothing type is illegal")
else -> CodeBlock.of("%T::class.java", copy(nullable = false)) else -> CodeBlock.of("%T::class.java", copy(nullable = false))
} }
} }
else -> throw UnsupportedOperationException("Parameter with type '${javaClass.simpleName}' is illegal. Only classes, parameterized types, or type variables are allowed.") else -> throw UnsupportedOperationException("Parameter with type '${javaClass.simpleName}' is illegal. Only classes, parameterized types, or type variables are allowed.")
} }
} }
@@ -138,11 +147,15 @@ internal fun KModifier.checkIsVisibility() {
internal fun TypeName.stripTypeVarVariance(resolver: TypeVariableResolver): TypeName { internal fun TypeName.stripTypeVarVariance(resolver: TypeVariableResolver): TypeName {
return when (this) { return when (this) {
is ClassName -> this is ClassName -> this
is ParameterizedTypeName -> { is ParameterizedTypeName -> {
deepCopy { it.stripTypeVarVariance(resolver) } deepCopy { it.stripTypeVarVariance(resolver) }
} }
is TypeVariableName -> resolver[name] is TypeVariableName -> resolver[name]
is WildcardTypeName -> deepCopy { it.stripTypeVarVariance(resolver) } is WildcardTypeName -> deepCopy { it.stripTypeVarVariance(resolver) }
else -> throw UnsupportedOperationException("Type '${javaClass.simpleName}' is illegal. Only classes, parameterized types, wildcard types, or type variables are allowed.") else -> throw UnsupportedOperationException("Type '${javaClass.simpleName}' is illegal. Only classes, parameterized types, wildcard types, or type variables are allowed.")
} }
} }
@@ -168,14 +181,17 @@ internal fun WildcardTypeName.deepCopy(transform: (TypeName) -> TypeName): TypeN
// Consumer type - single element inTypes, single ANY element outType. // Consumer type - single element inTypes, single ANY element outType.
return when { return when {
this == STAR -> this this == STAR -> this
outTypes.isNotEmpty() && inTypes.isEmpty() -> { outTypes.isNotEmpty() && inTypes.isEmpty() -> {
WildcardTypeName.producerOf(transform(outTypes[0])) WildcardTypeName.producerOf(transform(outTypes[0]))
.copy(nullable = isNullable, annotations = annotations) .copy(nullable = isNullable, annotations = annotations)
} }
inTypes.isNotEmpty() -> { inTypes.isNotEmpty() -> {
WildcardTypeName.consumerOf(transform(inTypes[0])) WildcardTypeName.consumerOf(transform(inTypes[0]))
.copy(nullable = isNullable, annotations = annotations) .copy(nullable = isNullable, annotations = annotations)
} }
else -> throw UnsupportedOperationException("Not possible.") else -> throw UnsupportedOperationException("Not possible.")
} }
} }

View File

@@ -44,18 +44,23 @@ private fun TypeName.unwrapTypeAliasInternal(): TypeName? {
internal fun TypeName.unwrapTypeAlias(): TypeName { internal fun TypeName.unwrapTypeAlias(): TypeName {
return when (this) { return when (this) {
is ClassName -> unwrapTypeAliasInternal() ?: this is ClassName -> unwrapTypeAliasInternal() ?: this
is ParameterizedTypeName -> { is ParameterizedTypeName -> {
unwrapTypeAliasInternal() ?: deepCopy(TypeName::unwrapTypeAlias) unwrapTypeAliasInternal() ?: deepCopy(TypeName::unwrapTypeAlias)
} }
is TypeVariableName -> { is TypeVariableName -> {
unwrapTypeAliasInternal() ?: deepCopy(transform = TypeName::unwrapTypeAlias) unwrapTypeAliasInternal() ?: deepCopy(transform = TypeName::unwrapTypeAlias)
} }
is WildcardTypeName -> { is WildcardTypeName -> {
unwrapTypeAliasInternal() ?: deepCopy(TypeName::unwrapTypeAlias) unwrapTypeAliasInternal() ?: deepCopy(TypeName::unwrapTypeAlias)
} }
is LambdaTypeName -> { is LambdaTypeName -> {
unwrapTypeAliasInternal() ?: deepCopy(TypeName::unwrapTypeAlias) unwrapTypeAliasInternal() ?: deepCopy(TypeName::unwrapTypeAlias)
} }
Dynamic -> throw UnsupportedOperationException("Type '${javaClass.simpleName}' is illegal. Only classes, parameterized types, wildcard types, or type variables are allowed.") Dynamic -> throw UnsupportedOperationException("Type '${javaClass.simpleName}' is illegal. Only classes, parameterized types, wildcard types, or type variables are allowed.")
} }
} }

View File

@@ -152,6 +152,7 @@ internal fun targetType(
) )
return null return null
} }
!kmClass.isClass -> { !kmClass.isClass -> {
messager.printMessage( messager.printMessage(
ERROR, ERROR,
@@ -160,6 +161,7 @@ internal fun targetType(
) )
return null return null
} }
kmClass.isInner -> { kmClass.isInner -> {
messager.printMessage( messager.printMessage(
ERROR, ERROR,
@@ -168,6 +170,7 @@ internal fun targetType(
) )
return null return null
} }
kmClass.flags.isSealed -> { kmClass.flags.isSealed -> {
messager.printMessage( messager.printMessage(
ERROR, ERROR,
@@ -176,6 +179,7 @@ internal fun targetType(
) )
return null return null
} }
kmClass.flags.isAbstract -> { kmClass.flags.isAbstract -> {
messager.printMessage( messager.printMessage(
ERROR, ERROR,
@@ -184,6 +188,7 @@ internal fun targetType(
) )
return null return null
} }
kmClass.flags.isLocal -> { kmClass.flags.isLocal -> {
messager.printMessage( messager.printMessage(
ERROR, ERROR,
@@ -192,6 +197,7 @@ internal fun targetType(
) )
return null return null
} }
!kmClass.flags.isPublic && !kmClass.flags.isInternal -> { !kmClass.flags.isPublic && !kmClass.flags.isInternal -> {
messager.printMessage( messager.printMessage(
ERROR, ERROR,
@@ -350,15 +356,18 @@ private fun resolveTypeArgs(
return when { return when {
resolvedType !is TypeVariableName -> resolvedType resolvedType !is TypeVariableName -> resolvedType
entryStartIndex != 0 -> { entryStartIndex != 0 -> {
// We need to go deeper // We need to go deeper
resolveTypeArgs(targetClass, resolvedType, resolvedTypes, allowedTypeVars, entryStartIndex - 1) resolveTypeArgs(targetClass, resolvedType, resolvedTypes, allowedTypeVars, entryStartIndex - 1)
} }
resolvedType.copy(nullable = false) in allowedTypeVars -> { resolvedType.copy(nullable = false) in allowedTypeVars -> {
// This is a generic type in the top-level declared class. This is fine to leave in because // This is a generic type in the top-level declared class. This is fine to leave in because
// this will be handled by the `Type` array passed in at runtime. // this will be handled by the `Type` array passed in at runtime.
resolvedType resolvedType
} }
else -> error("Could not find $resolvedType in $resolvedTypes. Also not present in allowable top-level type vars $allowedTypeVars") else -> error("Could not find $resolvedType in $resolvedTypes. Also not present in allowable top-level type vars $allowedTypeVars")
} }
} }

View File

@@ -76,6 +76,7 @@ private fun addValueToBlock(value: Any, resolver: Resolver, member: CodeBlock.Bu
} }
member.add("⇤⇤)") member.add("⇤⇤)")
} }
is KSType -> { is KSType -> {
val unwrapped = value.unwrapTypeAlias() val unwrapped = value.unwrapTypeAlias()
val isEnum = (unwrapped.declaration as KSClassDeclaration).classKind == ClassKind.ENUM_ENTRY val isEnum = (unwrapped.declaration as KSClassDeclaration).classKind == ClassKind.ENUM_ENTRY
@@ -87,13 +88,16 @@ private fun addValueToBlock(value: Any, resolver: Resolver, member: CodeBlock.Bu
member.add("%T::class", unwrapped.toClassName()) member.add("%T::class", unwrapped.toClassName())
} }
} }
is KSName -> is KSName ->
member.add( member.add(
"%T.%L", "%T.%L",
ClassName.bestGuess(value.getQualifier()), ClassName.bestGuess(value.getQualifier()),
value.getShortName(), value.getShortName(),
) )
is KSAnnotation -> member.add("%L", value.toAnnotationSpec(resolver)) is KSAnnotation -> member.add("%L", value.toAnnotationSpec(resolver))
else -> member.add(memberForValue(value)) else -> member.add(memberForValue(value))
} }
} }
@@ -105,13 +109,21 @@ private fun addValueToBlock(value: Any, resolver: Resolver, member: CodeBlock.Bu
*/ */
internal fun memberForValue(value: Any) = when (value) { internal fun memberForValue(value: Any) = when (value) {
is Class<*> -> CodeBlock.of("%T::class", value) is Class<*> -> CodeBlock.of("%T::class", value)
is Enum<*> -> CodeBlock.of("%T.%L", value.javaClass, value.name) is Enum<*> -> CodeBlock.of("%T.%L", value.javaClass, value.name)
is String -> CodeBlock.of("%S", value) is String -> CodeBlock.of("%S", value)
is Float -> CodeBlock.of("%Lf", value) is Float -> CodeBlock.of("%Lf", value)
is Double -> CodeBlock.of("%L", value) is Double -> CodeBlock.of("%L", value)
is Char -> CodeBlock.of("$value.toChar()") is Char -> CodeBlock.of("$value.toChar()")
is Byte -> CodeBlock.of("$value.toByte()") is Byte -> CodeBlock.of("$value.toByte()")
is Short -> CodeBlock.of("$value.toShort()") is Short -> CodeBlock.of("$value.toShort()")
// Int or Boolean // Int or Boolean
else -> CodeBlock.of("%L", value) else -> CodeBlock.of("%L", value)
} }

View File

@@ -80,32 +80,39 @@ private fun KSAnnotation.createInvocationHandler(clazz: Class<*>): InvocationHan
} }
when (val result = argument.value ?: method.defaultValue) { when (val result = argument.value ?: method.defaultValue) {
is Proxy -> result is Proxy -> result
is List<*> -> { is List<*> -> {
val value = { result.asArray(method) } val value = { result.asArray(method) }
cache.getOrPut(Pair(method.returnType, result), value) cache.getOrPut(Pair(method.returnType, result), value)
} }
else -> { else -> {
when { when {
method.returnType.isEnum -> { method.returnType.isEnum -> {
val value = { result.asEnum(method.returnType) } val value = { result.asEnum(method.returnType) }
cache.getOrPut(Pair(method.returnType, result), value) cache.getOrPut(Pair(method.returnType, result), value)
} }
method.returnType.isAnnotation -> { method.returnType.isAnnotation -> {
val value = { (result as KSAnnotation).asAnnotation(method.returnType) } val value = { (result as KSAnnotation).asAnnotation(method.returnType) }
cache.getOrPut(Pair(method.returnType, result), value) cache.getOrPut(Pair(method.returnType, result), value)
} }
method.returnType.name == "java.lang.Class" -> { method.returnType.name == "java.lang.Class" -> {
val value = { (result as KSType).asClass() } val value = { (result as KSType).asClass() }
cache.getOrPut(Pair(method.returnType, result), value) cache.getOrPut(Pair(method.returnType, result), value)
} }
method.returnType.name == "byte" -> { method.returnType.name == "byte" -> {
val value = { result.asByte() } val value = { result.asByte() }
cache.getOrPut(Pair(method.returnType, result), value) cache.getOrPut(Pair(method.returnType, result), value)
} }
method.returnType.name == "short" -> { method.returnType.name == "short" -> {
val value = { result.asShort() } val value = { result.asShort() }
cache.getOrPut(Pair(method.returnType, result), value) cache.getOrPut(Pair(method.returnType, result), value)
} }
else -> result // original value else -> result // original value
} }
} }
@@ -129,27 +136,39 @@ private fun KSAnnotation.asAnnotation(
private fun List<*>.asArray(method: Method) = private fun List<*>.asArray(method: Method) =
when (method.returnType.componentType.name) { when (method.returnType.componentType.name) {
"boolean" -> (this as List<Boolean>).toBooleanArray() "boolean" -> (this as List<Boolean>).toBooleanArray()
"byte" -> (this as List<Byte>).toByteArray() "byte" -> (this as List<Byte>).toByteArray()
"short" -> (this as List<Short>).toShortArray() "short" -> (this as List<Short>).toShortArray()
"char" -> (this as List<Char>).toCharArray() "char" -> (this as List<Char>).toCharArray()
"double" -> (this as List<Double>).toDoubleArray() "double" -> (this as List<Double>).toDoubleArray()
"float" -> (this as List<Float>).toFloatArray() "float" -> (this as List<Float>).toFloatArray()
"int" -> (this as List<Int>).toIntArray() "int" -> (this as List<Int>).toIntArray()
"long" -> (this as List<Long>).toLongArray() "long" -> (this as List<Long>).toLongArray()
"java.lang.Class" -> (this as List<KSType>).map { "java.lang.Class" -> (this as List<KSType>).map {
Class.forName(it.declaration.qualifiedName!!.asString()) Class.forName(it.declaration.qualifiedName!!.asString())
}.toTypedArray() }.toTypedArray()
"java.lang.String" -> (this as List<String>).toTypedArray() "java.lang.String" -> (this as List<String>).toTypedArray()
else -> { // arrays of enums or annotations else -> { // arrays of enums or annotations
when { when {
method.returnType.componentType.isEnum -> { method.returnType.componentType.isEnum -> {
this.toArray(method) { result -> result.asEnum(method.returnType.componentType) } this.toArray(method) { result -> result.asEnum(method.returnType.componentType) }
} }
method.returnType.componentType.isAnnotation -> { method.returnType.componentType.isAnnotation -> {
this.toArray(method) { result -> this.toArray(method) { result ->
(result as KSAnnotation).asAnnotation(method.returnType.componentType) (result as KSAnnotation).asAnnotation(method.returnType.componentType)
} }
} }
else -> throw IllegalStateException("Unable to process type ${method.returnType.componentType.name}") else -> throw IllegalStateException("Unable to process type ${method.returnType.componentType.name}")
} }
} }

View File

@@ -668,6 +668,7 @@ class JsonClassCodegenProcessorTest {
} }
""".trimIndent(), """.trimIndent(),
) )
"moshi-testPackage.Simple" -> assertThat(generatedFile.readText()).contains( "moshi-testPackage.Simple" -> assertThat(generatedFile.readText()).contains(
""" """
-if class testPackage.Simple -if class testPackage.Simple
@@ -678,6 +679,7 @@ class JsonClassCodegenProcessorTest {
} }
""".trimIndent(), """.trimIndent(),
) )
"moshi-testPackage.Generic" -> assertThat(generatedFile.readText()).contains( "moshi-testPackage.Generic" -> assertThat(generatedFile.readText()).contains(
""" """
-if class testPackage.Generic -if class testPackage.Generic
@@ -688,6 +690,7 @@ class JsonClassCodegenProcessorTest {
} }
""".trimIndent(), """.trimIndent(),
) )
"moshi-testPackage.UsingQualifiers" -> { "moshi-testPackage.UsingQualifiers" -> {
assertThat(generatedFile.readText()).contains( assertThat(generatedFile.readText()).contains(
""" """
@@ -700,6 +703,7 @@ class JsonClassCodegenProcessorTest {
""".trimIndent(), """.trimIndent(),
) )
} }
"moshi-testPackage.MixedTypes" -> assertThat(generatedFile.readText()).contains( "moshi-testPackage.MixedTypes" -> assertThat(generatedFile.readText()).contains(
""" """
-if class testPackage.MixedTypes -if class testPackage.MixedTypes
@@ -710,6 +714,7 @@ class JsonClassCodegenProcessorTest {
} }
""".trimIndent(), """.trimIndent(),
) )
"moshi-testPackage.DefaultParams" -> assertThat(generatedFile.readText()).contains( "moshi-testPackage.DefaultParams" -> assertThat(generatedFile.readText()).contains(
""" """
-if class testPackage.DefaultParams -if class testPackage.DefaultParams
@@ -726,6 +731,7 @@ class JsonClassCodegenProcessorTest {
} }
""".trimIndent(), """.trimIndent(),
) )
"moshi-testPackage.Complex" -> { "moshi-testPackage.Complex" -> {
assertThat(generatedFile.readText()).contains( assertThat(generatedFile.readText()).contains(
""" """
@@ -744,6 +750,7 @@ class JsonClassCodegenProcessorTest {
""".trimIndent(), """.trimIndent(),
) )
} }
"moshi-testPackage.MultipleMasks" -> assertThat(generatedFile.readText()).contains( "moshi-testPackage.MultipleMasks" -> assertThat(generatedFile.readText()).contains(
""" """
-if class testPackage.MultipleMasks -if class testPackage.MultipleMasks
@@ -760,6 +767,7 @@ class JsonClassCodegenProcessorTest {
} }
""".trimIndent(), """.trimIndent(),
) )
"moshi-testPackage.NestedType.NestedSimple" -> { "moshi-testPackage.NestedType.NestedSimple" -> {
assertThat(generatedFile.readText()).contains( assertThat(generatedFile.readText()).contains(
""" """
@@ -772,6 +780,7 @@ class JsonClassCodegenProcessorTest {
""".trimIndent(), """.trimIndent(),
) )
} }
else -> error("Unexpected proguard file! ${generatedFile.name}") else -> error("Unexpected proguard file! ${generatedFile.name}")
} }
} }

View File

@@ -718,6 +718,7 @@ class JsonClassSymbolProcessorTest {
} }
""".trimIndent(), """.trimIndent(),
) )
"moshi-testPackage.Simple" -> assertThat(generatedFile.readText()).contains( "moshi-testPackage.Simple" -> assertThat(generatedFile.readText()).contains(
""" """
-if class testPackage.Simple -if class testPackage.Simple
@@ -728,6 +729,7 @@ class JsonClassSymbolProcessorTest {
} }
""".trimIndent(), """.trimIndent(),
) )
"moshi-testPackage.Generic" -> assertThat(generatedFile.readText()).contains( "moshi-testPackage.Generic" -> assertThat(generatedFile.readText()).contains(
""" """
-if class testPackage.Generic -if class testPackage.Generic
@@ -738,6 +740,7 @@ class JsonClassSymbolProcessorTest {
} }
""".trimIndent(), """.trimIndent(),
) )
"moshi-testPackage.UsingQualifiers" -> { "moshi-testPackage.UsingQualifiers" -> {
assertThat(generatedFile.readText()).contains( assertThat(generatedFile.readText()).contains(
""" """
@@ -750,6 +753,7 @@ class JsonClassSymbolProcessorTest {
""".trimIndent(), """.trimIndent(),
) )
} }
"moshi-testPackage.MixedTypes" -> assertThat(generatedFile.readText()).contains( "moshi-testPackage.MixedTypes" -> assertThat(generatedFile.readText()).contains(
""" """
-if class testPackage.MixedTypes -if class testPackage.MixedTypes
@@ -760,6 +764,7 @@ class JsonClassSymbolProcessorTest {
} }
""".trimIndent(), """.trimIndent(),
) )
"moshi-testPackage.DefaultParams" -> assertThat(generatedFile.readText()).contains( "moshi-testPackage.DefaultParams" -> assertThat(generatedFile.readText()).contains(
""" """
-if class testPackage.DefaultParams -if class testPackage.DefaultParams
@@ -776,6 +781,7 @@ class JsonClassSymbolProcessorTest {
} }
""".trimIndent(), """.trimIndent(),
) )
"moshi-testPackage.Complex" -> { "moshi-testPackage.Complex" -> {
assertThat(generatedFile.readText()).contains( assertThat(generatedFile.readText()).contains(
""" """
@@ -794,6 +800,7 @@ class JsonClassSymbolProcessorTest {
""".trimIndent(), """.trimIndent(),
) )
} }
"moshi-testPackage.MultipleMasks" -> assertThat(generatedFile.readText()).contains( "moshi-testPackage.MultipleMasks" -> assertThat(generatedFile.readText()).contains(
""" """
-if class testPackage.MultipleMasks -if class testPackage.MultipleMasks
@@ -810,6 +817,7 @@ class JsonClassSymbolProcessorTest {
} }
""".trimIndent(), """.trimIndent(),
) )
"moshi-testPackage.NestedType.NestedSimple" -> { "moshi-testPackage.NestedType.NestedSimple" -> {
assertThat(generatedFile.readText()).contains( assertThat(generatedFile.readText()).contains(
""" """
@@ -822,6 +830,7 @@ class JsonClassSymbolProcessorTest {
""".trimIndent(), """.trimIndent(),
) )
} }
else -> error("Unexpected proguard file! ${generatedFile.name}") else -> error("Unexpected proguard file! ${generatedFile.name}")
} }
} }

View File

@@ -24,9 +24,11 @@ when (testMode) {
REFLECT -> { REFLECT -> {
// Do nothing! // Do nothing!
} }
KAPT -> { KAPT -> {
apply(plugin = "org.jetbrains.kotlin.kapt") apply(plugin = "org.jetbrains.kotlin.kapt")
} }
KSP -> { KSP -> {
apply(plugin = "com.google.devtools.ksp") apply(plugin = "com.google.devtools.ksp")
} }
@@ -51,9 +53,11 @@ dependencies {
REFLECT -> { REFLECT -> {
// Do nothing // Do nothing
} }
KAPT -> { KAPT -> {
"kaptTest"(project(":moshi-kotlin-codegen")) "kaptTest"(project(":moshi-kotlin-codegen"))
} }
KSP -> { KSP -> {
"kspTest"(project(":moshi-kotlin-codegen")) "kspTest"(project(":moshi-kotlin-codegen"))
} }

View File

@@ -25,9 +25,11 @@ when (testMode) {
// Default to KSP. This is a CI-only thing // Default to KSP. This is a CI-only thing
apply(plugin = "com.google.devtools.ksp") apply(plugin = "com.google.devtools.ksp")
} }
KAPT -> { KAPT -> {
apply(plugin = "org.jetbrains.kotlin.kapt") apply(plugin = "org.jetbrains.kotlin.kapt")
} }
KSP -> { KSP -> {
apply(plugin = "com.google.devtools.ksp") apply(plugin = "com.google.devtools.ksp")
} }
@@ -53,9 +55,11 @@ dependencies {
// Default to KSP in this case, this is a CI-only thing // Default to KSP in this case, this is a CI-only thing
"kspTest"(project(":moshi-kotlin-codegen")) "kspTest"(project(":moshi-kotlin-codegen"))
} }
KAPT -> { KAPT -> {
"kaptTest"(project(":moshi-kotlin-codegen")) "kaptTest"(project(":moshi-kotlin-codegen"))
} }
KSP -> { KSP -> {
"kspTest"(project(":moshi-kotlin-codegen")) "kspTest"(project(":moshi-kotlin-codegen"))
} }

View File

@@ -104,7 +104,10 @@ internal class KotlinJsonAdapter<T>(
if (values[i] === ABSENT_VALUE) { if (values[i] === ABSENT_VALUE) {
when { when {
constructor.parameters[i].isOptional -> isFullInitialized = false constructor.parameters[i].isOptional -> isFullInitialized = false
constructor.parameters[i].type.isMarkedNullable -> values[i] = null // Replace absent with null.
// Replace absent with null.
constructor.parameters[i].type.isMarkedNullable -> values[i] = null
else -> throw missingProperty( else -> throw missingProperty(
constructor.parameters[i].name, constructor.parameters[i].name,
allBindings[i]?.jsonName, allBindings[i]?.jsonName,
@@ -285,9 +288,11 @@ public class KotlinJsonAdapterFactory : JsonAdapter.Factory {
property.returnType.javaType property.returnType.javaType
} }
} }
is KTypeParameter -> { is KTypeParameter -> {
property.returnType.javaType property.returnType.javaType
} }
else -> error("Not possible!") else -> error("Not possible!")
} }
val resolvedPropertyType = propertyType.resolve(type, rawType) val resolvedPropertyType = propertyType.resolve(type, rawType)

View File

@@ -61,7 +61,9 @@ internal class AdapterMethodsFactory(
override fun toJson(writer: JsonWriter, value: Any?) { override fun toJson(writer: JsonWriter, value: Any?) {
when { when {
toAdapter == null -> knownNotNull(delegate).toJson(writer, value) toAdapter == null -> knownNotNull(delegate).toJson(writer, value)
!toAdapter.nullable && value == null -> writer.nullValue() !toAdapter.nullable && value == null -> writer.nullValue()
else -> { else -> {
try { try {
toAdapter.toJson(moshi, writer, value) toAdapter.toJson(moshi, writer, value)
@@ -77,7 +79,9 @@ internal class AdapterMethodsFactory(
override fun fromJson(reader: JsonReader): Any? { override fun fromJson(reader: JsonReader): Any? {
return when { return when {
fromAdapter == null -> knownNotNull(delegate).fromJson(reader) fromAdapter == null -> knownNotNull(delegate).fromJson(reader)
!fromAdapter.nullable && reader.peek() == JsonReader.Token.NULL -> reader.nextNull<Any>() !fromAdapter.nullable && reader.peek() == JsonReader.Token.NULL -> reader.nextNull<Any>()
else -> { else -> {
try { try {
fromAdapter.fromJson(moshi, reader) fromAdapter.fromJson(moshi, reader)
@@ -161,6 +165,7 @@ internal class AdapterMethodsFactory(
} }
} }
} }
parameterTypes.size == 1 && returnType != Void.TYPE -> { parameterTypes.size == 1 && returnType != Void.TYPE -> {
// List<Integer> pointToJson(Point point) { // List<Integer> pointToJson(Point point) {
val returnTypeAnnotations = method.jsonAnnotations val returnTypeAnnotations = method.jsonAnnotations
@@ -194,6 +199,7 @@ internal class AdapterMethodsFactory(
} }
} }
} }
else -> { else -> {
throw IllegalArgumentException( throw IllegalArgumentException(
""" """
@@ -249,6 +255,7 @@ internal class AdapterMethodsFactory(
override fun fromJson(moshi: Moshi, reader: JsonReader) = invokeMethod(reader) override fun fromJson(moshi: Moshi, reader: JsonReader) = invokeMethod(reader)
} }
} }
parameterTypes.size == 1 && returnType != Void.TYPE -> { parameterTypes.size == 1 && returnType != Void.TYPE -> {
// Point pointFromJson(List<Integer> o) { // Point pointFromJson(List<Integer> o) {
val qualifierAnnotations = parameterAnnotations[0].jsonAnnotations val qualifierAnnotations = parameterAnnotations[0].jsonAnnotations
@@ -279,6 +286,7 @@ internal class AdapterMethodsFactory(
} }
} }
} }
else -> { else -> {
throw IllegalArgumentException( throw IllegalArgumentException(
""" """

View File

@@ -49,41 +49,49 @@ internal class ArrayJsonAdapter(
elementAdapter.toJson(writer, element) elementAdapter.toJson(writer, element)
} }
} }
is ByteArray -> { is ByteArray -> {
for (element in value) { for (element in value) {
elementAdapter.toJson(writer, element) elementAdapter.toJson(writer, element)
} }
} }
is CharArray -> { is CharArray -> {
for (element in value) { for (element in value) {
elementAdapter.toJson(writer, element) elementAdapter.toJson(writer, element)
} }
} }
is DoubleArray -> { is DoubleArray -> {
for (element in value) { for (element in value) {
elementAdapter.toJson(writer, element) elementAdapter.toJson(writer, element)
} }
} }
is FloatArray -> { is FloatArray -> {
for (element in value) { for (element in value) {
elementAdapter.toJson(writer, element) elementAdapter.toJson(writer, element)
} }
} }
is IntArray -> { is IntArray -> {
for (element in value) { for (element in value) {
elementAdapter.toJson(writer, element) elementAdapter.toJson(writer, element)
} }
} }
is LongArray -> { is LongArray -> {
for (element in value) { for (element in value) {
elementAdapter.toJson(writer, element) elementAdapter.toJson(writer, element)
} }
} }
is ShortArray -> { is ShortArray -> {
for (element in value) { for (element in value) {
elementAdapter.toJson(writer, element) elementAdapter.toJson(writer, element)
} }
} }
is Array<*> -> { is Array<*> -> {
for (element in value) { for (element in value) {
elementAdapter.toJson(writer, element) elementAdapter.toJson(writer, element)

View File

@@ -53,9 +53,11 @@ internal abstract class CollectionJsonAdapter<C : MutableCollection<T?>, T> priv
List::class.java, Collection::class.java -> { List::class.java, Collection::class.java -> {
newArrayListAdapter<Any>(type, moshi).nullSafe() newArrayListAdapter<Any>(type, moshi).nullSafe()
} }
Set::class.java -> { Set::class.java -> {
newLinkedHashSetAdapter<Any>(type, moshi).nullSafe() newLinkedHashSetAdapter<Any>(type, moshi).nullSafe()
} }
else -> null else -> null
} }
} }

View File

@@ -483,6 +483,7 @@ public sealed class JsonReader : Closeable {
endArray() endArray()
} }
} }
Token.BEGIN_OBJECT -> { Token.BEGIN_OBJECT -> {
return buildMap { return buildMap {
beginObject() beginObject()
@@ -497,10 +498,15 @@ public sealed class JsonReader : Closeable {
endObject() endObject()
} }
} }
Token.STRING -> nextString() Token.STRING -> nextString()
Token.NUMBER -> nextDouble() Token.NUMBER -> nextDouble()
Token.BOOLEAN -> nextBoolean() Token.BOOLEAN -> nextBoolean()
Token.NULL -> nextNull<Any>() Token.NULL -> nextNull<Any>()
else -> throw IllegalStateException("Expected a value but was ${peek()} at path $path") else -> throw IllegalStateException("Expected a value but was ${peek()} at path $path")
} }
} }

View File

@@ -59,12 +59,14 @@ internal object JsonScope {
for (i in 0 until stackSize) { for (i in 0 until stackSize) {
when (stack[i]) { when (stack[i]) {
EMPTY_ARRAY, NONEMPTY_ARRAY -> append('[').append(pathIndices[i]).append(']') EMPTY_ARRAY, NONEMPTY_ARRAY -> append('[').append(pathIndices[i]).append(']')
EMPTY_OBJECT, DANGLING_NAME, NONEMPTY_OBJECT -> { EMPTY_OBJECT, DANGLING_NAME, NONEMPTY_OBJECT -> {
append('.') append('.')
if (pathNames[i] != null) { if (pathNames[i] != null) {
append(pathNames[i]) append(pathNames[i])
} }
} }
NONEMPTY_DOCUMENT, EMPTY_DOCUMENT, CLOSED -> {} NONEMPTY_DOCUMENT, EMPTY_DOCUMENT, CLOSED -> {}
} }
} }

View File

@@ -147,6 +147,7 @@ internal class JsonUtf8Reader : JsonReader {
val peekStack = scopes[stackSize - 1] val peekStack = scopes[stackSize - 1]
when (peekStack) { when (peekStack) {
JsonScope.EMPTY_ARRAY -> scopes[stackSize - 1] = JsonScope.NONEMPTY_ARRAY JsonScope.EMPTY_ARRAY -> scopes[stackSize - 1] = JsonScope.NONEMPTY_ARRAY
JsonScope.NONEMPTY_ARRAY -> { JsonScope.NONEMPTY_ARRAY -> {
// Look for a comma before the next element. // Look for a comma before the next element.
val c = nextNonWhitespace(true).toChar() val c = nextNonWhitespace(true).toChar()
@@ -155,11 +156,16 @@ internal class JsonUtf8Reader : JsonReader {
']' -> { ']' -> {
return setPeeked(PEEKED_END_ARRAY) return setPeeked(PEEKED_END_ARRAY)
} }
';' -> checkLenient() ';' -> checkLenient()
',' -> Unit /*no op*/
/*no op*/
',' -> Unit
else -> throw syntaxError("Unterminated array") else -> throw syntaxError("Unterminated array")
} }
} }
JsonScope.EMPTY_OBJECT, JsonScope.NONEMPTY_OBJECT -> { JsonScope.EMPTY_OBJECT, JsonScope.NONEMPTY_OBJECT -> {
scopes[stackSize - 1] = JsonScope.DANGLING_NAME scopes[stackSize - 1] = JsonScope.DANGLING_NAME
// Look for a comma before the next element. // Look for a comma before the next element.
@@ -170,8 +176,12 @@ internal class JsonUtf8Reader : JsonReader {
'}' -> { '}' -> {
return setPeeked(PEEKED_END_OBJECT) return setPeeked(PEEKED_END_OBJECT)
} }
',' -> Unit /*no op*/
/*no op*/
',' -> Unit
';' -> checkLenient() ';' -> checkLenient()
else -> throw syntaxError("Unterminated object") else -> throw syntaxError("Unterminated object")
} }
} }
@@ -180,17 +190,20 @@ internal class JsonUtf8Reader : JsonReader {
buffer.readByte() // consume the '\"'. buffer.readByte() // consume the '\"'.
PEEKED_DOUBLE_QUOTED_NAME PEEKED_DOUBLE_QUOTED_NAME
} }
'\'' -> { '\'' -> {
buffer.readByte() // consume the '\''. buffer.readByte() // consume the '\''.
checkLenient() checkLenient()
PEEKED_SINGLE_QUOTED_NAME PEEKED_SINGLE_QUOTED_NAME
} }
'}' -> if (peekStack != JsonScope.NONEMPTY_OBJECT) { '}' -> if (peekStack != JsonScope.NONEMPTY_OBJECT) {
buffer.readByte() // consume the '}'. buffer.readByte() // consume the '}'.
PEEKED_END_OBJECT PEEKED_END_OBJECT
} else { } else {
throw syntaxError("Expected name") throw syntaxError("Expected name")
} }
else -> { else -> {
checkLenient() checkLenient()
if (isLiteral(c.code)) { if (isLiteral(c.code)) {
@@ -203,23 +216,29 @@ internal class JsonUtf8Reader : JsonReader {
peeked = next peeked = next
return next return next
} }
JsonScope.DANGLING_NAME -> { JsonScope.DANGLING_NAME -> {
scopes[stackSize - 1] = JsonScope.NONEMPTY_OBJECT scopes[stackSize - 1] = JsonScope.NONEMPTY_OBJECT
// Look for a colon before the value. // Look for a colon before the value.
val c = nextNonWhitespace(true).toChar() val c = nextNonWhitespace(true).toChar()
buffer.readByte() // Consume ':'. buffer.readByte() // Consume ':'.
when (c) { when (c) {
':' -> Unit /*no op*/ /*no op*/
':' -> Unit
'=' -> { '=' -> {
checkLenient() checkLenient()
if (source.request(1) && buffer[0].asChar() == '>') { if (source.request(1) && buffer[0].asChar() == '>') {
buffer.readByte() // Consume '>'. buffer.readByte() // Consume '>'.
} }
} }
else -> throw syntaxError("Expected ':'") else -> throw syntaxError("Expected ':'")
} }
} }
JsonScope.EMPTY_DOCUMENT -> scopes[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT JsonScope.EMPTY_DOCUMENT -> scopes[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT
JsonScope.NONEMPTY_DOCUMENT -> { JsonScope.NONEMPTY_DOCUMENT -> {
if (nextNonWhitespace(false) == -1) { if (nextNonWhitespace(false) == -1) {
return setPeeked(PEEKED_EOF) return setPeeked(PEEKED_EOF)
@@ -227,12 +246,14 @@ internal class JsonUtf8Reader : JsonReader {
checkLenient() checkLenient()
} }
} }
JsonScope.STREAMING_VALUE -> { JsonScope.STREAMING_VALUE -> {
valueSource!!.discard() valueSource!!.discard()
valueSource = null valueSource = null
stackSize-- stackSize--
return doPeek() return doPeek()
} }
else -> check(peekStack != JsonScope.CLOSED) { "JsonReader is closed" } else -> check(peekStack != JsonScope.CLOSED) { "JsonReader is closed" }
} }
// "fallthrough" from previous `when` // "fallthrough" from previous `when`
@@ -243,39 +264,48 @@ internal class JsonUtf8Reader : JsonReader {
buffer.readByte() // Consume ']'. buffer.readByte() // Consume ']'.
setPeeked(PEEKED_END_ARRAY) setPeeked(PEEKED_END_ARRAY)
} }
JsonScope.NONEMPTY_ARRAY -> { JsonScope.NONEMPTY_ARRAY -> {
// In lenient mode, a 0-length literal in an array means 'null'. // In lenient mode, a 0-length literal in an array means 'null'.
checkLenient() checkLenient()
setPeeked(PEEKED_NULL) setPeeked(PEEKED_NULL)
} }
else -> throw syntaxError("Unexpected value") else -> throw syntaxError("Unexpected value")
} }
} }
// In lenient mode, a 0-length literal in an array means 'null'. // In lenient mode, a 0-length literal in an array means 'null'.
';', ',' -> return when (peekStack) { ';', ',' -> return when (peekStack) {
JsonScope.EMPTY_ARRAY, JsonScope.NONEMPTY_ARRAY -> { JsonScope.EMPTY_ARRAY, JsonScope.NONEMPTY_ARRAY -> {
checkLenient() checkLenient()
setPeeked(PEEKED_NULL) setPeeked(PEEKED_NULL)
} }
else -> throw syntaxError("Unexpected value") else -> throw syntaxError("Unexpected value")
} }
'\'' -> { '\'' -> {
checkLenient() checkLenient()
buffer.readByte() // Consume '\''. buffer.readByte() // Consume '\''.
return setPeeked(PEEKED_SINGLE_QUOTED) return setPeeked(PEEKED_SINGLE_QUOTED)
} }
'"' -> { '"' -> {
buffer.readByte() // Consume '\"'. buffer.readByte() // Consume '\"'.
return setPeeked(PEEKED_DOUBLE_QUOTED) return setPeeked(PEEKED_DOUBLE_QUOTED)
} }
'[' -> { '[' -> {
buffer.readByte() // Consume '['. buffer.readByte() // Consume '['.
return setPeeked(PEEKED_BEGIN_ARRAY) return setPeeked(PEEKED_BEGIN_ARRAY)
} }
'{' -> { '{' -> {
buffer.readByte() // Consume '{'. buffer.readByte() // Consume '{'.
return setPeeked(PEEKED_BEGIN_OBJECT) return setPeeked(PEEKED_BEGIN_OBJECT)
} }
else -> Unit /* no-op */ else -> Unit /* no-op */
} }
var result = peekKeyword() var result = peekKeyword()
@@ -305,16 +335,19 @@ internal class JsonUtf8Reader : JsonReader {
keywordUpper = "TRUE" keywordUpper = "TRUE"
peeking = PEEKED_TRUE peeking = PEEKED_TRUE
} }
'f', 'F' -> { 'f', 'F' -> {
keyword = "false" keyword = "false"
keywordUpper = "FALSE" keywordUpper = "FALSE"
peeking = PEEKED_FALSE peeking = PEEKED_FALSE
} }
'n', 'N' -> { 'n', 'N' -> {
keyword = "null" keyword = "null"
keywordUpper = "NULL" keywordUpper = "NULL"
peeking = PEEKED_NULL peeking = PEEKED_NULL
} }
else -> return PEEKED_NONE else -> return PEEKED_NONE
} }
@@ -358,6 +391,7 @@ internal class JsonUtf8Reader : JsonReader {
i++ i++
continue continue
} }
NUMBER_CHAR_EXP_E -> { NUMBER_CHAR_EXP_E -> {
last = NUMBER_CHAR_EXP_SIGN last = NUMBER_CHAR_EXP_SIGN
i++ i++
@@ -366,6 +400,7 @@ internal class JsonUtf8Reader : JsonReader {
} }
return PEEKED_NONE return PEEKED_NONE
} }
'+' -> { '+' -> {
if (last == NUMBER_CHAR_EXP_E) { if (last == NUMBER_CHAR_EXP_E) {
last = NUMBER_CHAR_EXP_SIGN last = NUMBER_CHAR_EXP_SIGN
@@ -374,6 +409,7 @@ internal class JsonUtf8Reader : JsonReader {
} }
return PEEKED_NONE return PEEKED_NONE
} }
'e', 'E' -> { 'e', 'E' -> {
if (last == NUMBER_CHAR_DIGIT || last == NUMBER_CHAR_FRACTION_DIGIT) { if (last == NUMBER_CHAR_DIGIT || last == NUMBER_CHAR_FRACTION_DIGIT) {
last = NUMBER_CHAR_EXP_E last = NUMBER_CHAR_EXP_E
@@ -382,6 +418,7 @@ internal class JsonUtf8Reader : JsonReader {
} }
return PEEKED_NONE return PEEKED_NONE
} }
'.' -> { '.' -> {
if (last == NUMBER_CHAR_DIGIT) { if (last == NUMBER_CHAR_DIGIT) {
last = NUMBER_CHAR_DECIMAL last = NUMBER_CHAR_DECIMAL
@@ -390,6 +427,7 @@ internal class JsonUtf8Reader : JsonReader {
} }
return PEEKED_NONE return PEEKED_NONE
} }
else -> { else -> {
if (c !in '0'..'9') { if (c !in '0'..'9') {
if (!isLiteral(c.code)) break if (!isLiteral(c.code)) break
@@ -400,6 +438,7 @@ internal class JsonUtf8Reader : JsonReader {
value = -(c - '0').toLong() value = -(c - '0').toLong()
last = NUMBER_CHAR_DIGIT last = NUMBER_CHAR_DIGIT
} }
NUMBER_CHAR_DIGIT -> { NUMBER_CHAR_DIGIT -> {
if (value == 0L) { if (value == 0L) {
return PEEKED_NONE // Leading '0' prefix is not allowed (since it could be octal). return PEEKED_NONE // Leading '0' prefix is not allowed (since it could be octal).
@@ -413,7 +452,9 @@ internal class JsonUtf8Reader : JsonReader {
) )
value = newValue value = newValue
} }
NUMBER_CHAR_DECIMAL -> last = NUMBER_CHAR_FRACTION_DIGIT NUMBER_CHAR_DECIMAL -> last = NUMBER_CHAR_FRACTION_DIGIT
NUMBER_CHAR_EXP_E, NUMBER_CHAR_EXP_SIGN -> last = NUMBER_CHAR_EXP_DIGIT NUMBER_CHAR_EXP_E, NUMBER_CHAR_EXP_SIGN -> last = NUMBER_CHAR_EXP_DIGIT
} }
} }
@@ -431,12 +472,14 @@ internal class JsonUtf8Reader : JsonReader {
buffer.skip(i) buffer.skip(i)
setPeeked(PEEKED_LONG) setPeeked(PEEKED_LONG)
} }
last == NUMBER_CHAR_DIGIT || last == NUMBER_CHAR_DIGIT ||
last == NUMBER_CHAR_FRACTION_DIGIT || last == NUMBER_CHAR_FRACTION_DIGIT ||
last == NUMBER_CHAR_EXP_DIGIT -> { last == NUMBER_CHAR_EXP_DIGIT -> {
peekedNumberLength = i.toInt() peekedNumberLength = i.toInt()
setPeeked(PEEKED_NUMBER) setPeeked(PEEKED_NUMBER)
} }
else -> PEEKED_NONE else -> PEEKED_NONE
} }
} }
@@ -448,8 +491,10 @@ internal class JsonUtf8Reader : JsonReader {
checkLenient() // fall-through checkLenient() // fall-through
false false
} }
// 0x000C = \f // 0x000C = \f
'{', '}', '[', ']', ':', ',', ' ', '\t', '\u000C', '\r', '\n' -> false '{', '}', '[', ']', ':', ',', ' ', '\t', '\u000C', '\r', '\n' -> false
else -> true else -> true
} }
} }
@@ -458,13 +503,17 @@ internal class JsonUtf8Reader : JsonReader {
override fun nextName(): String { override fun nextName(): String {
val result = when (peekIfNone()) { val result = when (peekIfNone()) {
PEEKED_UNQUOTED_NAME -> nextUnquotedValue() PEEKED_UNQUOTED_NAME -> nextUnquotedValue()
PEEKED_DOUBLE_QUOTED_NAME -> nextQuotedValue(DOUBLE_QUOTE_OR_SLASH) PEEKED_DOUBLE_QUOTED_NAME -> nextQuotedValue(DOUBLE_QUOTE_OR_SLASH)
PEEKED_SINGLE_QUOTED_NAME -> nextQuotedValue(SINGLE_QUOTE_OR_SLASH) PEEKED_SINGLE_QUOTED_NAME -> nextQuotedValue(SINGLE_QUOTE_OR_SLASH)
PEEKED_BUFFERED_NAME -> { PEEKED_BUFFERED_NAME -> {
val name = peekedString!! val name = peekedString!!
peekedString = null peekedString = null
name name
} }
else -> throw JsonDataException("Expected a name but was ${peek()} at path $path") else -> throw JsonDataException("Expected a name but was ${peek()} at path $path")
} }
peeked = PEEKED_NONE peeked = PEEKED_NONE
@@ -539,15 +588,21 @@ internal class JsonUtf8Reader : JsonReader {
override fun nextString(): String { override fun nextString(): String {
val result = when (peekIfNone()) { val result = when (peekIfNone()) {
PEEKED_UNQUOTED -> nextUnquotedValue() PEEKED_UNQUOTED -> nextUnquotedValue()
PEEKED_DOUBLE_QUOTED -> nextQuotedValue(DOUBLE_QUOTE_OR_SLASH) PEEKED_DOUBLE_QUOTED -> nextQuotedValue(DOUBLE_QUOTE_OR_SLASH)
PEEKED_SINGLE_QUOTED -> nextQuotedValue(SINGLE_QUOTE_OR_SLASH) PEEKED_SINGLE_QUOTED -> nextQuotedValue(SINGLE_QUOTE_OR_SLASH)
PEEKED_BUFFERED -> { PEEKED_BUFFERED -> {
val buffered = peekedString!! val buffered = peekedString!!
peekedString = null peekedString = null
buffered buffered
} }
PEEKED_LONG -> peekedLong.toString() PEEKED_LONG -> peekedLong.toString()
PEEKED_NUMBER -> buffer.readUtf8(peekedNumberLength.toLong()) PEEKED_NUMBER -> buffer.readUtf8(peekedNumberLength.toLong())
else -> throw JsonDataException("Expected a string but was ${peek()} at path $path") else -> throw JsonDataException("Expected a string but was ${peek()} at path $path")
} }
peeked = PEEKED_NONE peeked = PEEKED_NONE
@@ -601,11 +656,13 @@ internal class JsonUtf8Reader : JsonReader {
pathIndices[stackSize - 1]++ pathIndices[stackSize - 1]++
true true
} }
PEEKED_FALSE -> { PEEKED_FALSE -> {
peeked = PEEKED_NONE peeked = PEEKED_NONE
pathIndices[stackSize - 1]++ pathIndices[stackSize - 1]++
false false
} }
else -> throw JsonDataException("Expected a boolean but was ${peek()} at path $path") else -> throw JsonDataException("Expected a boolean but was ${peek()} at path $path")
} }
} }
@@ -630,13 +687,18 @@ internal class JsonUtf8Reader : JsonReader {
} }
val next = when (p) { val next = when (p) {
PEEKED_NUMBER -> buffer.readUtf8(peekedNumberLength.toLong()).also { peekedString = it } PEEKED_NUMBER -> buffer.readUtf8(peekedNumberLength.toLong()).also { peekedString = it }
PEEKED_DOUBLE_QUOTED -> nextQuotedValue(DOUBLE_QUOTE_OR_SLASH).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_SINGLE_QUOTED -> nextQuotedValue(SINGLE_QUOTE_OR_SLASH).also { peekedString = it }
PEEKED_UNQUOTED -> nextUnquotedValue().also { peekedString = it } PEEKED_UNQUOTED -> nextUnquotedValue().also { peekedString = it }
PEEKED_BUFFERED -> { PEEKED_BUFFERED -> {
// PEEKED_BUFFERED means the value's been stored in peekedString // PEEKED_BUFFERED means the value's been stored in peekedString
knownNotNull(peekedString) knownNotNull(peekedString)
} }
else -> throw JsonDataException("Expected a double but was " + peek() + " at path " + path) else -> throw JsonDataException("Expected a double but was " + peek() + " at path " + path)
} }
peeked = PEEKED_BUFFERED peeked = PEEKED_BUFFERED
@@ -663,6 +725,7 @@ internal class JsonUtf8Reader : JsonReader {
} }
when { when {
p == PEEKED_NUMBER -> peekedString = buffer.readUtf8(peekedNumberLength.toLong()) p == PEEKED_NUMBER -> peekedString = buffer.readUtf8(peekedNumberLength.toLong())
p == PEEKED_DOUBLE_QUOTED || p == PEEKED_SINGLE_QUOTED -> { 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) peekedString = if (p == PEEKED_DOUBLE_QUOTED) nextQuotedValue(DOUBLE_QUOTE_OR_SLASH) else nextQuotedValue(SINGLE_QUOTE_OR_SLASH)
try { try {
@@ -674,6 +737,7 @@ internal class JsonUtf8Reader : JsonReader {
// Fall back to parse as a BigDecimal below. // Fall back to parse as a BigDecimal below.
} }
} }
p != PEEKED_BUFFERED -> { p != PEEKED_BUFFERED -> {
throw JsonDataException("Expected a long but was " + peek() + " at path " + path) throw JsonDataException("Expected a long but was " + peek() + " at path " + path)
} }
@@ -768,6 +832,7 @@ internal class JsonUtf8Reader : JsonReader {
PEEKED_NUMBER -> { PEEKED_NUMBER -> {
buffer.readUtf8(peekedNumberLength.toLong()).also { peekedString = it } buffer.readUtf8(peekedNumberLength.toLong()).also { peekedString = it }
} }
PEEKED_DOUBLE_QUOTED, PEEKED_SINGLE_QUOTED -> { PEEKED_DOUBLE_QUOTED, PEEKED_SINGLE_QUOTED -> {
val next = if (p == PEEKED_DOUBLE_QUOTED) { val next = if (p == PEEKED_DOUBLE_QUOTED) {
nextQuotedValue(DOUBLE_QUOTE_OR_SLASH) nextQuotedValue(DOUBLE_QUOTE_OR_SLASH)
@@ -785,10 +850,12 @@ internal class JsonUtf8Reader : JsonReader {
next next
} }
} }
PEEKED_BUFFERED -> { PEEKED_BUFFERED -> {
// PEEKED_BUFFERED means the value's been stored in peekedString // PEEKED_BUFFERED means the value's been stored in peekedString
knownNotNull(peekedString) knownNotNull(peekedString)
} }
else -> throw JsonDataException("Expected an int but was ${peek()} at path $path") else -> throw JsonDataException("Expected an int but was ${peek()} at path $path")
} }
peeked = PEEKED_BUFFERED peeked = PEEKED_BUFFERED
@@ -826,10 +893,12 @@ internal class JsonUtf8Reader : JsonReader {
pushScope(JsonScope.EMPTY_ARRAY) pushScope(JsonScope.EMPTY_ARRAY)
count++ count++
} }
PEEKED_BEGIN_OBJECT -> { PEEKED_BEGIN_OBJECT -> {
pushScope(JsonScope.EMPTY_OBJECT) pushScope(JsonScope.EMPTY_OBJECT)
count++ count++
} }
PEEKED_END_ARRAY -> { PEEKED_END_ARRAY -> {
count-- count--
if (count < 0) { if (count < 0) {
@@ -837,6 +906,7 @@ internal class JsonUtf8Reader : JsonReader {
} }
stackSize-- stackSize--
} }
PEEKED_END_OBJECT -> { PEEKED_END_OBJECT -> {
count-- count--
if (count < 0) { if (count < 0) {
@@ -844,10 +914,15 @@ internal class JsonUtf8Reader : JsonReader {
} }
stackSize-- stackSize--
} }
PEEKED_UNQUOTED_NAME, PEEKED_UNQUOTED -> skipUnquotedValue() PEEKED_UNQUOTED_NAME, PEEKED_UNQUOTED -> skipUnquotedValue()
PEEKED_DOUBLE_QUOTED, PEEKED_DOUBLE_QUOTED_NAME -> skipQuotedValue(DOUBLE_QUOTE_OR_SLASH) PEEKED_DOUBLE_QUOTED, PEEKED_DOUBLE_QUOTED_NAME -> skipQuotedValue(DOUBLE_QUOTE_OR_SLASH)
PEEKED_SINGLE_QUOTED, PEEKED_SINGLE_QUOTED_NAME -> skipQuotedValue(SINGLE_QUOTE_OR_SLASH) PEEKED_SINGLE_QUOTED, PEEKED_SINGLE_QUOTED_NAME -> skipQuotedValue(SINGLE_QUOTE_OR_SLASH)
PEEKED_NUMBER -> buffer.skip(peekedNumberLength.toLong()) PEEKED_NUMBER -> buffer.skip(peekedNumberLength.toLong())
PEEKED_EOF -> throw JsonDataException("Expected a value but was ${peek()} at path $path") PEEKED_EOF -> throw JsonDataException("Expected a value but was ${peek()} at path $path")
} }
peeked = PEEKED_NONE peeked = PEEKED_NONE
@@ -867,29 +942,38 @@ internal class JsonUtf8Reader : JsonReader {
state = JsonValueSource.STATE_JSON state = JsonValueSource.STATE_JSON
valueSourceStackSize++ valueSourceStackSize++
} }
PEEKED_BEGIN_OBJECT -> { PEEKED_BEGIN_OBJECT -> {
prefix.writeUtf8("{") prefix.writeUtf8("{")
state = JsonValueSource.STATE_JSON state = JsonValueSource.STATE_JSON
valueSourceStackSize++ valueSourceStackSize++
} }
PEEKED_DOUBLE_QUOTED -> { PEEKED_DOUBLE_QUOTED -> {
prefix.writeUtf8("\"") prefix.writeUtf8("\"")
state = JsonValueSource.STATE_DOUBLE_QUOTED state = JsonValueSource.STATE_DOUBLE_QUOTED
} }
PEEKED_SINGLE_QUOTED -> { PEEKED_SINGLE_QUOTED -> {
prefix.writeUtf8("'") prefix.writeUtf8("'")
state = JsonValueSource.STATE_SINGLE_QUOTED state = JsonValueSource.STATE_SINGLE_QUOTED
} }
PEEKED_NUMBER, PEEKED_LONG, PEEKED_UNQUOTED -> prefix.writeUtf8(nextString()) PEEKED_NUMBER, PEEKED_LONG, PEEKED_UNQUOTED -> prefix.writeUtf8(nextString())
PEEKED_TRUE -> prefix.writeUtf8("true") PEEKED_TRUE -> prefix.writeUtf8("true")
PEEKED_FALSE -> prefix.writeUtf8("false") PEEKED_FALSE -> prefix.writeUtf8("false")
PEEKED_NULL -> prefix.writeUtf8("null") PEEKED_NULL -> prefix.writeUtf8("null")
PEEKED_BUFFERED -> { PEEKED_BUFFERED -> {
val string = nextString() val string = nextString()
JsonWriter.of(prefix).use { jsonWriter -> JsonWriter.of(prefix).use { jsonWriter ->
jsonWriter.value(string) jsonWriter.value(string)
} }
} }
else -> throw JsonDataException("Expected a value but was ${peek()} at path $path") else -> throw JsonDataException("Expected a value but was ${peek()} at path $path")
} }
@@ -942,6 +1026,7 @@ internal class JsonUtf8Reader : JsonReader {
p = 0 p = 0
continue continue
} }
'/' -> { '/' -> {
// skip a // end-of-line comment // skip a // end-of-line comment
buffer.readByte() // '/' buffer.readByte() // '/'
@@ -950,9 +1035,11 @@ internal class JsonUtf8Reader : JsonReader {
p = 0 p = 0
continue continue
} }
else -> c.code else -> c.code
} }
} }
'#' -> { '#' -> {
// Skip a # hash end-of-line comment. The JSON RFC doesn't specify this behaviour, but it's // Skip a # hash end-of-line comment. The JSON RFC doesn't specify this behaviour, but it's
// required to parse existing documents. // required to parse existing documents.
@@ -960,6 +1047,7 @@ internal class JsonUtf8Reader : JsonReader {
skipToEndOfLine() skipToEndOfLine()
p = 0 p = 0
} }
else -> return c.code else -> return c.code
} }
} }
@@ -1026,12 +1114,20 @@ internal class JsonUtf8Reader : JsonReader {
buffer.skip(4) buffer.skip(4)
result result
} }
't' -> '\t' 't' -> '\t'
'b' -> '\b' 'b' -> '\b'
'n' -> '\n' 'n' -> '\n'
'r' -> '\r' 'r' -> '\r'
'f' -> '\u000C' /*\f*/
/*\f*/
'f' -> '\u000C'
'\n', '\'', '"', '\\', '/' -> escaped '\n', '\'', '"', '\\', '/' -> escaped
else -> { else -> {
if (!lenient) throw syntaxError("Invalid escape sequence: \\$escaped") if (!lenient) throw syntaxError("Invalid escape sequence: \\$escaped")
escaped escaped

View File

@@ -302,21 +302,27 @@ internal class JsonUtf8Writer(
} }
nextTop = JsonScope.NONEMPTY_DOCUMENT nextTop = JsonScope.NONEMPTY_DOCUMENT
} }
JsonScope.EMPTY_DOCUMENT -> nextTop = JsonScope.NONEMPTY_DOCUMENT JsonScope.EMPTY_DOCUMENT -> nextTop = JsonScope.NONEMPTY_DOCUMENT
JsonScope.NONEMPTY_ARRAY -> { JsonScope.NONEMPTY_ARRAY -> {
sink.writeByte(','.code) sink.writeByte(','.code)
newline() newline()
nextTop = JsonScope.NONEMPTY_ARRAY nextTop = JsonScope.NONEMPTY_ARRAY
} }
JsonScope.EMPTY_ARRAY -> { JsonScope.EMPTY_ARRAY -> {
newline() newline()
nextTop = JsonScope.NONEMPTY_ARRAY nextTop = JsonScope.NONEMPTY_ARRAY
} }
JsonScope.DANGLING_NAME -> { JsonScope.DANGLING_NAME -> {
nextTop = JsonScope.NONEMPTY_OBJECT nextTop = JsonScope.NONEMPTY_OBJECT
sink.writeUtf8(separator) sink.writeUtf8(separator)
} }
JsonScope.STREAMING_VALUE -> throw IllegalStateException("Sink from valueSink() was not closed") JsonScope.STREAMING_VALUE -> throw IllegalStateException("Sink from valueSink() was not closed")
else -> throw IllegalStateException("Nesting problem.") else -> throw IllegalStateException("Nesting problem.")
} }
replaceTop(nextTop) replaceTop(nextTop)

View File

@@ -113,13 +113,21 @@ internal class JsonValueReader : JsonReader {
// If the top of the stack is an iterator, take its first element and push it on the stack. // If the top of the stack is an iterator, take its first element and push it on the stack.
return when (val peeked = stack[stackSize - 1]) { return when (val peeked = stack[stackSize - 1]) {
is JsonIterator -> peeked.endToken is JsonIterator -> peeked.endToken
is List<*> -> Token.BEGIN_ARRAY is List<*> -> Token.BEGIN_ARRAY
is Map<*, *> -> Token.BEGIN_OBJECT is Map<*, *> -> Token.BEGIN_OBJECT
is Map.Entry<*, *> -> Token.NAME is Map.Entry<*, *> -> Token.NAME
is String -> Token.STRING is String -> Token.STRING
is Boolean -> Token.BOOLEAN is Boolean -> Token.BOOLEAN
is Number -> Token.NUMBER is Number -> Token.NUMBER
null -> Token.NULL null -> Token.NULL
else -> ifNotClosed(peeked) { else -> ifNotClosed(peeked) {
throw typeMismatch(peeked, "a JSON value") throw typeMismatch(peeked, "a JSON value")
} }
@@ -170,10 +178,12 @@ internal class JsonValueReader : JsonReader {
remove() remove()
peeked peeked
} }
is Number -> { is Number -> {
remove() remove()
peeked.toString() peeked.toString()
} }
else -> ifNotClosed(peeked) { else -> ifNotClosed(peeked) {
throw typeMismatch(peeked, Token.STRING) throw typeMismatch(peeked, Token.STRING)
} }
@@ -211,6 +221,7 @@ internal class JsonValueReader : JsonReader {
override fun nextDouble(): Double { override fun nextDouble(): Double {
val result = when (val peeked = require<Any>(Token.NUMBER)) { val result = when (val peeked = require<Any>(Token.NUMBER)) {
is Number -> peeked.toDouble() is Number -> peeked.toDouble()
is String -> { is String -> {
try { try {
peeked.toDouble() peeked.toDouble()
@@ -218,6 +229,7 @@ internal class JsonValueReader : JsonReader {
throw typeMismatch(peeked, Token.NUMBER) throw typeMismatch(peeked, Token.NUMBER)
} }
} }
else -> { else -> {
throw typeMismatch(peeked, Token.NUMBER) throw typeMismatch(peeked, Token.NUMBER)
} }
@@ -232,6 +244,7 @@ internal class JsonValueReader : JsonReader {
override fun nextLong(): Long { override fun nextLong(): Long {
val result: Long = when (val peeked = require<Any>(Token.NUMBER)) { val result: Long = when (val peeked = require<Any>(Token.NUMBER)) {
is Number -> peeked.toLong() is Number -> peeked.toLong()
is String -> try { is String -> try {
peeked.toLong() peeked.toLong()
} catch (e: NumberFormatException) { } catch (e: NumberFormatException) {
@@ -241,6 +254,7 @@ internal class JsonValueReader : JsonReader {
throw typeMismatch(peeked, Token.NUMBER) throw typeMismatch(peeked, Token.NUMBER)
} }
} }
else -> throw typeMismatch(peeked, Token.NUMBER) else -> throw typeMismatch(peeked, Token.NUMBER)
} }
remove() remove()
@@ -250,6 +264,7 @@ internal class JsonValueReader : JsonReader {
override fun nextInt(): Int { override fun nextInt(): Int {
val result = when (val peeked = require<Any>(Token.NUMBER)) { val result = when (val peeked = require<Any>(Token.NUMBER)) {
is Number -> peeked.toInt() is Number -> peeked.toInt()
is String -> try { is String -> try {
peeked.toInt() peeked.toInt()
} catch (e: NumberFormatException) { } catch (e: NumberFormatException) {
@@ -259,6 +274,7 @@ internal class JsonValueReader : JsonReader {
throw typeMismatch(peeked, Token.NUMBER) throw typeMismatch(peeked, Token.NUMBER)
} }
} }
else -> throw typeMismatch(peeked, Token.NUMBER) else -> throw typeMismatch(peeked, Token.NUMBER)
} }
remove() remove()

View File

@@ -91,19 +91,23 @@ internal class JsonValueSource @JvmOverloads constructor(
stackSize++ stackSize++
limit = index + 1 limit = index + 1
} }
']', '}' -> { ']', '}' -> {
stackSize-- stackSize--
if (stackSize == 0) state = STATE_END_OF_JSON if (stackSize == 0) state = STATE_END_OF_JSON
limit = index + 1 limit = index + 1
} }
'\"' -> { '\"' -> {
state = STATE_DOUBLE_QUOTED state = STATE_DOUBLE_QUOTED
limit = index + 1 limit = index + 1
} }
'\'' -> { '\'' -> {
state = STATE_SINGLE_QUOTED state = STATE_SINGLE_QUOTED
limit = index + 1 limit = index + 1
} }
'/' -> { '/' -> {
source.require(index + 2) source.require(index + 2)
when (buffer[index + 1]) { when (buffer[index + 1]) {
@@ -111,20 +115,24 @@ internal class JsonValueSource @JvmOverloads constructor(
state = STATE_END_OF_LINE_COMMENT state = STATE_END_OF_LINE_COMMENT
limit = index + 2 limit = index + 2
} }
'*'.code.toByte() -> { '*'.code.toByte() -> {
state = STATE_C_STYLE_COMMENT state = STATE_C_STYLE_COMMENT
limit = index + 2 limit = index + 2
} }
else -> { else -> {
limit = index + 1 limit = index + 1
} }
} }
} }
'#' -> { '#' -> {
state = STATE_END_OF_LINE_COMMENT state = STATE_END_OF_LINE_COMMENT
limit = index + 1 limit = index + 1
} }
} }
state === STATE_SINGLE_QUOTED || state === STATE_DOUBLE_QUOTED -> { state === STATE_SINGLE_QUOTED || state === STATE_DOUBLE_QUOTED -> {
if (b == '\\'.code.toByte()) { if (b == '\\'.code.toByte()) {
source.require(index + 2) source.require(index + 2)
@@ -134,6 +142,7 @@ internal class JsonValueSource @JvmOverloads constructor(
limit = index + 1 limit = index + 1
} }
} }
state === STATE_C_STYLE_COMMENT -> { state === STATE_C_STYLE_COMMENT -> {
source.require(index + 2) source.require(index + 2)
if (buffer[index + 1] == '/'.code.toByte()) { if (buffer[index + 1] == '/'.code.toByte()) {
@@ -143,10 +152,12 @@ internal class JsonValueSource @JvmOverloads constructor(
limit = index + 1 limit = index + 1
} }
} }
state === STATE_END_OF_LINE_COMMENT -> { state === STATE_END_OF_LINE_COMMENT -> {
limit = index + 1 limit = index + 1
state = STATE_JSON state = STATE_JSON
} }
else -> { else -> {
throw AssertionError() throw AssertionError()
} }

View File

@@ -168,10 +168,13 @@ internal class JsonValueWriter : JsonWriter() {
override fun value(value: Number?): JsonWriter = apply { override fun value(value: Number?): JsonWriter = apply {
when (value) { when (value) {
null -> nullValue() null -> nullValue()
// If it's trivially converted to a long, do that. // If it's trivially converted to a long, do that.
is Byte, is Short, is Int, is Long -> value(value.toLong()) is Byte, is Short, is Int, is Long -> value(value.toLong())
// If it's trivially converted to a double, do that. // If it's trivially converted to a double, do that.
is Float, is Double -> value(value.toDouble()) is Float, is Double -> value(value.toDouble())
else -> { else -> {
// Everything else gets converted to a BigDecimal. // Everything else gets converted to a BigDecimal.
val bigDecimalValue = if (value is BigDecimal) value else BigDecimal(value.toString()) val bigDecimalValue = if (value is BigDecimal) value else BigDecimal(value.toString())
@@ -229,6 +232,7 @@ internal class JsonValueWriter : JsonWriter() {
scopes[stackSize - 1] = NONEMPTY_DOCUMENT scopes[stackSize - 1] = NONEMPTY_DOCUMENT
stack[stackSize - 1] = newTop stack[stackSize - 1] = newTop
} }
scope == EMPTY_OBJECT && deferredName != null -> { scope == EMPTY_OBJECT && deferredName != null -> {
if (newTop != null || serializeNulls) { if (newTop != null || serializeNulls) {
// Our maps always have string keys and object values. // Our maps always have string keys and object values.
@@ -242,13 +246,16 @@ internal class JsonValueWriter : JsonWriter() {
} }
deferredName = null deferredName = null
} }
scope == EMPTY_ARRAY -> { scope == EMPTY_ARRAY -> {
// Our lists always have object values. // Our lists always have object values.
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val list = stack[stackSize - 1] as MutableList<Any?> val list = stack[stackSize - 1] as MutableList<Any?>
list.add(newTop) list.add(newTop)
} }
scope == STREAMING_VALUE -> throw IllegalStateException("Sink from valueSink() was not closed") scope == STREAMING_VALUE -> throw IllegalStateException("Sink from valueSink() was not closed")
else -> throw IllegalStateException("Nesting problem.") else -> throw IllegalStateException("Nesting problem.")
} }
return this return this

View File

@@ -151,22 +151,15 @@ public sealed class JsonWriter : Closeable, Flushable {
* pretty printing. * pretty printing.
*/ */
@JvmField @JvmField
@Suppress("ktlint:standard:property-naming") // Exposed to sealed subtypes. @Suppress("ktlint:standard:backing-property-naming") // Exposed to sealed subtypes.
protected var _indent: String? = null protected var _indent: String? = null
public open var indent: String
/**
* Returns a string containing only whitespace, used for each level of indentation. If empty,
* the encoded document will be compact.
*/
get() = _indent.orEmpty()
/** /**
* Sets the indentation string to be repeated for each level of indentation in the encoded * A string containing only whitespace, used for each level of indentation.
* document. If `indent.isEmpty()` the encoded document will be compact. Otherwise, the * If empty, the encoded document will be compact.
* encoded document will be more human-readable. */
* public open var indent: String
* @param value a string containing only whitespace. get() = _indent.orEmpty()
*/
set(value) { set(value) {
_indent = value.ifEmpty { null } _indent = value.ifEmpty { null }
} }
@@ -402,6 +395,7 @@ public sealed class JsonWriter : Closeable, Flushable {
} }
endObject() endObject()
} }
is List<*> -> { is List<*> -> {
beginArray() beginArray()
for (element in value) { for (element in value) {
@@ -409,12 +403,19 @@ public sealed class JsonWriter : Closeable, Flushable {
} }
endArray() endArray()
} }
is String -> value(value as String?) is String -> value(value as String?)
is Boolean -> value(value) is Boolean -> value(value)
is Double -> value(value) is Double -> value(value)
is Long -> value(value) is Long -> value(value)
is Number -> value(value) is Number -> value(value)
null -> nullValue() null -> nullValue()
else -> throw IllegalArgumentException("Unsupported type: ${value.javaClass.name}") else -> throw IllegalArgumentException("Unsupported type: ${value.javaClass.name}")
} }
return this return this

View File

@@ -14,14 +14,10 @@ private val NATURAL_ORDER = Comparator<Any> { o1, o2 -> (o1 as Comparable<Any>).
* removal. * removal.
* *
* This implementation was derived from Android 4.1's TreeMap and LinkedHashMap classes. * This implementation was derived from Android 4.1's TreeMap and LinkedHashMap classes.
*/
internal class LinkedHashTreeMap<K, V>
/**
* Create a tree map ordered by [comparator]. This map's keys may only be null if [comparator] permits.
* *
* @param comparator the comparator to order elements with, or null to use the natural ordering. * @param comparator the comparator to order elements with, or null to use the natural ordering.
*/ */
constructor( internal class LinkedHashTreeMap<K, V>(
comparator: Comparator<Any?>? = null, comparator: Comparator<Any?>? = null,
) : AbstractMutableMap<K, V>(), Serializable { ) : AbstractMutableMap<K, V>(), Serializable {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@@ -402,6 +398,7 @@ constructor(
break // no further rotations will be necessary break // no further rotations will be necessary
} }
} }
2 -> { 2 -> {
val leftLeft = left!!.left val leftLeft = left!!.left
val leftRight = left.right val leftRight = left.right
@@ -417,12 +414,14 @@ constructor(
break // no further rotations will be necessary break // no further rotations will be necessary
} }
} }
0 -> { 0 -> {
node.height = leftHeight + 1 // leftHeight == rightHeight node.height = leftHeight + 1 // leftHeight == rightHeight
if (insert) { if (insert) {
break // the insert caused balance, so rebalancing is done! break // the insert caused balance, so rebalancing is done!
} }
} }
else -> { else -> {
assert(delta == -1 || delta == 1) assert(delta == -1 || delta == 1)
node.height = max(leftHeight, rightHeight) + 1 node.height = max(leftHeight, rightHeight) + 1
@@ -748,6 +747,7 @@ internal class AvlBuilder<K, V> {
left.parent = center left.parent = center
right.parent = center right.parent = center
} }
1 -> { 1 -> {
// Pop right and center, then make center the top of the stack. // Pop right and center, then make center the top of the stack.
val right = stack val right = stack
@@ -759,6 +759,7 @@ internal class AvlBuilder<K, V> {
right.parent = center right.parent = center
leavesSkipped = 0 leavesSkipped = 0
} }
2 -> { 2 -> {
leavesSkipped = 0 leavesSkipped = 0
} }

View File

@@ -238,11 +238,17 @@ internal object StandardJsonAdapters : JsonAdapter.Factory {
override fun fromJson(reader: JsonReader): Any? { override fun fromJson(reader: JsonReader): Any? {
return when (reader.peek()) { return when (reader.peek()) {
JsonReader.Token.BEGIN_ARRAY -> listJsonAdapter.fromJson(reader) JsonReader.Token.BEGIN_ARRAY -> listJsonAdapter.fromJson(reader)
JsonReader.Token.BEGIN_OBJECT -> mapAdapter.fromJson(reader) JsonReader.Token.BEGIN_OBJECT -> mapAdapter.fromJson(reader)
JsonReader.Token.STRING -> stringAdapter.fromJson(reader) JsonReader.Token.STRING -> stringAdapter.fromJson(reader)
JsonReader.Token.NUMBER -> doubleAdapter.fromJson(reader) JsonReader.Token.NUMBER -> doubleAdapter.fromJson(reader)
JsonReader.Token.BOOLEAN -> booleanAdapter.fromJson(reader) JsonReader.Token.BOOLEAN -> booleanAdapter.fromJson(reader)
JsonReader.Token.NULL -> reader.nextNull() JsonReader.Token.NULL -> reader.nextNull()
else -> throw IllegalStateException( else -> throw IllegalStateException(
"Expected a value but was ${reader.peek()} at path ${reader.path}", "Expected a value but was ${reader.peek()} at path ${reader.path}",
) )

View File

@@ -163,22 +163,27 @@ public object Types {
// type is a normal class. // type is a normal class.
type type
} }
is ParameterizedType -> { is ParameterizedType -> {
// I'm not exactly sure why getRawType() returns Type instead of Class. Neal isn't either but // I'm not exactly sure why getRawType() returns Type instead of Class. Neal isn't either but
// suspects some pathological case related to nested classes exists. // suspects some pathological case related to nested classes exists.
val rawType = type.rawType val rawType = type.rawType
rawType as Class<*> rawType as Class<*>
} }
is GenericArrayType -> { is GenericArrayType -> {
val componentType = type.genericComponentType val componentType = type.genericComponentType
java.lang.reflect.Array.newInstance(getRawType(componentType), 0).javaClass java.lang.reflect.Array.newInstance(getRawType(componentType), 0).javaClass
} }
is TypeVariable<*> -> { is TypeVariable<*> -> {
// We could use the variable's bounds, but that won't work if there are multiple. having a raw // We could use the variable's bounds, but that won't work if there are multiple. having a raw
// type that's more general than necessary is okay. // type that's more general than necessary is okay.
Any::class.java Any::class.java
} }
is WildcardType -> getRawType(type.upperBounds[0]) is WildcardType -> getRawType(type.upperBounds[0])
else -> { else -> {
val className = type?.javaClass?.name?.toString() val className = type?.javaClass?.name?.toString()
throw IllegalArgumentException("Expected a Class, ParameterizedType, or GenericArrayType, but <$type> is of type $className") throw IllegalArgumentException("Expected a Class, ParameterizedType, or GenericArrayType, but <$type> is of type $className")
@@ -222,6 +227,7 @@ public object Types {
a == b // Class already specifies equals(). a == b // Class already specifies equals().
} }
} }
is ParameterizedType -> { is ParameterizedType -> {
// Class instance with generic info, from method return types // Class instance with generic info, from method return types
if (b is Class<*> && a.rawType == b.rawType) { if (b is Class<*> && a.rawType == b.rawType) {
@@ -235,6 +241,7 @@ public object Types {
(a.rawType == b.rawType) && aTypeArguments.contentEquals(bTypeArguments) (a.rawType == b.rawType) && aTypeArguments.contentEquals(bTypeArguments)
) )
} }
is GenericArrayType -> { is GenericArrayType -> {
if (b is Class<*>) { if (b is Class<*>) {
return equals(b.componentType, a.genericComponentType) return equals(b.componentType, a.genericComponentType)
@@ -242,14 +249,17 @@ public object Types {
if (b !is GenericArrayType) return false if (b !is GenericArrayType) return false
return equals(a.genericComponentType, b.genericComponentType) return equals(a.genericComponentType, b.genericComponentType)
} }
is WildcardType -> { is WildcardType -> {
if (b !is WildcardType) return false if (b !is WildcardType) return false
return (a.upperBounds.contentEquals(b.upperBounds) && a.lowerBounds.contentEquals(b.lowerBounds)) return (a.upperBounds.contentEquals(b.upperBounds) && a.lowerBounds.contentEquals(b.lowerBounds))
} }
is TypeVariable<*> -> { is TypeVariable<*> -> {
if (b !is TypeVariable<*>) return false if (b !is TypeVariable<*>) return false
return (a.genericDeclaration === b.genericDeclaration && (a.name == b.name)) return (a.genericDeclaration === b.genericDeclaration && (a.name == b.name))
} }
else -> return false // This isn't a supported type. else -> return false // This isn't a supported type.
} }
} }
@@ -305,12 +315,16 @@ public object Types {
) { proxy, method, args -> ) { proxy, method, args ->
when (method.name) { when (method.name) {
"annotationType" -> annotationType "annotationType" -> annotationType
"equals" -> { "equals" -> {
val o = args[0] val o = args[0]
annotationType.isInstance(o) annotationType.isInstance(o)
} }
"hashCode" -> 0 "hashCode" -> 0
"toString" -> "@${annotationType.name}()" "toString" -> "@${annotationType.name}()"
else -> method.invoke(proxy, *args) else -> method.invoke(proxy, *args)
} }
} as T } as T

View File

@@ -176,18 +176,22 @@ internal fun Type.canonicalize(): Type {
is Class<*> -> { is Class<*> -> {
if (isArray) GenericArrayTypeImpl(this@canonicalize.componentType.canonicalize()) else this if (isArray) GenericArrayTypeImpl(this@canonicalize.componentType.canonicalize()) else this
} }
is ParameterizedType -> { is ParameterizedType -> {
if (this is ParameterizedTypeImpl) return this if (this is ParameterizedTypeImpl) return this
ParameterizedTypeImpl(ownerType, rawType, *actualTypeArguments) ParameterizedTypeImpl(ownerType, rawType, *actualTypeArguments)
} }
is GenericArrayType -> { is GenericArrayType -> {
if (this is GenericArrayTypeImpl) return this if (this is GenericArrayTypeImpl) return this
GenericArrayTypeImpl(genericComponentType) GenericArrayTypeImpl(genericComponentType)
} }
is WildcardType -> { is WildcardType -> {
if (this is WildcardTypeImpl) return this if (this is WildcardTypeImpl) return this
WildcardTypeImpl(upperBounds, lowerBounds) WildcardTypeImpl(upperBounds, lowerBounds)
} }
else -> this // This type is unsupported! else -> this // This type is unsupported!
} }
} }
@@ -226,18 +230,21 @@ private fun Type.resolve(
toResolve = resolveTypeVariable(context, contextRawType, typeVariable) toResolve = resolveTypeVariable(context, contextRawType, typeVariable)
if (toResolve === typeVariable) return toResolve if (toResolve === typeVariable) return toResolve
} }
toResolve is Class<*> && toResolve.isArray -> { toResolve is Class<*> && toResolve.isArray -> {
val original = toResolve val original = toResolve
val componentType: Type = original.componentType val componentType: Type = original.componentType
val newComponentType = componentType.resolve(context, contextRawType, visitedTypeVariables) val newComponentType = componentType.resolve(context, contextRawType, visitedTypeVariables)
return if (componentType === newComponentType) original else newComponentType.asArrayType() return if (componentType === newComponentType) original else newComponentType.asArrayType()
} }
toResolve is GenericArrayType -> { toResolve is GenericArrayType -> {
val original = toResolve val original = toResolve
val componentType = original.genericComponentType val componentType = original.genericComponentType
val newComponentType = componentType.resolve(context, contextRawType, visitedTypeVariables) val newComponentType = componentType.resolve(context, contextRawType, visitedTypeVariables)
return if (componentType === newComponentType) original else newComponentType.asArrayType() return if (componentType === newComponentType) original else newComponentType.asArrayType()
} }
toResolve is ParameterizedType -> { toResolve is ParameterizedType -> {
val original = toResolve val original = toResolve
val ownerType: Type? = original.ownerType val ownerType: Type? = original.ownerType
@@ -258,6 +265,7 @@ private fun Type.resolve(
} }
return if (changed) ParameterizedTypeImpl(newOwnerType, original.rawType, *args) else original return if (changed) ParameterizedTypeImpl(newOwnerType, original.rawType, *args) else original
} }
toResolve is WildcardType -> { toResolve is WildcardType -> {
val original = toResolve val original = toResolve
val originalLowerBound = original.lowerBounds val originalLowerBound = original.lowerBounds
@@ -275,6 +283,7 @@ private fun Type.resolve(
} }
return original return original
} }
else -> return toResolve else -> return toResolve
} }
} }