Skip to content

Instantly share code, notes, and snippets.

@hrules6872
Last active August 12, 2019 19:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hrules6872/467d80f8c2fde728905c1eda692d1423 to your computer and use it in GitHub Desktop.
Save hrules6872/467d80f8c2fde728905c1eda692d1423 to your computer and use it in GitHub Desktop.
Reduce two (Data) Classes in Kotlin
inline infix fun <reified T : Any> T?.reduce(other: T?): T? = when {
this == null && other == null -> null
this != null && other == null -> this
this == null && other != null -> other
else -> {
val nameToProperty = T::class.declaredMemberProperties.associateBy { property -> property.name }
val primaryConstructor = T::class.primaryConstructor!!
val args = primaryConstructor.parameters.associate { parameter ->
val property = nameToProperty[parameter.name]!!
val revertPrivateVisibility = if (property.visibility == PRIVATE || property.visibility == PROTECTED) {
property.isAccessible = true
true
} else false
parameter to (property.get(other!!) ?: property.get(this!!)).also {
if (revertPrivateVisibility) property.isAccessible = false
}
}
primaryConstructor.callBy(args)
}
}
class ClazzesExtKtTest {
companion object {
private const val DEFAULT_STRING = "TEST"
}
@Test fun `Reduce two classes should return the correct values`() {
var mutable: TestClassToMerge? = TestClassToMerge()
mutable = mutable reduce TestClassToMerge(_booleanValue = true)
mutable.`should not be null`()
mutable.booleanValue.`should be true`()
mutable.list.`should equal`(DEFAULT_LIST)
mutable = mutable reduce TestClassToMerge(
_booleanValue = false,
_stringValue = DEFAULT_STRING,
_listValue = listOf(DEFAULT_STRING)
)
mutable.`should not be null`()
mutable.booleanValue.`should be false`()
mutable.stringValue.`should be equal to`(DEFAULT_STRING)
mutable.list.`should not be empty`()
}
}
@Suppress("MemberVisibilityCanBePrivate")
open class TestClassToMerge(
private val _booleanValue: Boolean? = null,
internal val _stringValue: String? = null,
protected val _listValue: List<String>? = null
) {
companion object {
const val DEFAULT_BOOLEAN = false
const val DEFAULT_STRING = ""
val DEFAULT_LIST = listOf<String>()
}
val booleanValue: Boolean
get() = _booleanValue ?: DEFAULT_BOOLEAN
val stringValue: String
get() = _stringValue ?: DEFAULT_STRING
val list: List<String>
get() = _listValue ?: DEFAULT_LIST
}
@hrules6872
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment