Browse Source

DATACMNS-1338 - Calculate defaulting mask count in Kotlin default constructor resolution.

We now calculate the number of expected default masks to filter synthetic constructors that do not match the expected parameter count. A Kotlin constructor with argument defaulting generates a synthetic integer argument for every 32 constructor arguments. This is independent of the number of actual optional arguments.

Previously, we used an non-exact check to consider constructors as default ones if they had at least two additional arguments. This caused the wrong constructor being used if the non-synthetic types matched the types of the default constructor.
pull/303/head
Mark Paluch 8 years ago
parent
commit
3ea24a1976
  1. 11
      src/main/java/org/springframework/data/convert/KotlinClassGeneratingEntityInstantiator.java
  2. 35
      src/test/kotlin/org/springframework/data/convert/KotlinClassGeneratingEntityInstantiatorUnitTests.kt

11
src/main/java/org/springframework/data/convert/KotlinClassGeneratingEntityInstantiator.java

@ -112,13 +112,12 @@ public class KotlinClassGeneratingEntityInstantiator extends ClassGeneratingEnti @@ -112,13 +112,12 @@ public class KotlinClassGeneratingEntityInstantiator extends ClassGeneratingEnti
continue;
}
// with a parameter count greater zero
if (constructor.getParameterCount() == 0) {
continue;
}
// candidates must contain at least two additional parameters (int, DefaultConstructorMarker).
// Number of defaulting masks derives from the original constructor arg count
int syntheticParameters = (constructor.getParameterCount() / Integer.SIZE) + 1
+ /* DefaultConstructorMarker */ 1;
// candidates must contain at least two additional parameters (int, DefaultConstructorMarker)
if (constructor.getParameterCount() + 2 > candidate.getParameterCount()) {
if (constructor.getParameterCount() + syntheticParameters != candidate.getParameterCount()) {
continue;
}

35
src/test/kotlin/org/springframework/data/convert/KotlinClassGeneratingEntityInstantiatorUnitTests.kt

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2017-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,6 +23,7 @@ import org.junit.Test @@ -23,6 +23,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.springframework.data.annotation.PersistenceConstructor
import org.springframework.data.mapping.PersistentEntity
import org.springframework.data.mapping.context.SamplePersistentProperty
import org.springframework.data.mapping.model.MappingInstantiationException
@ -117,6 +118,21 @@ class KotlinClassGeneratingEntityInstantiatorUnitTests { @@ -117,6 +118,21 @@ class KotlinClassGeneratingEntityInstantiatorUnitTests {
Assertions.assertThat(instance.aBool).isTrue()
}
@Test // DATACMNS-1338
fun `should create instance using @PersistenceConstructor`() {
val entity = this.entity as PersistentEntity<CustomUser, SamplePersistentProperty>
val constructor = PreferredConstructorDiscoverer.discover<CustomUser, SamplePersistentProperty>(CustomUser::class.java)
doReturn("Walter").`when`(provider).getParameterValue<SamplePersistentProperty>(any())
doReturn(constructor).whenever(entity).persistenceConstructor
doReturn(constructor.constructor.declaringClass).whenever(entity).type
val instance: CustomUser = KotlinClassGeneratingEntityInstantiator().createInstance(entity, provider)
Assertions.assertThat(instance.id).isEqualTo("Walter")
}
data class Contact(val firstname: String, val lastname: String)
data class ContactWithDefaulting(val prop0: String, val prop1: String = "White", val prop2: String,
@ -137,5 +153,22 @@ class KotlinClassGeneratingEntityInstantiatorUnitTests { @@ -137,5 +153,22 @@ class KotlinClassGeneratingEntityInstantiatorUnitTests {
data class WithPrimitiveDefaulting(val aByte: Byte = 0, val aShort: Short = 0, val anInt: Int = 0, val aLong: Long = 0L,
val aFloat: Float = 0.0f, val aDouble: Double = 0.0, val aChar: Char = 'a', val aBool: Boolean = true)
data class ContactWithPersistenceConstructor(val firstname: String, val lastname: String) {
@PersistenceConstructor
constructor(firstname: String) : this(firstname, "")
}
data class CustomUser(
var id: String? = null,
var organisations: MutableList<Organisation> = mutableListOf()
) {
@PersistenceConstructor
constructor(id: String?) : this(id, mutableListOf())
}
data class Organisation(var id: String? = null)
}

Loading…
Cancel
Save