@@ -3,11 +3,11 @@ package dev.appoutlet.some.resolver
33import dev.appoutlet.some.config.NullableStrategy
44import dev.appoutlet.some.core.ResolverChain
55import dev.appoutlet.some.core.TypeResolver
6+ import dev.appoutlet.some.exception.SomeCircularReferenceException
67import java.util.Optional
78import kotlin.random.Random
89import kotlin.reflect.KClass
910import kotlin.reflect.KType
10- import kotlin.reflect.full.createType
1111import kotlin.reflect.full.isSubclassOf
1212
1313/* *
@@ -21,17 +21,43 @@ import kotlin.reflect.full.isSubclassOf
2121 * @param nullableStrategy Strategy for resolving optional types. Defaults to [NullableStrategy.default] when null.
2222 * @param random Random source used by [NullableStrategy.Random].
2323 */
24- class JavaOptionalResolver (
24+ class OptionalResolver (
2525 nullableStrategy : NullableStrategy ? ,
2626 private val random : Random
2727) : TypeResolver {
28+ /* *
29+ * Resolved nullable strategy used to decide whether the resulting [Optional] is empty or present.
30+ *
31+ * Initialized from the constructor parameter, falling back to [NullableStrategy.default] when null.
32+ */
2833 private val nullableStrategy = nullableStrategy ? : NullableStrategy .default
2934
35+ /* *
36+ * Returns `true` when [type] is a subclass of [Optional].
37+ *
38+ * @param type The type to inspect.
39+ * @return `true` if the type's classifier is a [KClass] that extends [Optional], `false` otherwise.
40+ */
3041 override fun canResolve (type : KType ): Boolean {
3142 val kClass = type.classifier as ? KClass <* > ? : return false
3243 return kClass.isSubclassOf(Optional ::class )
3344 }
3445
46+ /* *
47+ * Resolves an [Optional] of the wrapped type described by [type].
48+ *
49+ * The behavior depends on the configured [nullableStrategy]:
50+ * - [NullableStrategy.AlwaysNull] – always returns [Optional.empty].
51+ * - [NullableStrategy.NeverNull] – always returns a present [Optional] containing the resolved value.
52+ * - [NullableStrategy.Random] – returns [Optional.empty] with probability defined by the strategy.
53+ * - [NullableStrategy.NullOnCircularReference] – resolves the wrapped type and returns it inside a
54+ * present [Optional]. If the chain throws [SomeCircularReferenceException], returns [Optional.empty].
55+ *
56+ * @param type The [Optional] type to resolve. Its first type argument is used as the wrapped value type.
57+ * @param chain Resolver chain used to generate the wrapped value.
58+ * @return An [Optional] that may be empty or present depending on the active strategy.
59+ * @throws IllegalArgumentException If the [Optional] type uses a star projection.
60+ */
3561 override fun resolve (type : KType , chain : ResolverChain ): Any {
3662 val valueType = requireNotNull(type.arguments.firstOrNull()?.type) {
3763 " Star projection not supported in Optional"
@@ -48,12 +74,11 @@ class JavaOptionalResolver(
4874 }
4975 }
5076 is NullableStrategy .NullOnCircularReference -> {
51- val nullableValueType = (valueType.classifier as ? KClass <* >)?.createType(
52- arguments = valueType.arguments,
53- nullable = true
54- ) ? : valueType
55-
56- Optional .ofNullable(chain.resolve(nullableValueType))
77+ try {
78+ Optional .ofNullable(chain.resolve(valueType))
79+ } catch (_: SomeCircularReferenceException ) {
80+ Optional .empty<Any >()
81+ }
5782 }
5883 }
5984 }
0 commit comments