From 4f86adbea41ff222664ddf43fa294915a2aba929 Mon Sep 17 00:00:00 2001 From: Marcin Kuszczak <1508798+aartiPl@users.noreply.github.com> Date: Mon, 21 Aug 2023 15:07:41 +0200 Subject: [PATCH] Improvements --- .../typeutils/globalcontext/GlobalContext.kt | 29 ++++++++-------- .../typeutils/marker/AutoTypedMarker.kt | 6 ++-- .../{AbstractMarker.kt => DefaultMarker.kt} | 4 ++- .../typeutils/marker/DefaultTypedMarker.kt | 2 +- .../property/ImmutableTypedProperties.kt | 4 +++ .../typeutils/property/TypedProperties.kt | 29 ++++++++-------- .../typeutils/marker/AutoTypedMarkerTest.kt | 13 ++++++++ .../typeutils/property/TypedPropertiesTest.kt | 33 +++++++++++++++++++ 8 files changed, 85 insertions(+), 35 deletions(-) rename src/main/kotlin/net/igsoft/typeutils/marker/{AbstractMarker.kt => DefaultMarker.kt} (64%) create mode 100644 src/test/kotlin/net/igsoft/typeutils/marker/AutoTypedMarkerTest.kt diff --git a/src/main/kotlin/net/igsoft/typeutils/globalcontext/GlobalContext.kt b/src/main/kotlin/net/igsoft/typeutils/globalcontext/GlobalContext.kt index ce57ab0..f20269a 100644 --- a/src/main/kotlin/net/igsoft/typeutils/globalcontext/GlobalContext.kt +++ b/src/main/kotlin/net/igsoft/typeutils/globalcontext/GlobalContext.kt @@ -3,11 +3,12 @@ package net.igsoft.typeutils.globalcontext import net.igsoft.typeutils.marker.Marker import net.igsoft.typeutils.marker.TypedMarker import net.igsoft.typeutils.property.ImmutableTypedProperties +import net.igsoft.typeutils.property.TypedProperties import java.util.concurrent.ConcurrentHashMap -@Suppress("UNCHECKED_CAST", "unused") +@Suppress("unused") object GlobalContext : ImmutableTypedProperties { - private val context: MutableMap = ConcurrentHashMap() + private val context: TypedProperties = TypedProperties(ConcurrentHashMap()) fun register(key: TypedMarker, value: T) { require(!context.containsKey(key)) { @@ -28,29 +29,27 @@ object GlobalContext : ImmutableTypedProperties { return getOrElse(marker) { error(message) } } - override operator fun get(marker: TypedMarker) = context[marker] as T? - override fun get(key: Marker): Any? = context[key] - override fun getValue(marker: TypedMarker): T = context.getValue(marker) as T + override operator fun get(marker: TypedMarker) = context[marker] + + override fun getValue(marker: Marker): Any? = context.getValue(marker) + + override fun getValue(marker: TypedMarker): T = context.getValue(marker) override fun getOrDefault(marker: TypedMarker, defaultValue: T): T = - context.getOrDefault(marker, defaultValue) as T + context.getOrDefault(marker, defaultValue) override fun getOrElse(marker: TypedMarker, calculateValue: () -> T): T = - context.getOrElse(marker, calculateValue) as T + context.getOrElse(marker, calculateValue) - override val entries: Set> - get() = context.entries + override val entries: Set> get() = context.entries - override val keys: Set - get() = context.keys + override val keys: Set get() = context.keys - override val size: Int - get() = context.size + override val size: Int get() = context.size - override val values: Collection - get() = context.values + override val values: Collection get() = context.values override fun containsKey(key: Marker): Boolean = context.containsKey(key) diff --git a/src/main/kotlin/net/igsoft/typeutils/marker/AutoTypedMarker.kt b/src/main/kotlin/net/igsoft/typeutils/marker/AutoTypedMarker.kt index e126f2b..fac42aa 100644 --- a/src/main/kotlin/net/igsoft/typeutils/marker/AutoTypedMarker.kt +++ b/src/main/kotlin/net/igsoft/typeutils/marker/AutoTypedMarker.kt @@ -10,10 +10,8 @@ class AutoTypedMarker internal constructor(override val id: Any, override val private val intGenerator = IntGenerator() @JvmStatic - fun create(clazz: Class) = - AutoTypedMarker(intGenerator.next(), clazz) + fun create(clazz: Class) = AutoTypedMarker(intGenerator.next(), clazz) - inline fun create() = - create(T::class.java) + inline fun create() = create(T::class.java) } } diff --git a/src/main/kotlin/net/igsoft/typeutils/marker/AbstractMarker.kt b/src/main/kotlin/net/igsoft/typeutils/marker/DefaultMarker.kt similarity index 64% rename from src/main/kotlin/net/igsoft/typeutils/marker/AbstractMarker.kt rename to src/main/kotlin/net/igsoft/typeutils/marker/DefaultMarker.kt index cedb040..d439539 100644 --- a/src/main/kotlin/net/igsoft/typeutils/marker/AbstractMarker.kt +++ b/src/main/kotlin/net/igsoft/typeutils/marker/DefaultMarker.kt @@ -1,6 +1,8 @@ package net.igsoft.typeutils.marker -abstract class AbstractMarker(override val id: Any, override val clazz: Class<*>) : Marker { +open class DefaultMarker(override val id: Any, override val clazz: Class<*>) : Marker { + constructor(marker: Marker) : this(marker.id, marker.clazz) + final override fun equals(other: Any?): Boolean = Markers.markerEquals(this, other) final override fun hashCode(): Int = Markers.markerHashCode(this) override fun toString(): String = Markers.markerToString(this, id, clazz) diff --git a/src/main/kotlin/net/igsoft/typeutils/marker/DefaultTypedMarker.kt b/src/main/kotlin/net/igsoft/typeutils/marker/DefaultTypedMarker.kt index 48780e0..aba55db 100644 --- a/src/main/kotlin/net/igsoft/typeutils/marker/DefaultTypedMarker.kt +++ b/src/main/kotlin/net/igsoft/typeutils/marker/DefaultTypedMarker.kt @@ -4,7 +4,7 @@ import kotlin.properties.ReadOnlyProperty @Suppress("unused") open class DefaultTypedMarker(override val id: Any, override val clazz: Class) : TypedMarker, - AbstractMarker(id, clazz) { + DefaultMarker(id, clazz) { //Copying constructor (de facto alias of marker) constructor(marker: TypedMarker) : this(marker.id, marker.clazz) diff --git a/src/main/kotlin/net/igsoft/typeutils/property/ImmutableTypedProperties.kt b/src/main/kotlin/net/igsoft/typeutils/property/ImmutableTypedProperties.kt index 6877fc1..6560b5c 100644 --- a/src/main/kotlin/net/igsoft/typeutils/property/ImmutableTypedProperties.kt +++ b/src/main/kotlin/net/igsoft/typeutils/property/ImmutableTypedProperties.kt @@ -4,8 +4,12 @@ import net.igsoft.typeutils.marker.Marker import net.igsoft.typeutils.marker.TypedMarker interface ImmutableTypedProperties : Map, Iterable> { + override operator fun get(key: Marker): Any? operator fun get(marker: TypedMarker): T? + + fun getValue(marker: Marker): Any? fun getValue(marker: TypedMarker): T + fun getOrDefault(marker: TypedMarker, defaultValue: T): T fun getOrElse(marker: TypedMarker, calculateValue: () -> T): T } diff --git a/src/main/kotlin/net/igsoft/typeutils/property/TypedProperties.kt b/src/main/kotlin/net/igsoft/typeutils/property/TypedProperties.kt index 6d62c51..c5cc1a1 100644 --- a/src/main/kotlin/net/igsoft/typeutils/property/TypedProperties.kt +++ b/src/main/kotlin/net/igsoft/typeutils/property/TypedProperties.kt @@ -10,11 +10,17 @@ class TypedProperties(private val map: MutableMap) : MutableTypedP map[marker] = value } - override fun get(key: Marker): Any? = - map[key] + override fun get(key: Marker): Any? = map[key] - override fun get(marker: TypedMarker): T? = - map[marker] as? T + override fun get(marker: TypedMarker): T? = map[marker] as? T + + override fun getValue(marker: Marker): Any? { + if (isPropertyKeyMissing(null, marker)) { + throw NoSuchElementException("Marker $marker is missing in the properties") + } + + return map.getValue(marker) + } override fun getValue(marker: TypedMarker): T { val value = map[marker] @@ -57,17 +63,13 @@ class TypedProperties(private val map: MutableMap) : MutableTypedP return value as T } - override val size: Int - get() = map.size + override val size: Int get() = map.size - override val entries: MutableSet> - get() = map.entries + override val entries: MutableSet> get() = map.entries - override val keys: MutableSet - get() = map.keys + override val keys: MutableSet get() = map.keys - override val values: MutableCollection - get() = map.values + override val values: MutableCollection get() = map.values override fun isEmpty(): Boolean = map.isEmpty() @@ -87,6 +89,5 @@ class TypedProperties(private val map: MutableMap) : MutableTypedP fun remove(key: Marker): Any? = map.remove(key) - private fun isPropertyKeyMissing(any: Any?, marker: Marker) = - any == null && !map.containsKey(marker) + private fun isPropertyKeyMissing(any: Any?, marker: Marker) = any == null && !map.containsKey(marker) } diff --git a/src/test/kotlin/net/igsoft/typeutils/marker/AutoTypedMarkerTest.kt b/src/test/kotlin/net/igsoft/typeutils/marker/AutoTypedMarkerTest.kt new file mode 100644 index 0000000..a82a120 --- /dev/null +++ b/src/test/kotlin/net/igsoft/typeutils/marker/AutoTypedMarkerTest.kt @@ -0,0 +1,13 @@ +package net.igsoft.typeutils.marker + +import assertk.assertThat +import assertk.assertions.isNotEqualTo +import org.junit.jupiter.api.Test + +class AutoTypedMarkerTest { + + @Test + fun `Assert that creation of two AutoTypedMarkers generates unique 'id's`() { + assertThat(AutoTypedMarker.create().id).isNotEqualTo(AutoTypedMarker.create().id) + } +} diff --git a/src/test/kotlin/net/igsoft/typeutils/property/TypedPropertiesTest.kt b/src/test/kotlin/net/igsoft/typeutils/property/TypedPropertiesTest.kt index 2603f90..c22cda6 100644 --- a/src/test/kotlin/net/igsoft/typeutils/property/TypedPropertiesTest.kt +++ b/src/test/kotlin/net/igsoft/typeutils/property/TypedPropertiesTest.kt @@ -1,13 +1,16 @@ package net.igsoft.typeutils.property +import assertk.assertFailure import assertk.assertThat import assertk.assertions.* import net.igsoft.typeutils.marker.DefaultTypedMarker +import net.igsoft.typeutils.marker.Marker import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test class TypedPropertiesTest { private lateinit var properties: TypedProperties + private val firstname by DefaultTypedMarker.create() private val surname by DefaultTypedMarker.create() private val age by DefaultTypedMarker.create() @@ -35,6 +38,36 @@ class TypedPropertiesTest { } } + @Test + fun `Assert that getting properties is possible`() { + assertThat(properties[firstname]).isEqualTo("Gregory") + assertThat(properties[surname]).isEqualTo("Iksiński") + assertThat(properties[shoeSize]).isNull() + + val untypedFirstname: Marker = firstname + val untypedSurname: Marker = surname + val untypedShoeSize: Marker = shoeSize + + assertThat(properties[untypedFirstname]).isNotNull().isInstanceOf().isEqualTo("Gregory") + assertThat(properties[untypedSurname]).isNotNull().isInstanceOf().isEqualTo("Iksiński") + assertThat(properties[untypedShoeSize]).isNull() + } + + @Test + fun `Assert that getting not null properties is possible`() { + assertThat(properties.getValue(firstname)).isEqualTo("Gregory") + assertThat(properties.getValue(surname)).isEqualTo("Iksiński") + assertFailure { properties.getValue(shoeSize) }.hasMessage("Marker DefaultTypedMarker(id=shoeSize, clazz=java.lang.Integer) is missing in the properties") + + val untypedFirstname: Marker = firstname + val untypedSurname: Marker = surname + val untypedShoeSize: Marker = shoeSize + + assertThat(properties.getValue(untypedFirstname)).isNotNull().isInstanceOf().isEqualTo("Gregory") + assertThat(properties.getValue(untypedSurname)).isNotNull().isInstanceOf().isEqualTo("Iksiński") + assertFailure { properties.getValue(untypedShoeSize) }.hasMessage("Marker DefaultTypedMarker(id=shoeSize, clazz=java.lang.Integer) is missing in the properties") + } + @Test fun `Assert that putting new properties is possible`() { properties[shoeSize] = 32