Switch from internal to experimental internal annotation (#1410)

This commit is contained in:
Zac Sweers
2021-10-30 12:15:08 -04:00
committed by GitHub
parent 313683fa98
commit c288ad6133
11 changed files with 78 additions and 40 deletions

View File

@@ -32,6 +32,7 @@ tasks.withType<KotlinCompile>().configureEach {
"-Xopt-in=kotlin.RequiresOptIn", "-Xopt-in=kotlin.RequiresOptIn",
"-Xopt-in=com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview", "-Xopt-in=com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview",
"-Xopt-in=com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview", "-Xopt-in=com.squareup.kotlinpoet.ksp.KotlinPoetKspPreview",
"-Xopt-in=com.squareup.moshi.kotlin.codegen.api.InternalMoshiCodegenApi",
) )
} }
} }

View File

@@ -52,12 +52,13 @@ private const val TO_STRING_PREFIX = "GeneratedJsonAdapter("
private const val TO_STRING_SIZE_BASE = TO_STRING_PREFIX.length + 1 // 1 is the closing paren private const val TO_STRING_SIZE_BASE = TO_STRING_PREFIX.length + 1 // 1 is the closing paren
/** Generates a JSON adapter for a target type. */ /** Generates a JSON adapter for a target type. */
internal class AdapterGenerator( @InternalMoshiCodegenApi
public class AdapterGenerator(
private val target: TargetType, private val target: TargetType,
private val propertyList: List<PropertyGenerator> private val propertyList: List<PropertyGenerator>
) { ) {
companion object { private companion object {
private val INT_TYPE_BLOCK = CodeBlock.of("%T::class.javaPrimitiveType", INT) private val INT_TYPE_BLOCK = CodeBlock.of("%T::class.javaPrimitiveType", INT)
private val DEFAULT_CONSTRUCTOR_MARKER_TYPE_BLOCK = CodeBlock.of( private val DEFAULT_CONSTRUCTOR_MARKER_TYPE_BLOCK = CodeBlock.of(
"%T.DEFAULT_CONSTRUCTOR_MARKER", "%T.DEFAULT_CONSTRUCTOR_MARKER",
@@ -166,7 +167,7 @@ internal class AdapterGenerator(
.initializer("null") .initializer("null")
.build() .build()
fun prepare(generateProguardRules: Boolean, typeHook: (TypeSpec) -> TypeSpec = { it }): PreparedAdapter { public fun prepare(generateProguardRules: Boolean, typeHook: (TypeSpec) -> TypeSpec = { it }): PreparedAdapter {
val reservedSimpleNames = mutableSetOf<String>() val reservedSimpleNames = mutableSetOf<String>()
for (property in nonTransientProperties) { for (property in nonTransientProperties) {
// Allocate names for simple property types first to avoid collisions // Allocate names for simple property types first to avoid collisions
@@ -727,7 +728,8 @@ private fun FunSpec.Builder.addMissingPropertyCheck(property: PropertyGenerator,
} }
/** Represents a prepared adapter with its [spec] and optional associated [proguardConfig]. */ /** Represents a prepared adapter with its [spec] and optional associated [proguardConfig]. */
internal data class PreparedAdapter(val spec: FileSpec, val proguardConfig: ProguardConfig?) @InternalMoshiCodegenApi
public data class PreparedAdapter(val spec: FileSpec, val proguardConfig: ProguardConfig?)
private fun AsmType.toReflectionString(): String { private fun AsmType.toReflectionString(): String {
return when (this) { return when (this) {

View File

@@ -36,15 +36,16 @@ import com.squareup.moshi.Types
import java.util.Locale import java.util.Locale
/** A JsonAdapter that can be used to encode and decode a particular field. */ /** A JsonAdapter that can be used to encode and decode a particular field. */
internal data class DelegateKey( @InternalMoshiCodegenApi
public data class DelegateKey(
private val type: TypeName, private val type: TypeName,
private val jsonQualifiers: List<AnnotationSpec>, private val jsonQualifiers: List<AnnotationSpec>,
private val instantiateAnnotations: Boolean private val instantiateAnnotations: Boolean
) { ) {
val nullable get() = type.isNullable public val nullable: Boolean get() = type.isNullable
/** Returns an adapter to use when encoding and decoding this property. */ /** Returns an adapter to use when encoding and decoding this property. */
fun generateProperty( internal fun generateProperty(
nameAllocator: NameAllocator, nameAllocator: NameAllocator,
typeRenderer: TypeRenderer, typeRenderer: TypeRenderer,
moshiParameter: ParameterSpec, moshiParameter: ParameterSpec,

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2021 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
*
* https://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.kotlin.codegen.api
/** Internal Moshi code gen APIs. */
@MustBeDocumented
@Retention(value = AnnotationRetention.BINARY)
@RequiresOptIn(
level = RequiresOptIn.Level.WARNING,
message = "This is an internal API and may change at any time."
)
public annotation class InternalMoshiCodegenApi

View File

@@ -17,7 +17,8 @@ package com.squareup.moshi.kotlin.codegen.api
import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.ClassName
internal object Options { @InternalMoshiCodegenApi
public object Options {
/** /**
* This processing option can be specified to have a `@Generated` annotation * This processing option can be specified to have a `@Generated` annotation
* included in the generated code. It is not encouraged unless you need it for static analysis * included in the generated code. It is not encouraged unless you need it for static analysis
@@ -27,14 +28,14 @@ internal object Options {
* * `"javax.annotation.processing.Generated"` (JRE 9+) * * `"javax.annotation.processing.Generated"` (JRE 9+)
* * `"javax.annotation.Generated"` (JRE <9) * * `"javax.annotation.Generated"` (JRE <9)
*/ */
const val OPTION_GENERATED: String = "moshi.generated" public const val OPTION_GENERATED: String = "moshi.generated"
/** /**
* This boolean processing option can disable proguard rule generation. * This boolean processing option can disable proguard rule generation.
* Normally, this is not recommended unless end-users build their own JsonAdapter look-up tool. * Normally, this is not recommended unless end-users build their own JsonAdapter look-up tool.
* This is enabled by default. * This is enabled by default.
*/ */
const val OPTION_GENERATE_PROGUARD_RULES: String = "moshi.generateProguardRules" public const val OPTION_GENERATE_PROGUARD_RULES: String = "moshi.generateProguardRules"
/** /**
* This boolean processing option controls whether or not Moshi will directly instantiate * This boolean processing option controls whether or not Moshi will directly instantiate
@@ -42,9 +43,9 @@ internal object Options {
* but can be disabled to restore the legacy behavior of storing annotations on generated adapter * but can be disabled to restore the legacy behavior of storing annotations on generated adapter
* fields and looking them up reflectively. * fields and looking them up reflectively.
*/ */
const val OPTION_INSTANTIATE_ANNOTATIONS: String = "moshi.instantiateAnnotations" public const val OPTION_INSTANTIATE_ANNOTATIONS: String = "moshi.instantiateAnnotations"
val POSSIBLE_GENERATED_NAMES = arrayOf( public val POSSIBLE_GENERATED_NAMES: Map<String, ClassName> = arrayOf(
ClassName("javax.annotation.processing", "Generated"), ClassName("javax.annotation.processing", "Generated"),
ClassName("javax.annotation", "Generated") ClassName("javax.annotation", "Generated")
).associateBy { it.canonicalName } ).associateBy { it.canonicalName }

View File

@@ -29,9 +29,11 @@ import com.squareup.kotlinpoet.ClassName
* conditioned on usage of the original target type. * conditioned on usage of the original target type.
* *
* To keep this processor as an ISOLATING incremental processor, we generate one file per target * To keep this processor as an ISOLATING incremental processor, we generate one file per target
* class with a deterministic name (see [outputFile]) with an appropriate originating element. * class with a deterministic name (see [outputFilePathWithoutExtension]) with an appropriate
* originating element.
*/ */
internal data class ProguardConfig( @InternalMoshiCodegenApi
public data class ProguardConfig(
val targetClass: ClassName, val targetClass: ClassName,
val adapterName: String, val adapterName: String,
val adapterConstructorParams: List<String>, val adapterConstructorParams: List<String>,
@@ -39,11 +41,11 @@ internal data class ProguardConfig(
val targetConstructorParams: List<String>, val targetConstructorParams: List<String>,
val qualifierProperties: Set<QualifierAdapterProperty> val qualifierProperties: Set<QualifierAdapterProperty>
) { ) {
fun outputFilePathWithoutExtension(canonicalName: String): String { public fun outputFilePathWithoutExtension(canonicalName: String): String {
return "META-INF/proguard/moshi-$canonicalName" return "META-INF/proguard/moshi-$canonicalName"
} }
fun writeTo(out: Appendable): Unit = out.run { public fun writeTo(out: Appendable): Unit = out.run {
// //
// -if class {the target class} // -if class {the target class}
// -keepnames class {the target class} // -keepnames class {the target class}
@@ -112,4 +114,5 @@ internal data class ProguardConfig(
* Represents a qualified property with its [name] in the adapter fields and list of [qualifiers] * Represents a qualified property with its [name] in the adapter fields and list of [qualifiers]
* associated with it. * associated with it.
*/ */
internal data class QualifierAdapterProperty(val name: String, val qualifiers: Set<ClassName>) @InternalMoshiCodegenApi
public data class QualifierAdapterProperty(val name: String, val qualifiers: Set<ClassName>)

View File

@@ -20,21 +20,22 @@ import com.squareup.kotlinpoet.NameAllocator
import com.squareup.kotlinpoet.PropertySpec import com.squareup.kotlinpoet.PropertySpec
/** Generates functions to encode and decode a property as JSON. */ /** Generates functions to encode and decode a property as JSON. */
internal class PropertyGenerator( @InternalMoshiCodegenApi
val target: TargetProperty, public class PropertyGenerator(
val delegateKey: DelegateKey, public val target: TargetProperty,
val isTransient: Boolean = false public val delegateKey: DelegateKey,
public val isTransient: Boolean = false
) { ) {
val name = target.name public val name: String = target.name
val jsonName = target.jsonName ?: target.name public val jsonName: String = target.jsonName ?: target.name
val hasDefault = target.hasDefault public val hasDefault: Boolean = target.hasDefault
lateinit var localName: String public lateinit var localName: String
lateinit var localIsPresentName: String public lateinit var localIsPresentName: String
val isRequired get() = !delegateKey.nullable && !hasDefault public val isRequired: Boolean get() = !delegateKey.nullable && !hasDefault
val hasConstructorParameter get() = target.parameterIndex != -1 public val hasConstructorParameter: Boolean get() = target.parameterIndex != -1
/** /**
* IsPresent is required if the following conditions are met: * IsPresent is required if the following conditions are met:
@@ -46,15 +47,15 @@ internal class PropertyGenerator(
* This is used to indicate that presence should be checked first before possible assigning null * This is used to indicate that presence should be checked first before possible assigning null
* to an absent value * to an absent value
*/ */
val hasLocalIsPresentName = !isTransient && hasDefault && !hasConstructorParameter && delegateKey.nullable public val hasLocalIsPresentName: Boolean = !isTransient && hasDefault && !hasConstructorParameter && delegateKey.nullable
val hasConstructorDefault = hasDefault && hasConstructorParameter public val hasConstructorDefault: Boolean = hasDefault && hasConstructorParameter
fun allocateNames(nameAllocator: NameAllocator) { internal fun allocateNames(nameAllocator: NameAllocator) {
localName = nameAllocator.newName(name) localName = nameAllocator.newName(name)
localIsPresentName = nameAllocator.newName("${name}Set") localIsPresentName = nameAllocator.newName("${name}Set")
} }
fun generateLocalProperty(): PropertySpec { internal fun generateLocalProperty(): PropertySpec {
return PropertySpec.builder(localName, target.type.copy(nullable = true)) return PropertySpec.builder(localName, target.type.copy(nullable = true))
.mutable(true) .mutable(true)
.apply { .apply {
@@ -70,7 +71,7 @@ internal class PropertyGenerator(
.build() .build()
} }
fun generateLocalIsPresentProperty(): PropertySpec { internal fun generateLocalIsPresentProperty(): PropertySpec {
return PropertySpec.builder(localIsPresentName, BOOLEAN) return PropertySpec.builder(localIsPresentName, BOOLEAN)
.mutable(true) .mutable(true)
.initializer("false") .initializer("false")

View File

@@ -18,7 +18,8 @@ package com.squareup.moshi.kotlin.codegen.api
import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.KModifier
/** A constructor in user code that should be called by generated code. */ /** A constructor in user code that should be called by generated code. */
internal data class TargetConstructor( @InternalMoshiCodegenApi
public data class TargetConstructor(
val parameters: LinkedHashMap<String, TargetParameter>, val parameters: LinkedHashMap<String, TargetParameter>,
val visibility: KModifier, val visibility: KModifier,
val signature: String? val signature: String?

View File

@@ -19,7 +19,8 @@ import com.squareup.kotlinpoet.AnnotationSpec
import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.TypeName
/** A parameter in user code that should be populated by generated code. */ /** A parameter in user code that should be populated by generated code. */
internal data class TargetParameter( @InternalMoshiCodegenApi
public data class TargetParameter(
val name: String, val name: String,
val index: Int, val index: Int,
val type: TypeName, val type: TypeName,

View File

@@ -20,7 +20,8 @@ import com.squareup.kotlinpoet.PropertySpec
import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.TypeName
/** A property in user code that maps to JSON. */ /** A property in user code that maps to JSON. */
internal data class TargetProperty( @InternalMoshiCodegenApi
public data class TargetProperty(
val propertySpec: PropertySpec, val propertySpec: PropertySpec,
val parameter: TargetParameter?, val parameter: TargetParameter?,
val visibility: KModifier, val visibility: KModifier,
@@ -28,8 +29,8 @@ internal data class TargetProperty(
) { ) {
val name: String get() = propertySpec.name val name: String get() = propertySpec.name
val type: TypeName get() = propertySpec.type val type: TypeName get() = propertySpec.type
val parameterIndex get() = parameter?.index ?: -1 val parameterIndex: Int get() = parameter?.index ?: -1
val hasDefault get() = parameter?.hasDefault ?: true val hasDefault: Boolean get() = parameter?.hasDefault ?: true
override fun toString() = name override fun toString(): String = name
} }

View File

@@ -20,7 +20,8 @@ import com.squareup.kotlinpoet.TypeName
import com.squareup.kotlinpoet.TypeVariableName import com.squareup.kotlinpoet.TypeVariableName
/** A user type that should be decoded and encoded by generated code. */ /** A user type that should be decoded and encoded by generated code. */
internal data class TargetType( @InternalMoshiCodegenApi
public data class TargetType(
val typeName: TypeName, val typeName: TypeName,
val constructor: TargetConstructor, val constructor: TargetConstructor,
val properties: Map<String, TargetProperty>, val properties: Map<String, TargetProperty>,