Fail on sealed classes in KotlinJsonAdapterFactory and code gen (#914)

Resolves #906
This commit is contained in:
Zac Sweers
2019-09-12 20:38:46 -04:00
committed by GitHub
parent a67b4d6a72
commit dd0e3807d3
4 changed files with 41 additions and 0 deletions

View File

@@ -57,6 +57,7 @@ import me.eugeniomarletti.kotlin.metadata.kotlinMetadata
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.Modality.SEALED
import me.eugeniomarletti.kotlin.metadata.shadow.metadata.ProtoBuf.Type
import me.eugeniomarletti.kotlin.metadata.shadow.metadata.ProtoBuf.TypeParameter
import me.eugeniomarletti.kotlin.metadata.shadow.metadata.ProtoBuf.TypeParameter.Variance
@@ -277,6 +278,11 @@ internal fun targetType(messager: Messager,
ERROR, "@JsonClass can't be applied to $element: must not be an inner class", element)
return null
}
proto.modality == SEALED -> {
messager.printMessage(
ERROR, "@JsonClass can't be applied to $element: must not be sealed", element)
return null
}
proto.modality == ABSTRACT -> {
messager.printMessage(
ERROR, "@JsonClass can't be applied to $element: must not be abstract", element)

View File

@@ -118,6 +118,23 @@ class JsonClassCodegenProcessorTest {
"error: @JsonClass can't be applied to AbstractClass: must not be abstract")
}
@Test fun sealedClassesNotSupported() {
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)
|sealed class SealedClass(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 SealedClass: must not be sealed")
}
@Test fun innerClassesNotSupported() {
val call = KotlinCompilerCall(temporaryFolder.root)
call.inheritClasspath = true

View File

@@ -202,6 +202,9 @@ class KotlinJsonAdapterFactory : JsonAdapter.Factory {
require(rawTypeKotlin.objectInstance == null) {
"Cannot serialize object declaration ${rawType.name}"
}
require(!rawTypeKotlin.isSealed) {
"Cannot reflectively serialize sealed class ${rawType.name}. Please register an adapter."
}
val constructor = rawTypeKotlin.primaryConstructor ?: return null
val parametersByName = constructor.parameters.associateBy { it.name }

View File

@@ -1113,6 +1113,21 @@ class KotlinJsonAdapterTest {
@JvmSuppressWildcards(suppress = false)
data class MapOfStringToClassCodegen(val map: Map<String, ConstructorParameters> = mapOf())
@Test fun sealedClassesAreRejected() {
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
try {
moshi.adapter<SealedClass>()
fail()
} catch (e: IllegalArgumentException) {
assertThat(e).hasMessageContaining("Cannot reflectively serialize sealed class")
}
}
sealed class SealedClass
private fun <T> mapWildcardsParameterizedTest(type: Class<T>, json: String, value: T) {
// Ensure the map was created with the expected wildcards of a Kotlin map.
val fieldType = type.getDeclaredField("map").genericType