Skip to content

Commit b9c4b1f

Browse files
authored
Merge pull request #212 from ProjectMapK/develop
Release 2024-01-21 12:31:31 +0000
2 parents 8d75abc + a2e9042 commit b9c4b1f

File tree

36 files changed

+15660
-155
lines changed

36 files changed

+15660
-155
lines changed

build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ val jacksonVersion = libs.versions.jackson.get()
1616
val generatedSrcPath = "${layout.buildDirectory.get()}/generated/kotlin"
1717

1818
group = groupStr
19-
version = "${jacksonVersion}-beta9"
19+
version = "${jacksonVersion}-beta10"
2020

2121
repositories {
2222
mavenCentral()
@@ -32,6 +32,7 @@ dependencies {
3232
api(libs.jackson.annotations)
3333

3434
// test libs
35+
testImplementation("${libs.kotlin.reflect.get()}:${kotlinVersion}")
3536
testImplementation(libs.junit.api)
3637
testImplementation(libs.junit.params)
3738
testRuntimeOnly(libs.junit.engine)

gradle/libs.versions.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[versions]
22
kotlin = "1.8.22" # Mainly for CI, it can be rewritten by environment variable.
3-
jackson = "2.16.0"
3+
jackson = "2.16.1"
44

55
# test libs
66
junit = "5.10.1"
@@ -12,6 +12,7 @@ jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", ver
1212
jackson-annotations = { module = "com.fasterxml.jackson.core:jackson-annotations", version.ref = "jackson" }
1313

1414
# test libs
15+
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect" }
1516
junit-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" }
1617
junit-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" }
1718
junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" }

src/main/java/io/github/projectmapk/jackson/module/kogera/deser/ValueClassDeserializer.java renamed to src/main/java/io/github/projectmapk/jackson/module/kogera/deser/WrapsNullableValueClassDeserializer.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,37 @@
11
package io.github.projectmapk.jackson.module.kogera.deser;
22

3+
import com.fasterxml.jackson.core.JacksonException;
4+
import com.fasterxml.jackson.core.JsonParser;
5+
import com.fasterxml.jackson.databind.DeserializationContext;
36
import com.fasterxml.jackson.databind.JavaType;
47
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
5-
import io.github.projectmapk.jackson.module.kogera.deser.deserializers.ValueClassBoxDeserializer;
8+
import io.github.projectmapk.jackson.module.kogera.deser.deserializers.WrapsNullableValueClassBoxDeserializer;
69
import kotlin.jvm.JvmClassMappingKt;
710
import kotlin.reflect.KClass;
811
import org.jetbrains.annotations.NotNull;
912
import org.jetbrains.annotations.Nullable;
1013

14+
import java.io.IOException;
15+
1116
/**
1217
* An interface to be inherited by JsonDeserializer that handles value classes that may wrap nullable.
13-
* @see ValueClassBoxDeserializer for implementation.
18+
* @see WrapsNullableValueClassBoxDeserializer for implementation.
1419
*/
15-
// To ensure maximum compatibility with StdDeserializer, this class is defined in Java.
16-
public abstract class ValueClassDeserializer<D> extends StdDeserializer<D> {
17-
protected ValueClassDeserializer(@NotNull KClass<?> vc) {
20+
// To ensure maximum compatibility with StdDeserializer, this class is written in Java.
21+
public abstract class WrapsNullableValueClassDeserializer<D> extends StdDeserializer<D> {
22+
protected WrapsNullableValueClassDeserializer(@NotNull KClass<?> vc) {
1823
super(JvmClassMappingKt.getJavaClass(vc));
1924
}
2025

21-
protected ValueClassDeserializer(@NotNull Class<?> vc) {
26+
protected WrapsNullableValueClassDeserializer(@NotNull Class<?> vc) {
2227
super(vc);
2328
}
2429

25-
protected ValueClassDeserializer(@NotNull JavaType valueType) {
30+
protected WrapsNullableValueClassDeserializer(@NotNull JavaType valueType) {
2631
super(valueType);
2732
}
2833

29-
protected ValueClassDeserializer(@NotNull StdDeserializer<D> src) {
34+
protected WrapsNullableValueClassDeserializer(@NotNull StdDeserializer<D> src) {
3035
super(src);
3136
}
3237

@@ -44,4 +49,8 @@ public final Class<D> handledType() {
4449
// It is defined so that null can also be returned so that Nulls.SKIP can be applied.
4550
@Nullable
4651
public abstract D getBoxedNullValue();
52+
53+
@Override
54+
public abstract D deserialize(@NotNull JsonParser p, @NotNull DeserializationContext ctxt)
55+
throws IOException, JacksonException;
4756
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ internal class ValueClassUnboxConverter<T : Any>(val valueClass: Class<T>) : Std
2929
private val unboxMethod = valueClass.getDeclaredMethod("unbox-impl").apply {
3030
if (!this.isAccessible) this.isAccessible = true
3131
}
32-
val unboxedClass: Class<*> = unboxMethod.returnType
3332

3433
override fun convert(value: T): Any? = unboxMethod.invoke(value)
3534

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import java.lang.reflect.Method
1212
internal typealias JavaDuration = java.time.Duration
1313
internal typealias KotlinDuration = kotlin.time.Duration
1414

15-
internal fun Class<*>.isUnboxableValueClass() = this.getAnnotation(JvmInline::class.java) != null
15+
internal fun Class<*>.isUnboxableValueClass() = this.isAnnotationPresent(JvmInline::class.java)
1616

1717
// JmClass must be value class.
1818
internal fun JmClass.wrapsNullValueClass() = inlineClassUnderlyingType!!.isNullable

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ internal object KotlinClassIntrospector : BasicClassIntrospector() {
5050
?: run {
5151
val coll = collectProperties(config, type, r, true)
5252

53-
if (type.rawClass.annotations.any { it is Metadata }) {
53+
if (type.rawClass.isAnnotationPresent(Metadata::class.java)) {
5454
KotlinBeanDescription(coll)
5555
} else {
5656
BasicBeanDescription.forDeserialization(coll)
@@ -71,7 +71,7 @@ internal object KotlinClassIntrospector : BasicClassIntrospector() {
7171
?: run {
7272
val coll = collectProperties(config, type, r, false)
7373

74-
if (type.rawClass.annotations.any { it is Metadata }) {
74+
if (type.rawClass.isAnnotationPresent(Metadata::class.java)) {
7575
KotlinBeanDescription(coll)
7676
} else {
7777
BasicBeanDescription.forDeserialization(coll)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ internal class KotlinFallbackAnnotationIntrospector(
8282
}
8383
} else {
8484
// If JsonUnbox is specified, the unboxed getter is used as is.
85-
if (a.hasAnnotation(JsonKUnbox::class.java) || it.getAnnotation(JsonKUnbox::class.java) != null) {
85+
if (a.hasAnnotation(JsonKUnbox::class.java) || it.isAnnotationPresent(JsonKUnbox::class.java)) {
8686
null
8787
} else {
8888
cache.getValueClassBoxConverter(a.rawReturnType, it)

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import io.github.projectmapk.jackson.module.kogera.KotlinDuration
1414
import io.github.projectmapk.jackson.module.kogera.ReflectionCache
1515
import io.github.projectmapk.jackson.module.kogera.ValueClassBoxConverter
1616
import io.github.projectmapk.jackson.module.kogera.deser.JavaToKotlinDurationConverter
17-
import io.github.projectmapk.jackson.module.kogera.deser.ValueClassDeserializer
17+
import io.github.projectmapk.jackson.module.kogera.deser.WrapsNullableValueClassDeserializer
1818
import io.github.projectmapk.jackson.module.kogera.hasCreatorAnnotation
1919
import io.github.projectmapk.jackson.module.kogera.isUnboxableValueClass
2020
import io.github.projectmapk.jackson.module.kogera.toSignature
@@ -89,10 +89,10 @@ internal object ULongDeserializer : StdDeserializer<ULong>(ULong::class.java) {
8989
ULongChecker.readWithRangeCheck(p, p.bigIntegerValue)
9090
}
9191

92-
internal class ValueClassBoxDeserializer<S, D : Any>(
92+
internal class WrapsNullableValueClassBoxDeserializer<S, D : Any>(
9393
private val creator: Method,
9494
private val converter: ValueClassBoxConverter<S, D>
95-
) : ValueClassDeserializer<D>(converter.boxedClass) {
95+
) : WrapsNullableValueClassDeserializer<D>(converter.boxedClass) {
9696
private val inputType: Class<*> = creator.parameterTypes[0]
9797

9898
init {
@@ -169,9 +169,9 @@ internal class KotlinDeserializers(
169169
rawClass == KotlinDuration::class.java ->
170170
JavaToKotlinDurationConverter.takeIf { useJavaDurationConversion }?.delegatingDeserializer
171171
rawClass.isUnboxableValueClass() -> findValueCreator(type, rawClass, cache.getJmClass(rawClass)!!)?.let {
172-
val unboxedClass = cache.getValueClassUnboxConverter(rawClass).unboxedClass
172+
val unboxedClass = it.returnType
173173
val converter = cache.getValueClassBoxConverter(unboxedClass, rawClass)
174-
ValueClassBoxDeserializer(it, converter)
174+
WrapsNullableValueClassBoxDeserializer(it, converter)
175175
}
176176
else -> null
177177
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import com.fasterxml.jackson.databind.deser.std.StdValueInstantiator
1414
import com.fasterxml.jackson.databind.exc.InvalidNullException
1515
import com.fasterxml.jackson.databind.module.SimpleValueInstantiators
1616
import io.github.projectmapk.jackson.module.kogera.ReflectionCache
17-
import io.github.projectmapk.jackson.module.kogera.deser.ValueClassDeserializer
17+
import io.github.projectmapk.jackson.module.kogera.deser.WrapsNullableValueClassDeserializer
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
@@ -47,7 +47,7 @@ internal class KotlinValueInstantiator(
4747
isNullableParam: Boolean,
4848
valueDeserializer: JsonDeserializer<*>?
4949
): Boolean = !isNullableParam &&
50-
valueDeserializer is ValueClassDeserializer<*> &&
50+
valueDeserializer is WrapsNullableValueClassDeserializer<*> &&
5151
cache.getJmClass(valueDeserializer.handledType())!!.wrapsNullValueClass()
5252

5353
private val valueCreator: ValueCreator<*>? by ReflectProperties.lazySoft {
@@ -83,7 +83,7 @@ internal class KotlinValueInstantiator(
8383
// Deserializer.getNullValue could not be used because there is no way to get and parse parameters
8484
// from the BeanDescription and using AnnotationIntrospector would override user customization.
8585
if (requireValueClassSpecialNullValue(paramDef.isNullable, valueDeserializer)) {
86-
(valueDeserializer as ValueClassDeserializer<*>).boxedNullValue?.let { return@run it }
86+
(valueDeserializer as WrapsNullableValueClassDeserializer<*>).boxedNullValue?.let { return@run it }
8787
}
8888

8989
if (jsonProp.skipNulls() && paramDef.isOptional) return@forEachIndexed

src/test/kotlin/io/github/projectmapk/jackson/module/kogera/TestCommons.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import com.fasterxml.jackson.core.util.DefaultIndenter
44
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
55
import com.fasterxml.jackson.databind.ObjectMapper
66
import com.fasterxml.jackson.databind.ObjectWriter
7+
import org.junit.jupiter.api.Assertions.assertEquals
8+
import kotlin.reflect.KParameter
9+
import kotlin.reflect.full.memberProperties
10+
import kotlin.reflect.full.primaryConstructor
711

812
// This `printer` is used to match the output from Jackson to the newline char of the source code.
913
// If this is removed, comparisons will fail in a Windows-like platform.
@@ -13,3 +17,18 @@ internal val LF_PRINTER: DefaultPrettyPrinter =
1317
internal fun ObjectMapper.testPrettyWriter(): ObjectWriter = this.writer(LF_PRINTER)
1418

1519
internal fun Class<*>.isKotlinClass() = declaredAnnotations.any { it is Metadata }
20+
21+
internal val defaultMapper = jacksonObjectMapper()
22+
23+
internal inline fun <reified T : Any> callPrimaryConstructor(mapper: (KParameter) -> Any? = { it.name }): T =
24+
T::class.primaryConstructor!!.run {
25+
val args = parameters.associateWith { mapper(it) }
26+
callBy(args)
27+
}
28+
29+
// Function for comparing non-data classes.
30+
internal inline fun <reified T : Any> assertReflectEquals(expected: T, actual: T) {
31+
T::class.memberProperties.forEach {
32+
assertEquals(it.get(expected), it.get(actual))
33+
}
34+
}

0 commit comments

Comments
 (0)