Skip to content

Commit

Permalink
resolves #118 Deserialize not-constructor params (native)
Browse files Browse the repository at this point in the history
  • Loading branch information
zigzago committed Feb 22, 2019
1 parent 3454759 commit c895152
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import org.junit.experimental.categories.Category
import org.litote.kmongo.JacksonMappingCategory
import org.litote.kmongo.KMongoRootTest
import org.litote.kmongo.NativeMappingCategory
import org.litote.kmongo.model.Friend
import org.litote.kmongo.reactivestreams.ReactiveStreamsFlapdoodleRule
import java.lang.reflect.ParameterizedType
import kotlin.reflect.KClass

/**
Expand All @@ -45,6 +45,7 @@ open class KMongoReactiveStreamsCoroutineBaseTest<T : Any> : KMongoRootTest() {
inline fun <reified T : Any> getCollection(): CoroutineCollection<T> = rule.getCollection<T>().coroutine

@Suppress("UNCHECKED_CAST")
open fun getDefaultCollectionClass(): KClass<T> = Friend::class as KClass<T>
open fun getDefaultCollectionClass(): KClass<T> =
((this::class.java.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<T>).kotlin

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2017/2018 Litote
*
* 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
*
* http://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 org.litote.kmongo.coroutine.issues

import kotlinx.coroutines.runBlocking
import org.bson.codecs.pojo.annotations.BsonId
import org.junit.Test
import org.litote.kmongo.coroutine.KMongoReactiveStreamsCoroutineBaseTest
import org.litote.kmongo.coroutine.issues.Issue118DeserializeNotConstructorParams.Document2
import kotlin.test.assertEquals

/**
*
*/
class Issue118DeserializeNotConstructorParams : KMongoReactiveStreamsCoroutineBaseTest<Document2>() {

data class Document2(@BsonId val id: Int) {
var field1: String? = null
var field2: String? = null
}

@Test
fun canFindOne() = runBlocking {
col.insertOne(
Document2(1)
.apply {
field1 = "1"
field2 = "2"
}
)
assertEquals(1, col.findOne()?.id)
assertEquals("1", col.findOne()?.field1)
assertEquals("2", col.findOne()?.field2)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,41 +24,53 @@ import kotlin.reflect.full.companionObjectInstance
/**
*
*/
internal class KotlinInstanceCreator<T : Any>(val kClass: KClass<T>, val instantiator: KFunction<*>) : InstanceCreator<T> {
internal class KotlinInstanceCreator<T : Any>(val kClass: KClass<T>, val instantiator: KFunction<*>) :
InstanceCreator<T> {

private val properties: MutableMap<String, Any?> = mutableMapOf()
private val properties: MutableMap<String, Pair<Any?, PropertyModel<Any>>> = mutableMapOf()

override fun <S : Any?> set(value: S, propertyModel: PropertyModel<S>) {
properties[propertyModel.name] = value
@Suppress("UNCHECKED_CAST")
properties[propertyModel.name] = value to propertyModel as PropertyModel<Any>
}

@Suppress("UNCHECKED_CAST")
override fun getInstance(): T {
val params = instantiator
.parameters
.mapNotNull { paramDef ->
if (paramDef.kind == KParameter.Kind.INSTANCE) {
paramDef to kClass.companionObjectInstance
} else {
val name = paramDef.name
val value = properties[name]
val isMissing = !properties.containsKey(name)
.parameters
.asSequence()
.mapNotNull { paramDef ->
if (paramDef.kind == KParameter.Kind.INSTANCE) {
paramDef to kClass.companionObjectInstance
} else {
val name = paramDef.name
val pair = properties.remove(name)

if (isMissing && paramDef.isOptional) {
null
} else {
if (value == null && !paramDef.type.isMarkedNullable) {
throw MissingKotlinParameterException(
"Instantiation of $kClass value failed for property $name due to missing (therefore NULL) value for creator parameter $name which is a non-nullable type"
)
}
paramDef to value
if (pair == null && paramDef.isOptional) {
null
} else {
val value = pair?.first
if (value == null && !paramDef.type.isMarkedNullable) {
throw MissingKotlinParameterException(
"Instantiation of $kClass value failed for property $name due to missing (therefore NULL) value for creator parameter $name which is a non-nullable type"
)
}
paramDef to value
}
}
.toMap()
}
.toMap()

@Suppress("UNCHECKED_CAST")
val result = instantiator.callBy(params) as T

//now try to set remaining properties
properties.values.forEach { (v, model) ->
if (model.isWritable) {
model.propertyAccessor.set(result, v)
}
}

return instantiator.callBy(params) as T
return result
}

}

0 comments on commit c895152

Please sign in to comment.