Custom Structured Values
Use Konstrained types when primitive or enum values are not enough.
Prerequisites: You understand Features and Types.
Step 1: Define a Structured Type
import io.amichne.konditional.core.types.Konstrained
import io.amichne.kontracts.dsl.schema
import io.amichne.kontracts.schema.ObjectSchema
data class CheckoutPolicy(
val maxRetries: Int,
val timeoutMillis: Int,
) : Konstrained.Object<ObjectSchema> {
override val schema = schema {
::maxRetries of { minimum = 0 }
::timeoutMillis of { minimum = 100 }
}
}
You can also model a zero-field singleton with Kotlin object when you need a
single shared typed value:
import io.amichne.konditional.core.types.Konstrained
import io.amichne.kontracts.dsl.schema
import io.amichne.kontracts.schema.ObjectSchema
object DefaultCheckoutPolicy : Konstrained.Object<ObjectSchema> {
override val schema = schema {}
}
Step 2: Declare Feature with custom<...>
import io.amichne.konditional.context.Context
import io.amichne.konditional.core.Namespace
object CheckoutFlags : Namespace("checkout") {
val policy by custom<CheckoutPolicy, Context>(
default = CheckoutPolicy(maxRetries = 3, timeoutMillis = 1500),
)
}
Step 3: Evaluate as a Typed Object
val policy: CheckoutPolicy = CheckoutFlags.policy.evaluate(ctx)
Decode behavior at the boundary
When Konditional parses custom structured values from JSON, it uses deterministic field resolution rules.
- Use the JSON field value when the field exists and is non-null.
- Use the schema
defaultValuewhen the field is missing and the schema defines a default. - Use the Kotlin constructor default when the field is missing and the constructor parameter is optional.
- Return
Result.failurewithParseError.InvalidSnapshotwhen a required field is missing and no default applies.
For Kotlin object singletons, decode returns the existing singleton instance
without requiring a primary constructor.
Expected Outcome
After this guide, your feature returns a schema-backed typed object with boundary-safe serialization behavior.