group.phorus.mapper.OriginClasses.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mapper Show documentation
Show all versions of mapper Show documentation
Kotlin based mapper with extra functionalities.
The newest version!
package group.phorus.mapper
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
import kotlin.reflect.KType
import kotlin.reflect.full.memberProperties
/**
* [OriginalEntity] and [OriginalNode] common interface.
* Contains the [findProperty] function and common fields.
*
* @param T the wrapped entity type.
*/
interface OriginalNodeInterface {
/**
* The parent entity, or null if it doesn't exist.
*/
val parent: OriginalNodeInterface<*>?
get() = null
/**
* The entity type.
*/
var type: KType
/**
* The entity.
*/
var value: Any?
/**
* The entity properties presented in a [Map] with the property name as key, and the property
* wrapped with [OriginalNode] as value.
*/
val properties: Map>
/**
* Looks for a [node][OriginalNodeInterface] in a specific location.
*
* @param location location of the desired node, formatted as a [list][List] of [fields][Field].
*
* For example: {"pet", "name"}
*
* @return the found [node][OriginalNodeInterface], or null if it doesn't exist.
*/
fun findProperty(location: List): OriginalNodeInterface<*>? {
// If the location list is empty, return null
if (location.isEmpty())
return null
// Find the first node of the location, if we cannot find it return null
val property = if (location.first() == "..") {
parent ?: return null
} else {
properties[location.first()] ?: return null
}
// If this is the last location, return the found property
if (location.size == 1)
return property
// Go to the next node
return property.findProperty(location.drop(1))
}
}
/**
* Implementation of the [OriginalNodeInterface] interface.
* Wraps around an entity of [type][type] [T].
*
* @param T the entity type.
* @param value the entity.
* @param type the [T] type as a [KType].
* This is required since kotlin cannot extract a [KType] from a class without loosing its type arguments.
*/
class OriginalEntity(
value: T,
/**
* @see [OriginalNodeInterface.type]
*/
override var type: KType,
) : OriginalNodeInterface {
/**
* @see [OriginalNodeInterface.value]
*/
override var value: Any? = value
/**
* @see [OriginalNodeInterface.properties]
*/
override val properties: Map> by lazy { value::class.memberProperties
.associate { prop -> prop.name to OriginalNode(this, prop) } }
}
/**
* Implementation of the [OriginalNodeInterface] interface.
* Wraps around a property of type [B].
*
* @param T the parent type.
* @param B the entity type.
* @param parent the entity parent.
* @param property the property of type [B].
*/
class OriginalNode(
/**
* @see [OriginalNodeInterface.parent]
*/
override val parent: OriginalNodeInterface,
property: KProperty,
) : OriginalNodeInterface {
/**
* @see [OriginalNodeInterface.type]
*/
override var type: KType = property.returnType
/**
* @see [OriginalNodeInterface.value]
*/
override var value: Any? = runCatching { property.getter.call(parent.value) }.getOrNull()
/**
* @see [OriginalNodeInterface.properties]
*/
override val properties: Map> by lazy {
value?.let { (type.classifier as KClass<*>).memberProperties
.associate { prop -> prop.name to OriginalNode(this, prop) }} ?: emptyMap()
}
}