Skip to content

Commit

Permalink
Ensure Kotshi runs on the oldest supported Moshi version (#284)
Browse files Browse the repository at this point in the history
  • Loading branch information
ansman authored Dec 29, 2023
1 parent f52fef4 commit 6d521ef
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 16 deletions.
13 changes: 12 additions & 1 deletion .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 38 additions & 3 deletions compiler/src/main/kotlin/se/ansman/kotshi/ksp/annotations.kt
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -24,7 +57,9 @@ fun Sequence<KSAnnotation>.getAnnotation(type: Class<out Annotation>): KSAnnotat
}

inline fun <reified V> 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 <reified V> KSAnnotation.getValueOrDefault(name: String, defaultValue: () -> V): V {
val arg = arguments.firstOrNull { it.name?.asString() == name } ?: return defaultValue()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -81,13 +92,13 @@ class DataClassAdapterGenerator(
globalConfig = globalConfig,
useAdaptersForPrimitives = annotation.getEnumValue("useAdaptersForPrimitives", PrimitiveAdapters.DEFAULT),
parameterJsonName = (getAnnotation<JsonProperty>() ?: jsonAnnotation)
?.getValue<String?>("name")
?.getValueOrDefault<String?>("name") { null }
?.takeUnless { it == JSON_UNSET_NAME },
propertyJsonName = (property.getAnnotation<JsonProperty>() ?: propertyJsonAnnotation)
?.getValue<String?>("name")
?.getValueOrDefault<String?>("name") { null }
?.takeUnless { it == JSON_UNSET_NAME },
isTransient = property.getAnnotation<Transient>() != null,
isJsonIgnore = (jsonAnnotation ?: propertyJsonAnnotation)?.getValue("ignore"),
isJsonIgnore = (jsonAnnotation ?: propertyJsonAnnotation)?.getValueOrDefault("ignore") { false },
hasDefaultValue = hasDefault,
error = { KspProcessingError(it, property) }
)
Expand Down
8 changes: 7 additions & 1 deletion gradle-plugin/src/main/kotlin/test-library.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ sourceSets {
}

tasks.withType<Test>().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",
Expand All @@ -33,7 +34,12 @@ tasks.withType<Test>().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)
}
2 changes: 2 additions & 0 deletions tests/src/test/kotlin/se/ansman/kotshi/BaseGeneratorTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<IgnoredProperties> = moshi.adapter()

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -71,13 +70,16 @@ class ManuallyRegisteredAdapterTest {
@OptIn(ExperimentalStdlibApi::class)
@Test
fun testManuallyRegisteredWrappedGenericAdapter() {
assertFailure { moshi.adapter<ManuallyRegisteredWrappedGenericAdapter.GenericType<List<Int>>>() }
.isInstanceOf<IllegalArgumentException>()
assertThat(
moshi.adapter<ManuallyRegisteredWrappedGenericAdapter.GenericType<List<String>>>(
typeOf<ManuallyRegisteredWrappedGenericAdapter.GenericType<List<String>>>().javaType
)
).isInstanceOf<ManuallyRegisteredWrappedGenericAdapter>()
if (!usingLegacyMoshi) {
// Legacy moshi doesn't throw on unsupported Kotlin types
assertFailure { moshi.adapter<ManuallyRegisteredWrappedGenericAdapter.GenericType<List<Int>>>() }
.isInstanceOf<IllegalArgumentException>()
}
}

@OptIn(ExperimentalStdlibApi::class)
Expand Down
9 changes: 9 additions & 0 deletions tests/src/test/kotlin/se/ansman/kotshi/Moshis.kt
Original file line number Diff line number Diff line change
@@ -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 <reified T : Any> Moshi.adapter(): JsonAdapter<T> = adapter(typeOf<T>().javaType)
3 changes: 3 additions & 0 deletions tests/src/test/kotlin/se/ansman/kotshi/globals.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package se.ansman.kotshi

val usingLegacyMoshi: Boolean = System.getProperty("usingLegacyMoshi")?.toBooleanStrict() ?: false

0 comments on commit 6d521ef

Please sign in to comment.