Skip to content

Commit

Permalink
Merge pull request #126 from ProjectMapK/fix/param-info
Browse files Browse the repository at this point in the history
Fixed KotrinFallbackAnnotationIntrospector processing to be independent of ValueCreator/ValueParameter
  • Loading branch information
k163377 authored Aug 5, 2023
2 parents 985283f + baa6a99 commit b41da2f
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ import io.github.projectmapk.jackson.module.kogera.ReflectionCache
import io.github.projectmapk.jackson.module.kogera.deser.CollectionValueStrictNullChecksConverter
import io.github.projectmapk.jackson.module.kogera.deser.MapValueStrictNullChecksConverter
import io.github.projectmapk.jackson.module.kogera.deser.ValueClassUnboxConverter
import io.github.projectmapk.jackson.module.kogera.deser.value_instantiator.creator.ValueParameter
import io.github.projectmapk.jackson.module.kogera.isNullable
import io.github.projectmapk.jackson.module.kogera.isUnboxableValueClass
import io.github.projectmapk.jackson.module.kogera.reconstructClassOrNull
import io.github.projectmapk.jackson.module.kogera.ser.SequenceToIteratorConverter
import io.github.projectmapk.jackson.module.kogera.toSignature
import kotlinx.metadata.KmTypeProjection
import kotlinx.metadata.KmValueParameter
import kotlinx.metadata.jvm.fieldSignature
import kotlinx.metadata.jvm.setterSignature
import java.lang.reflect.Constructor
import java.lang.reflect.Executable
import java.lang.reflect.Method
import java.lang.reflect.Modifier

Expand All @@ -36,28 +36,29 @@ internal class KotlinFallbackAnnotationIntrospector(
private val strictNullChecks: Boolean,
private val cache: ReflectionCache
) : NopAnnotationIntrospector() {
private fun findKotlinParameter(param: AnnotatedParameter): KmValueParameter? =
when (val owner = param.owner.member) {
is Constructor<*> -> cache.getJmClass(param.declaringClass)?.findKmConstructor(owner)?.valueParameters
is Method ->
owner.takeIf { _ -> Modifier.isStatic(owner.modifiers) }
?.let { _ ->
val companion = cache.getJmClass(param.declaringClass)?.companion ?: return@let null
companion.findFunctionByMethod(owner)?.valueParameters
}
else -> null
}?.let { it[param.index] }

// since 2.4
override fun findImplicitPropertyName(member: AnnotatedMember): String? = when (member) {
is AnnotatedMethod -> if (member.parameterCount == 0) {
cache.getJmClass(member.declaringClass)?.findPropertyByGetter(member.annotated)?.name
} else {
null
}
is AnnotatedParameter -> findKotlinParameterName(member)
is AnnotatedParameter -> findKotlinParameter(member)?.name
else -> null
}

private fun findKotlinParameterName(param: AnnotatedParameter): String? = when (val owner = param.owner.member) {
is Constructor<*> -> cache.getJmClass(param.declaringClass)?.findKmConstructor(owner)?.valueParameters
is Method ->
owner.takeIf { _ -> Modifier.isStatic(owner.modifiers) }
?.let { _ ->
val companion = cache.getJmClass(param.declaringClass)?.companion ?: return@let null
companion.findFunctionByMethod(owner)?.valueParameters
}
else -> null
}?.let { it[param.index].name }

// If it is not a property on Kotlin, it is not used to ser/deserialization
override fun findPropertyAccess(ann: Annotated): JsonProperty.Access? = (ann as? AnnotatedMethod)?.let { _ ->
cache.getJmClass(ann.declaringClass)?.let { jmClass ->
Expand All @@ -75,12 +76,9 @@ internal class KotlinFallbackAnnotationIntrospector(
}
}

private fun getValueParameter(a: AnnotatedParameter): ValueParameter? =
cache.valueCreatorFromJava(a.owner.annotated as Executable)?.let { it.valueParameters[a.index] }

// returns Converter when the argument on Java is an unboxed value class
override fun findDeserializationConverter(a: Annotated): Any? = (a as? AnnotatedParameter)?.let { param ->
getValueParameter(param)?.let { valueParameter ->
findKotlinParameter(param)?.let { valueParameter ->
val rawType = a.rawType

valueParameter.createValueClassUnboxConverterOrNull(rawType) ?: run {
Expand Down Expand Up @@ -166,17 +164,18 @@ internal object ClosedRangeHelpers {
}
}

private fun ValueParameter.createValueClassUnboxConverterOrNull(rawType: Class<*>): ValueClassUnboxConverter<*>? {
private fun KmValueParameter.createValueClassUnboxConverterOrNull(rawType: Class<*>): ValueClassUnboxConverter<*>? {
return type.reconstructClassOrNull()
?.takeIf { it.isUnboxableValueClass() && it != rawType }
?.let { ValueClassUnboxConverter(it) }
}

// If the collection type argument cannot be obtained, treat it as nullable
// @see io.github.projectmapk.jackson.module.kogera._ported.test.StrictNullChecksTest#testListOfGenericWithNullValue
private fun ValueParameter.isNullishTypeAt(index: Int) = arguments.getOrNull(index)?.isNullable ?: true
private fun KmValueParameter.isNullishTypeAt(index: Int): Boolean = type.arguments.getOrNull(index)?.let {
// If it is not a StarProjection, type is not null
it === KmTypeProjection.STAR || it.type!!.isNullable()
} ?: true // If a type argument cannot be taken, treat it as nullable to avoid unexpected failure.

private fun ValueParameter.createStrictNullChecksConverterOrNull(type: JavaType): Converter<*, *>? {
private fun KmValueParameter.createStrictNullChecksConverterOrNull(type: JavaType): Converter<*, *>? {
return when {
type.isArrayType && !this.isNullishTypeAt(0) ->
CollectionValueStrictNullChecksConverter.ForArray(type, this.name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,16 @@ import io.github.projectmapk.jackson.module.kogera.isNullable
import kotlinx.metadata.Flag
import kotlinx.metadata.KmClassifier
import kotlinx.metadata.KmType
import kotlinx.metadata.KmTypeProjection
import kotlinx.metadata.KmValueParameter

internal class ValueParameter(private val param: KmValueParameter) {
internal sealed interface Argument {
val isNullable: Boolean
val name: String?

object Star : Argument {
override val isNullable: Boolean = true
override val name: String? = null
}

class ArgumentImpl(type: KmType) : Argument {
override val isNullable: Boolean = type.isNullable()

// TODO: Formatting because it is a minimal display about the error content
override val name: String = type.classifier.toString()
}
}

internal class ValueParameter(param: KmValueParameter) {
val name: String = param.name
val type: KmType = param.type
val isOptional: Boolean = Flag.ValueParameter.DECLARES_DEFAULT_VALUE(param.flags)
val isPrimitive: Boolean = Flag.IS_PRIVATE(param.type.flags)
val isNullable: Boolean = type.isNullable()
val isGenericType: Boolean = param.type.classifier is KmClassifier.TypeParameter

val arguments: List<Argument> by lazy {
param.type.arguments.map {
if (it === KmTypeProjection.STAR) {
Argument.Star
} else {
// If it is not a StarProjection, type is not null
Argument.ArgumentImpl(it.type!!)
}
}
}

// TODO: Formatting into a form that is easy to understand as an error message with reference to KParameter
override fun toString() = "parameter name: ${param.name} parameter type: ${param.type.classifier}"
override fun toString() = "parameter name: $name parameter type: ${type.classifier}"
}

0 comments on commit b41da2f

Please sign in to comment.