Finish migrating tests from the reflective adapter

This commit is contained in:
Jesse Wilson
2018-05-13 21:52:06 -04:00
parent 298aff24f5
commit 13952c5430
10 changed files with 159 additions and 217 deletions

View File

@@ -319,7 +319,6 @@ internal class AdapterGenerator(
.returns(jsonAdapterTypeName)
.addParameter(moshiParam)
// TODO make this configurable. Right now it just matches the source model
if (visibility == Visibility.INTERNAL) {
result.addModifiers(KModifier.INTERNAL)
}

View File

@@ -53,12 +53,14 @@ internal data class DelegateKey(
val annotationElement = MoreTypes.asTypeElement(annotationType)
annotationElement.getAnnotation(java.lang.annotation.Retention::class.java)?.let {
if (it.value != RetentionPolicy.RUNTIME) {
messager.printMessage(ERROR, "JsonQualifier @${MoreTypes.asTypeElement(annotationType).simpleName} must have RUNTIME retention")
messager.printMessage(ERROR, "JsonQualifier " +
"@${MoreTypes.asTypeElement(annotationType).simpleName} must have RUNTIME retention")
}
}
annotationElement.getAnnotation(java.lang.annotation.Target::class.java)?.let {
if (ElementType.FIELD !in it.value) {
messager.printMessage(ERROR, "JsonQualifier @${MoreTypes.asTypeElement(annotationType).simpleName} must support FIELD target")
messager.printMessage(ERROR, "JsonQualifier " +
"@${MoreTypes.asTypeElement(annotationType).simpleName} must support FIELD target")
}
}
return this
@@ -84,9 +86,8 @@ internal data class DelegateKey(
val (initializerString, args) = when {
qualifiers.isEmpty() -> "" to emptyArray()
else -> {
", %${standardArgsSize}T.getFieldJsonQualifierAnnotations(javaClass, %${standardArgsSize + 1}S)" to arrayOf(
Types::class.asTypeName(),
adapterName)
", %${standardArgsSize}T.getFieldJsonQualifierAnnotations(javaClass, " +
"%${standardArgsSize + 1}S)" to arrayOf(Types::class.asTypeName(), adapterName)
}
}
val finalArgs = arrayOf(*standardArgs, *args)
@@ -94,7 +95,9 @@ internal data class DelegateKey(
val nullModifier = if (nullable) ".nullSafe()" else ".nonNull()"
return PropertySpec.builder(adapterName, adapterTypeName, KModifier.PRIVATE)
.addAnnotations(qualifiers.map { AnnotationSpec.get(it).toBuilder().useSiteTarget(FIELD).build() })
.addAnnotations(qualifiers.map {
AnnotationSpec.get(it).toBuilder().useSiteTarget(FIELD).build()
})
.initializer("%1N.adapter%2L(%3L$initializerString)$nullModifier", *finalArgs)
.build()
}
@@ -104,9 +107,7 @@ internal data class DelegateKey(
* 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() }
}
private fun List<TypeName>.toVariableNames() = joinToString("") { it.toVariableName() }
/** Returns a suggested variable name derived from a type name, like nullableListOfString. */
private fun TypeName.toVariableName(): String {

View File

@@ -73,8 +73,8 @@ class JsonClassCodeGenProcessor : KotlinAbstractProcessor(), KotlinMetadataUtils
super.init(processingEnv)
generatedType = processingEnv.options[OPTION_GENERATED]?.let {
if (it !in POSSIBLE_GENERATED_NAMES) {
throw IllegalArgumentException(
"Invalid option value for $OPTION_GENERATED. Found $it, allowable values are $POSSIBLE_GENERATED_NAMES.")
throw IllegalArgumentException("Invalid option value for $OPTION_GENERATED. Found $it, " +
"allowable values are $POSSIBLE_GENERATED_NAMES.")
}
processingEnv.elementUtils.getTypeElement(it)
}

View File

@@ -31,7 +31,9 @@ import me.eugeniomarletti.kotlin.metadata.modality
import me.eugeniomarletti.kotlin.metadata.shadow.metadata.ProtoBuf.Class
import me.eugeniomarletti.kotlin.metadata.shadow.metadata.ProtoBuf.Modality.ABSTRACT
import me.eugeniomarletti.kotlin.metadata.shadow.metadata.ProtoBuf.TypeParameter
import me.eugeniomarletti.kotlin.metadata.shadow.metadata.ProtoBuf.Visibility.INTERNAL
import me.eugeniomarletti.kotlin.metadata.shadow.metadata.ProtoBuf.Visibility.LOCAL
import me.eugeniomarletti.kotlin.metadata.shadow.metadata.ProtoBuf.Visibility.PUBLIC
import me.eugeniomarletti.kotlin.metadata.shadow.metadata.deserialization.NameResolver
import me.eugeniomarletti.kotlin.metadata.shadow.util.capitalizeDecapitalize.decapitalizeAsciiOnly
import me.eugeniomarletti.kotlin.metadata.visibility
@@ -70,6 +72,11 @@ internal data class TargetType(
val proto = typeMetadata.data.classProto
when {
proto.classKind == Class.Kind.ENUM_CLASS -> {
messager.printMessage(
ERROR, "@JsonClass can't be applied to $element: must not be an enum class", element)
return null
}
proto.classKind != Class.Kind.CLASS -> {
messager.printMessage(
ERROR, "@JsonClass can't be applied to $element: must be a Kotlin class", element)
@@ -96,6 +103,12 @@ internal data class TargetType(
val appliedType = AppliedType.get(element)
val constructor = TargetConstructor.primary(typeMetadata, elements)
if (constructor.proto.visibility != INTERNAL && constructor.proto.visibility != PUBLIC) {
messager.printMessage(ERROR, "@JsonClass can't be applied to $element: " +
"primary constructor is not internal or public", element)
return null
}
val properties = mutableMapOf<String, TargetProperty>()
for (supertype in appliedType.supertypes(types)) {
if (supertype.element.asClassName() == OBJECT_CLASS) {

View File

@@ -27,7 +27,29 @@ import javax.annotation.processing.Processor
class CompilerTest {
@Rule @JvmField var temporaryFolder: TemporaryFolder = TemporaryFolder()
@Test fun privateProperty() {
@Test fun privateConstructor() {
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)
|class PrivateConstructor private constructor(var a: Int, var b: Int) {
| fun a() = a
| fun b() = b
| companion object {
| fun newInstance(a: Int, b: Int) = PrivateConstructor(a, b)
| }
|}
|""".trimMargin())
val result = call.execute()
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
assertThat(result.systemErr).contains("constructor is not internal or public")
}
@Test fun privateConstructorParameter() {
val call = KotlinCompilerCall(temporaryFolder.root)
call.inheritClasspath = true
call.addService(Processor::class, JsonClassCodeGenProcessor::class)
@@ -43,6 +65,25 @@ class CompilerTest {
assertThat(result.systemErr).contains("property a is not visible")
}
@Test fun privateProperties() {
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)
|class PrivateProperties {
| private var a: Int = -1
| private var b: Int = -1
|}
|""".trimMargin())
val result = call.execute()
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
assertThat(result.systemErr).contains("property a is not visible")
}
@Test fun interfacesNotSupported() {
val call = KotlinCompilerCall(temporaryFolder.root)
call.inheritClasspath = true
@@ -96,6 +137,25 @@ class CompilerTest {
"error: @JsonClass can't be applied to Outer.InnerClass: must not be an inner class")
}
@Test fun enumClassesNotSupported() {
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)
|enum class KotlinEnum {
| A, B
|}
|""".trimMargin())
val result = call.execute()
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
assertThat(result.systemErr).contains(
"error: @JsonClass can't be applied to KotlinEnum: must not be an enum 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
@@ -245,6 +305,24 @@ class CompilerTest {
assertThat(result.systemErr).contains("supertype java.util.Date is not a Kotlin type")
}
@Test fun extendJavaType() {
val call = KotlinCompilerCall(temporaryFolder.root)
call.inheritClasspath = true
call.addService(Processor::class, JsonClassCodeGenProcessor::class)
call.addKt("source.kt", """
|import com.squareup.moshi.JsonClass
|import com.squareup.moshi.JavaSuperclass
|
|@JsonClass(generateAdapter = true)
|class ExtendsJavaType(var b: Int) : JavaSuperclass()
|""".trimMargin())
val result = call.execute()
assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
assertThat(result.systemErr)
.contains("supertype com.squareup.moshi.JavaSuperclass is not a Kotlin type")
}
@Test
fun nonFieldApplicableQualifier() {
val call = KotlinCompilerCall(temporaryFolder.root)

View File

@@ -0,0 +1,21 @@
/*
* 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;
/** For {@link CompilerTest#extendJavaType}. */
public class JavaSuperclass {
public int a = 1;
}

View File

@@ -1,3 +1,18 @@
/*
* 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.google.common.truth.Truth.assertThat
@@ -7,7 +22,6 @@ import com.squareup.kotlinpoet.asClassName
import org.junit.Test
class TypeResolverTest {
private val resolver = TypeResolver()
@Test
@@ -32,5 +46,4 @@ class TypeResolverTest {
assertThat(resolver.resolve(nullableTypeName).nullable).isTrue()
}
}