Skip to content

Commit 0f8c5fc

Browse files
authored
Merge pull request #234 from ProjectMapK/reduce-props
Reduce the amount of information that continues to be held in memory
2 parents f572264 + 685c589 commit 0f8c5fc

File tree

17 files changed

+170
-101
lines changed

17 files changed

+170
-101
lines changed

src/main/kotlin/io/github/projectmapk/jackson/module/kogera/InternalCommons.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import io.github.projectmapk.jackson.module.kogera.annotation.JsonKUnbox
66
import kotlinx.metadata.KmClass
77
import kotlinx.metadata.KmClassifier
88
import kotlinx.metadata.KmType
9-
import kotlinx.metadata.isNullable
109
import kotlinx.metadata.jvm.JvmMethodSignature
1110
import kotlinx.metadata.jvm.KotlinClassMetadata
1211
import java.lang.reflect.AnnotatedElement
@@ -22,9 +21,6 @@ internal fun Class<*>.toKmClass(): KmClass? = getAnnotation(METADATA_CLASS)?.let
2221

2322
internal fun Class<*>.isUnboxableValueClass() = this.isAnnotationPresent(JVM_INLINE_CLASS)
2423

25-
// JmClass must be value class.
26-
internal fun JmClass.wrapsNullValueClass() = inlineClassUnderlyingType!!.isNullable
27-
2824
private val primitiveClassToDesc = mapOf(
2925
Byte::class.java to 'B',
3026
Char::class.java to 'C',
@@ -87,8 +83,9 @@ internal fun String.reconstructClass(): Class<*> {
8783
return Class.forName(String(replaced))
8884
}
8985

90-
internal fun KmType.reconstructClassOrNull(): Class<*>? = (classifier as? KmClassifier.Class)
91-
?.let { kotlin.runCatching { it.name.reconstructClass() }.getOrNull() }
86+
internal fun KmType.reconstructClassOrNull(): Class<*>? = (classifier as? KmClassifier.Class)?.reconstructClassOrNull()
87+
internal fun KmClassifier.Class.reconstructClassOrNull(): Class<*>? =
88+
runCatching { name.reconstructClass() }.getOrNull()
9289

9390
internal fun AnnotatedElement.hasCreatorAnnotation(): Boolean = getAnnotation(JSON_CREATOR_CLASS)
9491
?.let { it.mode != JsonCreator.Mode.DISABLED }

src/main/kotlin/io/github/projectmapk/jackson/module/kogera/ReflectionCache.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.github.projectmapk.jackson.module.kogera
22

33
import com.fasterxml.jackson.databind.util.LRUMap
4+
import io.github.projectmapk.jackson.module.kogera.jmClass.JmClass
45
import java.io.Serializable
56
import java.lang.reflect.Method
67
import java.util.Optional

src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinFallbackAnnotationIntrospector.kt

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,11 @@ import io.github.projectmapk.jackson.module.kogera.JSON_K_UNBOX_CLASS
1616
import io.github.projectmapk.jackson.module.kogera.KOTLIN_DURATION_CLASS
1717
import io.github.projectmapk.jackson.module.kogera.ReflectionCache
1818
import io.github.projectmapk.jackson.module.kogera.isUnboxableValueClass
19-
import io.github.projectmapk.jackson.module.kogera.reconstructClassOrNull
19+
import io.github.projectmapk.jackson.module.kogera.jmClass.JmValueParameter
2020
import io.github.projectmapk.jackson.module.kogera.ser.KotlinDurationValueToJavaDurationConverter
2121
import io.github.projectmapk.jackson.module.kogera.ser.KotlinToJavaDurationConverter
2222
import io.github.projectmapk.jackson.module.kogera.ser.SequenceToIteratorConverter
23-
import io.github.projectmapk.jackson.module.kogera.wrapsNullValueClass
2423
import kotlinx.metadata.KmTypeProjection
25-
import kotlinx.metadata.KmValueParameter
2624
import kotlinx.metadata.isNullable
2725
import java.lang.reflect.Constructor
2826
import java.lang.reflect.Method
@@ -36,9 +34,9 @@ internal class KotlinFallbackAnnotationIntrospector(
3634
private val useJavaDurationConversion: Boolean,
3735
private val cache: ReflectionCache
3836
) : NopAnnotationIntrospector() {
39-
private fun findKotlinParameter(param: AnnotatedParameter): KmValueParameter? =
37+
private fun findKotlinParameter(param: AnnotatedParameter): JmValueParameter? =
4038
when (val owner = param.owner.member) {
41-
is Constructor<*> -> cache.getJmClass(param.declaringClass)?.findKmConstructor(owner)?.valueParameters
39+
is Constructor<*> -> cache.getJmClass(param.declaringClass)?.findJmConstructor(owner)?.valueParameters
4240
is Method -> if (Modifier.isStatic(owner.modifiers)) {
4341
cache.getJmClass(param.declaringClass)
4442
?.companion
@@ -49,7 +47,7 @@ internal class KotlinFallbackAnnotationIntrospector(
4947
else -> null
5048
}?.let { it[param.index] }
5149

52-
private fun findKotlinParameter(param: Annotated): KmValueParameter? =
50+
private fun findKotlinParameter(param: Annotated): JmValueParameter? =
5351
(param as? AnnotatedParameter)?.let { findKotlinParameter(it) }
5452

5553
// since 2.4
@@ -66,7 +64,7 @@ internal class KotlinFallbackAnnotationIntrospector(
6664
override fun refineDeserializationType(config: MapperConfig<*>, a: Annotated, baseType: JavaType): JavaType =
6765
findKotlinParameter(a)?.let { param ->
6866
val rawType = a.rawType
69-
param.type.reconstructClassOrNull()
67+
param.reconstructedClassOrNull
7068
?.takeIf { it.isUnboxableValueClass() && it != rawType }
7169
?.let { config.constructType(it) }
7270
} ?: baseType
@@ -101,7 +99,7 @@ internal class KotlinFallbackAnnotationIntrospector(
10199

102100
// Determine if the unbox result of value class is nullable
103101
// @see findNullSerializer
104-
private fun Class<*>.requireRebox(): Boolean = cache.getJmClass(this)!!.wrapsNullValueClass()
102+
private fun Class<*>.requireRebox(): Boolean = cache.getJmClass(this)!!.wrapsNullableIfValue
105103

106104
// Perform proper serialization even if the value wrapped by the value class is null.
107105
// If value is a non-null object type, it must not be reboxing.
@@ -124,11 +122,11 @@ internal class KotlinFallbackAnnotationIntrospector(
124122
?: super.findSetterInfo(ann)
125123
}
126124

127-
private fun KmValueParameter.isNullishTypeAt(index: Int): Boolean = type.arguments.getOrNull(index)?.let {
125+
private fun JmValueParameter.isNullishTypeAt(index: Int): Boolean = arguments.getOrNull(index)?.let {
128126
// If it is not a StarProjection, type is not null
129127
it === KmTypeProjection.STAR || it.type!!.isNullable
130128
} ?: true // If a type argument cannot be taken, treat it as nullable to avoid unexpected failure.
131129

132-
private fun KmValueParameter.requireStrictNullCheck(type: JavaType): Boolean =
130+
private fun JmValueParameter.requireStrictNullCheck(type: JavaType): Boolean =
133131
((type.isArrayType || type.isCollectionLikeType) && !this.isNullishTypeAt(0)) ||
134132
(type.isMapLikeType && !this.isNullishTypeAt(1))

src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinPrimaryAnnotationIntrospector.kt

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,15 @@ import com.fasterxml.jackson.databind.introspect.AnnotatedParameter
1313
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector
1414
import com.fasterxml.jackson.databind.jsontype.NamedType
1515
import io.github.projectmapk.jackson.module.kogera.JSON_PROPERTY_CLASS
16-
import io.github.projectmapk.jackson.module.kogera.JmClass
1716
import io.github.projectmapk.jackson.module.kogera.ReflectionCache
1817
import io.github.projectmapk.jackson.module.kogera.hasCreatorAnnotation
18+
import io.github.projectmapk.jackson.module.kogera.jmClass.JmClass
19+
import io.github.projectmapk.jackson.module.kogera.jmClass.JmProperty
20+
import io.github.projectmapk.jackson.module.kogera.jmClass.JmValueParameter
1921
import io.github.projectmapk.jackson.module.kogera.reconstructClass
2022
import io.github.projectmapk.jackson.module.kogera.toSignature
2123
import kotlinx.metadata.KmClassifier
22-
import kotlinx.metadata.KmProperty
23-
import kotlinx.metadata.KmValueParameter
24-
import kotlinx.metadata.declaresDefaultValue
2524
import kotlinx.metadata.isNullable
26-
import kotlinx.metadata.isSecondary
27-
import kotlinx.metadata.jvm.getterSignature
28-
import kotlinx.metadata.jvm.setterSignature
29-
import kotlinx.metadata.jvm.signature
3025
import java.lang.reflect.Constructor
3126
import java.lang.reflect.Executable
3227
import java.lang.reflect.Method
@@ -71,11 +66,11 @@ internal class KotlinPrimaryAnnotationIntrospector(
7166
// only a check for the existence of a getter is performed.
7267
// https://youtrack.jetbrains.com/issue/KT-6519
7368
?.let {
74-
if (it.getterSignature == null) !(it.returnType.isNullable || type.hasDefaultEmptyValue()) else null
69+
if (it.getterName == null) !(it.returnType.isNullable || type.hasDefaultEmptyValue()) else null
7570
}
7671
}
7772

78-
private fun KmProperty.isRequiredByNullability(): Boolean = !this.returnType.isNullable
73+
private fun JmProperty.isRequiredByNullability(): Boolean = !this.returnType.isNullable
7974

8075
private fun AnnotatedMethod.getRequiredMarkerFromCorrespondingAccessor(jmClass: JmClass): Boolean? =
8176
when (parameterCount) {
@@ -93,19 +88,19 @@ internal class KotlinPrimaryAnnotationIntrospector(
9388

9489
private fun AnnotatedParameter.hasRequiredMarker(jmClass: JmClass): Boolean? {
9590
val paramDef = when (val member = member) {
96-
is Constructor<*> -> jmClass.findKmConstructor(member)?.valueParameters
91+
is Constructor<*> -> jmClass.findJmConstructor(member)?.valueParameters
9792
is Method -> jmClass.companion?.findFunctionByMethod(member)?.valueParameters
9893
else -> null
9994
}?.let { it[index] } ?: return null // Return null if function on Kotlin cannot be determined
10095

10196
// non required if...
10297
return when {
10398
// Argument definition is nullable
104-
paramDef.type.isNullable -> false
99+
paramDef.isNullable -> false
105100
// Default argument are defined
106-
paramDef.declaresDefaultValue -> false
101+
paramDef.isOptional -> false
107102
// vararg is treated as an empty array because undefined input is allowed
108-
paramDef.varargElementType != null -> false
103+
paramDef.isVararg -> false
109104
// The conversion in case of null is defined.
110105
type.hasDefaultEmptyValue() -> false
111106
else -> true
@@ -141,18 +136,18 @@ internal class KotlinPrimaryAnnotationIntrospector(
141136
}
142137
}
143138

144-
private fun Constructor<*>.isPrimarilyConstructorOf(jmClass: JmClass): Boolean = jmClass.findKmConstructor(this)
139+
private fun Constructor<*>.isPrimarilyConstructorOf(jmClass: JmClass): Boolean = jmClass.findJmConstructor(this)
145140
?.let { !it.isSecondary || jmClass.constructors.size == 1 }
146141
?: false
147142

148143
private fun KmClassifier.isString(): Boolean = this is KmClassifier.Class && this.name == "kotlin/String"
149144

150145
private fun isPossibleSingleString(
151-
kotlinParams: List<KmValueParameter>,
146+
kotlinParams: List<JmValueParameter>,
152147
javaFunction: Executable,
153148
propertyNames: Set<String>
154149
): Boolean = kotlinParams.size == 1 &&
155-
kotlinParams[0].let { it.name !in propertyNames && it.type.classifier.isString() } &&
150+
kotlinParams[0].let { it.name !in propertyNames && it.isString } &&
156151
javaFunction.parameters[0].annotations.none { it is JsonProperty }
157152

158153
private fun hasCreatorConstructor(clazz: Class<*>, jmClass: JmClass, propertyNames: Set<String>): Boolean {

src/main/kotlin/io/github/projectmapk/jackson/module/kogera/deser/deserializers/KotlinDeserializers.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import com.fasterxml.jackson.databind.JsonDeserializer
99
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
1010
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException
1111
import com.fasterxml.jackson.databind.module.SimpleDeserializers
12-
import io.github.projectmapk.jackson.module.kogera.JmClass
1312
import io.github.projectmapk.jackson.module.kogera.KotlinDuration
1413
import io.github.projectmapk.jackson.module.kogera.ReflectionCache
1514
import io.github.projectmapk.jackson.module.kogera.ValueClassBoxConverter
1615
import io.github.projectmapk.jackson.module.kogera.deser.JavaToKotlinDurationConverter
1716
import io.github.projectmapk.jackson.module.kogera.deser.WrapsNullableValueClassDeserializer
1817
import io.github.projectmapk.jackson.module.kogera.hasCreatorAnnotation
1918
import io.github.projectmapk.jackson.module.kogera.isUnboxableValueClass
19+
import io.github.projectmapk.jackson.module.kogera.jmClass.JmClass
2020
import io.github.projectmapk.jackson.module.kogera.toSignature
2121
import kotlinx.metadata.isSecondary
2222
import kotlinx.metadata.jvm.signature

src/main/kotlin/io/github/projectmapk/jackson/module/kogera/deser/valueInstantiator/KotlinValueInstantiator.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import io.github.projectmapk.jackson.module.kogera.deser.WrapsNullableValueClass
1818
import io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.creator.ConstructorValueCreator
1919
import io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.creator.MethodValueCreator
2020
import io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.creator.ValueCreator
21-
import io.github.projectmapk.jackson.module.kogera.wrapsNullValueClass
2221
import java.lang.reflect.Constructor
2322
import java.lang.reflect.Executable
2423
import java.lang.reflect.Method
@@ -48,7 +47,7 @@ internal class KotlinValueInstantiator(
4847
valueDeserializer: JsonDeserializer<*>?
4948
): Boolean = !isNullableParam &&
5049
valueDeserializer is WrapsNullableValueClassDeserializer<*> &&
51-
cache.getJmClass(valueDeserializer.handledType())!!.wrapsNullValueClass()
50+
cache.getJmClass(valueDeserializer.handledType())!!.wrapsNullableIfValue
5251

5352
private val valueCreator: ValueCreator<*>? by ReflectProperties.lazySoft {
5453
val creator = _withArgsCreator.annotated as Executable

src/main/kotlin/io/github/projectmapk/jackson/module/kogera/deser/valueInstantiator/argumentBucket/ArgumentBucket.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.argu
22

33
import io.github.projectmapk.jackson.module.kogera.ValueClassUnboxConverter
44
import io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.calcMaskSize
5-
import io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.creator.ValueParameter
5+
import io.github.projectmapk.jackson.module.kogera.jmClass.JmValueParameter
66
import java.lang.reflect.Array as ReflectArray
77

88
private fun defaultPrimitiveValue(type: Class<*>): Any = when (type) {
@@ -47,7 +47,7 @@ private fun IntArray.update(index: Int, operation: MaskOperation) {
4747
// @see https://github.com/JetBrains/kotlin/blob/4c925d05883a8073e6732bca95bf575beb031a59/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt#L114
4848
internal class BucketGenerator(
4949
parameterTypes: List<Class<*>>,
50-
valueParameters: List<ValueParameter>,
50+
valueParameters: List<JmValueParameter>,
5151
private val converters: List<ValueClassUnboxConverter<Any>?>
5252
) {
5353
private val valueParameterSize: Int = parameterTypes.size

src/main/kotlin/io/github/projectmapk/jackson/module/kogera/deser/valueInstantiator/creator/ConstructorValueCreator.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.creator
22

3-
import io.github.projectmapk.jackson.module.kogera.JmClass
43
import io.github.projectmapk.jackson.module.kogera.ReflectionCache
54
import io.github.projectmapk.jackson.module.kogera.call
65
import io.github.projectmapk.jackson.module.kogera.defaultConstructorMarker
76
import io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.argumentBucket.ArgumentBucket
87
import io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.argumentBucket.BucketGenerator
98
import io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.calcMaskSize
109
import io.github.projectmapk.jackson.module.kogera.getDeclaredConstructorBy
10+
import io.github.projectmapk.jackson.module.kogera.jmClass.JmClass
11+
import io.github.projectmapk.jackson.module.kogera.jmClass.JmValueParameter
1112
import java.lang.reflect.Constructor
1213

1314
internal class ConstructorValueCreator<T : Any>(
@@ -19,21 +20,19 @@ internal class ConstructorValueCreator<T : Any>(
1920

2021
override val isAccessible: Boolean = constructor.isAccessible
2122
override val callableName: String = constructor.name
22-
override val valueParameters: List<ValueParameter>
23+
override val valueParameters: List<JmValueParameter>
2324
override val bucketGenerator: BucketGenerator
2425

2526
init {
2627
// To prevent the call from failing, save the initial value and then rewrite the flag.
2728
if (!isAccessible) constructor.isAccessible = true
2829

29-
val constructorParameters = declaringJmClass.findKmConstructor(constructor)!!.valueParameters
30-
31-
valueParameters = constructorParameters.map { ValueParameter(it) }
30+
valueParameters = declaringJmClass.findJmConstructor(constructor)!!.valueParameters
3231
val rawTypes = constructor.parameterTypes.asList()
3332
bucketGenerator = BucketGenerator(
3433
rawTypes,
3534
valueParameters,
36-
constructorParameters.mapToConverters(rawTypes, cache)
35+
valueParameters.mapToConverters(rawTypes, cache)
3736
)
3837
}
3938

src/main/kotlin/io/github/projectmapk/jackson/module/kogera/deser/valueInstantiator/creator/MethodValueCreator.kt

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.creator
22

33
import io.github.projectmapk.jackson.module.kogera.ANY_CLASS
4-
import io.github.projectmapk.jackson.module.kogera.JmClass
54
import io.github.projectmapk.jackson.module.kogera.ReflectionCache
65
import io.github.projectmapk.jackson.module.kogera.call
76
import io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.argumentBucket.ArgumentBucket
87
import io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.argumentBucket.BucketGenerator
98
import io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.calcMaskSize
109
import io.github.projectmapk.jackson.module.kogera.getDeclaredMethodBy
11-
import kotlinx.metadata.KmFunction
10+
import io.github.projectmapk.jackson.module.kogera.jmClass.JmClass
11+
import io.github.projectmapk.jackson.module.kogera.jmClass.JmValueParameter
1212
import java.lang.reflect.Method
1313

1414
internal class MethodValueCreator<T>(
@@ -19,22 +19,21 @@ internal class MethodValueCreator<T>(
1919
private val companion: JmClass.CompanionObject = declaringJmClass.companion!!
2020
override val isAccessible: Boolean = method.isAccessible && companion.isAccessible
2121
override val callableName: String = method.name
22-
override val valueParameters: List<ValueParameter>
22+
override val valueParameters: List<JmValueParameter>
2323
override val bucketGenerator: BucketGenerator
2424

2525
init {
2626
// To prevent the call from failing, save the initial value and then rewrite the flag.
2727
if (!method.isAccessible) method.isAccessible = true
2828

29-
val kmFunction: KmFunction = companion.findFunctionByMethod(method)!!
30-
val kmParameters = kmFunction.valueParameters
29+
val function = companion.findFunctionByMethod(method)!!
3130

32-
valueParameters = kmParameters.map { ValueParameter(it) }
31+
valueParameters = function.valueParameters
3332
val rawTypes = method.parameterTypes.asList()
3433
bucketGenerator = BucketGenerator(
3534
rawTypes,
3635
valueParameters,
37-
kmParameters.mapToConverters(rawTypes, cache)
36+
valueParameters.mapToConverters(rawTypes, cache)
3837
)
3938
}
4039

src/main/kotlin/io/github/projectmapk/jackson/module/kogera/deser/valueInstantiator/creator/ValueCreator.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ import io.github.projectmapk.jackson.module.kogera.ValueClassUnboxConverter
77
import io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.argumentBucket.ArgumentBucket
88
import io.github.projectmapk.jackson.module.kogera.deser.valueInstantiator.argumentBucket.BucketGenerator
99
import io.github.projectmapk.jackson.module.kogera.isUnboxableValueClass
10-
import io.github.projectmapk.jackson.module.kogera.reconstructClassOrNull
11-
import kotlinx.metadata.KmValueParameter
10+
import io.github.projectmapk.jackson.module.kogera.jmClass.JmValueParameter
1211

1312
/**
1413
* A class that abstracts the creation of instances by calling KFunction.
@@ -28,7 +27,7 @@ internal sealed class ValueCreator<T> {
2827
/**
2928
* ValueParameters of the KFunction to be called.
3029
*/
31-
abstract val valueParameters: List<ValueParameter>
30+
abstract val valueParameters: List<JmValueParameter>
3231

3332
protected abstract val bucketGenerator: BucketGenerator
3433

@@ -61,12 +60,12 @@ internal sealed class ValueCreator<T> {
6160
}
6261

6362
@Suppress("UNCHECKED_CAST")
64-
internal fun List<KmValueParameter>.mapToConverters(
63+
internal fun List<JmValueParameter>.mapToConverters(
6564
rawTypes: List<Class<*>>,
6665
cache: ReflectionCache
6766
): List<ValueClassUnboxConverter<Any>?> =
6867
mapIndexed { i, param ->
69-
param.type.reconstructClassOrNull()
68+
param.reconstructedClassOrNull
7069
?.takeIf { it.isUnboxableValueClass() && rawTypes[i] != it }
7170
?.let { cache.getValueClassUnboxConverter(it) }
7271
} as List<ValueClassUnboxConverter<Any>?> // Cast to cheat generics

0 commit comments

Comments
 (0)