diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 944f3f1..1971e11 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -45,9 +45,20 @@ jobs: - uses: gradle/gradle-build-action@v2 with: arguments: check --continue --stacktrace -Pkotshi.useLegacyDataClassRenderer=true + testOldestSupportedMoshi: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + distribution: 'zulu' + java-version: '19' + - uses: gradle/gradle-build-action@v2 + with: + arguments: check --continue --stacktrace -Pkotshi.internal.useLegacyMoshi=true deploySnapshot: runs-on: ubuntu-latest - needs: [test, testWithAnnotations, testWithLegacyDataClassRenderer] + needs: [test, testWithAnnotations, testWithLegacyDataClassRenderer, testOldestSupportedMoshi] steps: - uses: actions/checkout@v2 - uses: actions/setup-java@v2 diff --git a/compiler/src/main/kotlin/se/ansman/kotshi/kapt/KotshiProcessor.kt b/compiler/src/main/kotlin/se/ansman/kotshi/kapt/KotshiProcessor.kt index f68353c..1534011 100644 --- a/compiler/src/main/kotlin/se/ansman/kotshi/kapt/KotshiProcessor.kt +++ b/compiler/src/main/kotlin/se/ansman/kotshi/kapt/KotshiProcessor.kt @@ -13,7 +13,11 @@ import se.ansman.kotshi.Errors import se.ansman.kotshi.Options import se.ansman.kotshi.model.GeneratedAdapter import se.ansman.kotshi.model.GeneratedAnnotation -import javax.annotation.processing.* +import javax.annotation.processing.AbstractProcessor +import javax.annotation.processing.Filer +import javax.annotation.processing.ProcessingEnvironment +import javax.annotation.processing.Processor +import javax.annotation.processing.RoundEnvironment import javax.lang.model.SourceVersion import javax.lang.model.element.Element import javax.lang.model.element.TypeElement diff --git a/compiler/src/main/kotlin/se/ansman/kotshi/ksp/annotations.kt b/compiler/src/main/kotlin/se/ansman/kotshi/ksp/annotations.kt index a29ad4e..f140a35 100644 --- a/compiler/src/main/kotlin/se/ansman/kotshi/ksp/annotations.kt +++ b/compiler/src/main/kotlin/se/ansman/kotshi/ksp/annotations.kt @@ -1,8 +1,41 @@ package se.ansman.kotshi.ksp -import com.google.devtools.ksp.symbol.* -import com.squareup.kotlinpoet.* +import com.google.devtools.ksp.symbol.ClassKind +import com.google.devtools.ksp.symbol.KSAnnotated +import com.google.devtools.ksp.symbol.KSAnnotation +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSName +import com.google.devtools.ksp.symbol.KSNode +import com.google.devtools.ksp.symbol.KSType +import com.squareup.kotlinpoet.BOOLEAN +import com.squareup.kotlinpoet.BOOLEAN_ARRAY +import com.squareup.kotlinpoet.BYTE +import com.squareup.kotlinpoet.BYTE_ARRAY +import com.squareup.kotlinpoet.CHAR +import com.squareup.kotlinpoet.CHAR_ARRAY +import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.DOUBLE +import com.squareup.kotlinpoet.DOUBLE_ARRAY +import com.squareup.kotlinpoet.FLOAT +import com.squareup.kotlinpoet.FLOAT_ARRAY +import com.squareup.kotlinpoet.INT +import com.squareup.kotlinpoet.INT_ARRAY +import com.squareup.kotlinpoet.LIST +import com.squareup.kotlinpoet.LONG +import com.squareup.kotlinpoet.LONG_ARRAY +import com.squareup.kotlinpoet.ParameterizedTypeName import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy +import com.squareup.kotlinpoet.SHORT +import com.squareup.kotlinpoet.SHORT_ARRAY +import com.squareup.kotlinpoet.TypeName +import com.squareup.kotlinpoet.U_BYTE +import com.squareup.kotlinpoet.U_BYTE_ARRAY +import com.squareup.kotlinpoet.U_INT +import com.squareup.kotlinpoet.U_INT_ARRAY +import com.squareup.kotlinpoet.U_LONG +import com.squareup.kotlinpoet.U_LONG_ARRAY +import com.squareup.kotlinpoet.U_SHORT +import com.squareup.kotlinpoet.U_SHORT_ARRAY import com.squareup.kotlinpoet.ksp.toClassName import com.squareup.kotlinpoet.ksp.toTypeName import com.squareup.moshi.JsonQualifier @@ -24,7 +57,9 @@ fun Sequence.getAnnotation(type: Class): KSAnnotat } inline fun KSAnnotation.getValue(name: String): V = - arguments.first { it.name?.asString() == name }.value as V + getValueOrDefault(name) { + throw IllegalArgumentException("Annotation ${annotationType.resolve().declaration.qualifiedName?.asString()} is missing argument $name. Arguments: ${arguments.map { it.name?.asString() }}") + } inline fun KSAnnotation.getValueOrDefault(name: String, defaultValue: () -> V): V { val arg = arguments.firstOrNull { it.name?.asString() == name } ?: return defaultValue() diff --git a/compiler/src/main/kotlin/se/ansman/kotshi/ksp/generators/DataClassAdapterGenerator.kt b/compiler/src/main/kotlin/se/ansman/kotshi/ksp/generators/DataClassAdapterGenerator.kt index 43a87d4..75354d1 100644 --- a/compiler/src/main/kotlin/se/ansman/kotshi/ksp/generators/DataClassAdapterGenerator.kt +++ b/compiler/src/main/kotlin/se/ansman/kotshi/ksp/generators/DataClassAdapterGenerator.kt @@ -11,9 +11,20 @@ import com.google.devtools.ksp.symbol.KSValueParameter import com.google.devtools.ksp.symbol.Modifier import com.squareup.kotlinpoet.ksp.toTypeName import com.squareup.moshi.Json -import se.ansman.kotshi.* +import se.ansman.kotshi.Errors import se.ansman.kotshi.Errors.privateDataClassProperty -import se.ansman.kotshi.ksp.* +import se.ansman.kotshi.ExperimentalKotshiApi +import se.ansman.kotshi.JSON_UNSET_NAME +import se.ansman.kotshi.JsonProperty +import se.ansman.kotshi.JsonSerializable +import se.ansman.kotshi.PrimitiveAdapters +import se.ansman.kotshi.SerializeNulls +import se.ansman.kotshi.ksp.KspProcessingError +import se.ansman.kotshi.ksp.getAnnotation +import se.ansman.kotshi.ksp.getEnumValue +import se.ansman.kotshi.ksp.getValueOrDefault +import se.ansman.kotshi.ksp.isJsonQualifier +import se.ansman.kotshi.ksp.toAnnotationModel import se.ansman.kotshi.model.DataClassJsonAdapter import se.ansman.kotshi.model.GeneratableJsonAdapter import se.ansman.kotshi.model.GlobalConfig @@ -81,13 +92,13 @@ class DataClassAdapterGenerator( globalConfig = globalConfig, useAdaptersForPrimitives = annotation.getEnumValue("useAdaptersForPrimitives", PrimitiveAdapters.DEFAULT), parameterJsonName = (getAnnotation() ?: jsonAnnotation) - ?.getValue("name") + ?.getValueOrDefault("name") { null } ?.takeUnless { it == JSON_UNSET_NAME }, propertyJsonName = (property.getAnnotation() ?: propertyJsonAnnotation) - ?.getValue("name") + ?.getValueOrDefault("name") { null } ?.takeUnless { it == JSON_UNSET_NAME }, isTransient = property.getAnnotation() != null, - isJsonIgnore = (jsonAnnotation ?: propertyJsonAnnotation)?.getValue("ignore"), + isJsonIgnore = (jsonAnnotation ?: propertyJsonAnnotation)?.getValueOrDefault("ignore") { false }, hasDefaultValue = hasDefault, error = { KspProcessingError(it, property) } ) diff --git a/gradle-plugin/src/main/kotlin/test-library.gradle.kts b/gradle-plugin/src/main/kotlin/test-library.gradle.kts index fdaf71b..c2b34f4 100644 --- a/gradle-plugin/src/main/kotlin/test-library.gradle.kts +++ b/gradle-plugin/src/main/kotlin/test-library.gradle.kts @@ -16,6 +16,7 @@ sourceSets { } tasks.withType().configureEach { + systemProperty("usingLegacyMoshi", providers.gradleProperty("kotshi.internal.useLegacyMoshi").orElse("false").get()) jvmArgs( "--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", "--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", @@ -33,7 +34,12 @@ tasks.withType().configureEach { dependencies { implementation(project(":api")) implementation(project(":compiler")) - implementation(libs.moshi.current) + if (providers.gradleProperty("kotshi.internal.useLegacyMoshi").orNull?.toBooleanStrict() == true) { + compileOnly(libs.moshi.current) + testImplementation(libs.moshi.oldestSupported) + } else { + implementation(libs.moshi.current) + } compileOnly(libs.findBugs) testImplementation(libs.compileTesting.core) } \ No newline at end of file diff --git a/tests/src/test/kotlin/se/ansman/kotshi/BaseGeneratorTest.kt b/tests/src/test/kotlin/se/ansman/kotshi/BaseGeneratorTest.kt index 6b450a4..f8aeb8a 100644 --- a/tests/src/test/kotlin/se/ansman/kotshi/BaseGeneratorTest.kt +++ b/tests/src/test/kotlin/se/ansman/kotshi/BaseGeneratorTest.kt @@ -78,6 +78,7 @@ abstract class BaseGeneratorTest { @Test fun `ignored data class properties must have default values`() { + if (usingLegacyMoshi) return val result = compile(kotlin("source.kt", """ @se.ansman.kotshi.JsonSerializable data class Foo(@com.squareup.moshi.Json(ignore = true) val property: String) @@ -88,6 +89,7 @@ abstract class BaseGeneratorTest { @Test fun `non ignored data class properties must not be transient`() { + if (usingLegacyMoshi) return val result = compile(kotlin("source.kt", """ @se.ansman.kotshi.JsonSerializable data class Foo(@com.squareup.moshi.Json(ignore = false) @Transient val property: String) diff --git a/tests/src/test/kotlin/se/ansman/kotshi/IgnoredPropertiesTest.kt b/tests/src/test/kotlin/se/ansman/kotshi/IgnoredPropertiesTest.kt index 2251849..85c416a 100644 --- a/tests/src/test/kotlin/se/ansman/kotshi/IgnoredPropertiesTest.kt +++ b/tests/src/test/kotlin/se/ansman/kotshi/IgnoredPropertiesTest.kt @@ -4,12 +4,10 @@ import assertk.assertThat import assertk.assertions.isEqualTo import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Moshi -import com.squareup.moshi.adapter import org.junit.jupiter.api.Test class IgnoredPropertiesTest { private val moshi = Moshi.Builder().add(TestFactory).build() - @OptIn(ExperimentalStdlibApi::class) private val adapter: JsonAdapter = moshi.adapter() @Test diff --git a/tests/src/test/kotlin/se/ansman/kotshi/ManuallyRegisteredAdapterTest.kt b/tests/src/test/kotlin/se/ansman/kotshi/ManuallyRegisteredAdapterTest.kt index c27077c..db24f50 100644 --- a/tests/src/test/kotlin/se/ansman/kotshi/ManuallyRegisteredAdapterTest.kt +++ b/tests/src/test/kotlin/se/ansman/kotshi/ManuallyRegisteredAdapterTest.kt @@ -7,7 +7,6 @@ import assertk.assertions.isInstanceOf import assertk.assertions.isNotInstanceOf import assertk.assertions.isSameInstanceAs import com.squareup.moshi.Moshi -import com.squareup.moshi.adapter import org.junit.jupiter.api.Test import kotlin.reflect.javaType import kotlin.reflect.typeOf @@ -71,13 +70,16 @@ class ManuallyRegisteredAdapterTest { @OptIn(ExperimentalStdlibApi::class) @Test fun testManuallyRegisteredWrappedGenericAdapter() { - assertFailure { moshi.adapter>>() } - .isInstanceOf() assertThat( moshi.adapter>>( typeOf>>().javaType ) ).isInstanceOf() + if (!usingLegacyMoshi) { + // Legacy moshi doesn't throw on unsupported Kotlin types + assertFailure { moshi.adapter>>() } + .isInstanceOf() + } } @OptIn(ExperimentalStdlibApi::class) diff --git a/tests/src/test/kotlin/se/ansman/kotshi/Moshis.kt b/tests/src/test/kotlin/se/ansman/kotshi/Moshis.kt new file mode 100644 index 0000000..c50c6fd --- /dev/null +++ b/tests/src/test/kotlin/se/ansman/kotshi/Moshis.kt @@ -0,0 +1,9 @@ +package se.ansman.kotshi + +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.Moshi +import kotlin.reflect.javaType +import kotlin.reflect.typeOf + +@OptIn(ExperimentalStdlibApi::class) +inline fun Moshi.adapter(): JsonAdapter = adapter(typeOf().javaType) \ No newline at end of file diff --git a/tests/src/test/kotlin/se/ansman/kotshi/globals.kt b/tests/src/test/kotlin/se/ansman/kotshi/globals.kt new file mode 100644 index 0000000..a996353 --- /dev/null +++ b/tests/src/test/kotlin/se/ansman/kotshi/globals.kt @@ -0,0 +1,3 @@ +package se.ansman.kotshi + +val usingLegacyMoshi: Boolean = System.getProperty("usingLegacyMoshi")?.toBooleanStrict() ?: false \ No newline at end of file