Package-level declarations

The main function toStateOrNull(...) can be found in this package. The property states (Correct and Incorrect) are also part of this package. There are overrides of toStateOrNull(...) for from 1 up to 25 property states.

Usage

The minimal steps to convert to an object with properties in a known state are:

  • Import function toStateOrNull(...) and state test functions from com.zybbe.to_state.property_state_test.

  • Create a class representing the object in the correct state.

  • Write an extension function for the object to validate.

class FormData(
val name: String?,
val dateOfBirth: LocalDate?
)

class FormDataComplete(
val name: String,
val dateOfBirth: LocalDate
)

fun FormData.toCompleteOrNull() =
toStateOrNull(
::FormDataComplete,
isNotNull(name),
isNotNull(dateOfBirth)
)

val possiblyCompleteFormData = formData.toCompleteOrNull()
if (possiblyCompleteFormData == null) {
// Handle unexpected case.
} else {
// Regular processing.
}

Additional Conditions

If you need to do additional checks you can do it in 2 ways:

  • On a property state: use and(...) and supply a 1-parameter lambda returning a Boolean.

  • On the set of individually validated properties: supply a lambda to toStateOrNull(...) with a parameter for each property state, and returning a Boolean.

On a Property State

If an existing property state test function is not sufficient, it is easy to add additional checks to a correct value. Simply call and(...) on the property state. When invoked on Incorrect it is a no-operation action. For example, to check that the length of a username is correct:

isNotNull(username).and { it.length >= 5 }

For Combinations of Properties

If the condition is based on values of multiple properties, you can supply a lambda as the last argument to toStateOrNull(...). The lambda must have the same number of parameters as the number of property states. The lambda is only invoked if all property states are Correct. For example to test if the repeated password is equal to the password:

toStateOrNull(
::UserRegistrationCorrect,
isNotNull(username),
isNotNull(password),
isNotNull(repeatedPassword)
) { _, password, repeatedPassword -> password == repeatedPassword }

Custom State Test Functions

ToState comes with a limited set of property state test functions. If you need more it is easy to write your own. The only requirement is that it returns a property state: Correct or Incorrect. For example, if you need to check if a value has the correct type:

inline fun <reified T: Any> isInstanceOf(value: Any?): PropertyState<T> {
val valueAsTOrNull = value as? T
return if (valueAsTOrNull == null) Incorrect else Correct(valueAsTOrNull)
}

If needed, you can also do transformations within your property state test function. For example if you get an Any? as input and expect it to be a finite Float after it has been validated:

fun isFiniteFloat(value: Any?): PropertyState<Float> {
val floatOrNull = (value as? String)?.toFloatOrNull()?.takeIf { it.isFinite() }
return if (floatOrNull == null) Incorrect else Correct(floatOrNull)
}

Types

Link copied to clipboard
class Correct<TValue>(val value: TValue) : PropertyState<TValue>

Indicates that the property is in the correct state.

Link copied to clipboard

Indicates that the property is not in the correct state.

Link copied to clipboard
sealed class PropertyState<out TValue>

The state of a property.

Functions

Link copied to clipboard
fun <TResult : Any, TFirst> toStateOrNull(constructor: (TFirst) -> TResult, ps1: PropertyState<TFirst>, isAdditionalStateCorrectFunction: (TFirst) -> Boolean? = null): TResult?
fun <TResult : Any, TFirst, TSecond> toStateOrNull(constructor: (TFirst, TSecond) -> TResult, ps1: PropertyState<TFirst>, ps2: PropertyState<TSecond>, isAdditionalStateCorrectFunction: (TFirst, TSecond) -> Boolean? = null): TResult?
fun <TResult : Any, TFirst, TSecond, TThird> toStateOrNull(constructor: (TFirst, TSecond, TThird) -> TResult, ps1: PropertyState<TFirst>, ps2: PropertyState<TSecond>, ps3: PropertyState<TThird>, isAdditionalStateCorrectFunction: (TFirst, TSecond, TThird) -> Boolean? = null): TResult?
fun <TResult : Any, TFirst, TSecond, TThird, TFourth> toStateOrNull(constructor: (TFirst, TSecond, TThird, TFourth) -> TResult, ps1: PropertyState<TFirst>, ps2: PropertyState<TSecond>, ps3: PropertyState<TThird>, ps4: PropertyState<TFourth>, isAdditionalStateCorrectFunction: (TFirst, TSecond, TThird, TFourth) -> Boolean? = null): TResult?
fun <TResult : Any, TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TEighth, TNinth, TTenth, TEleventh, TTwelfth, TThirteenth, TFourteenth, TFifteenth, TSixteenth, TSeventeenth, TEighteenth, TNineteenth, TTwentieth, TTwentyFirst, TTwentySecond> toStateOrNull(constructor: (TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TEighth, TNinth, TTenth, TEleventh, TTwelfth, TThirteenth, TFourteenth, TFifteenth, TSixteenth, TSeventeenth, TEighteenth, TNineteenth, TTwentieth, TTwentyFirst, TTwentySecond) -> TResult, ps1: PropertyState<TFirst>, ps2: PropertyState<TSecond>, ps3: PropertyState<TThird>, ps4: PropertyState<TFourth>, ps5: PropertyState<TFifth>, ps6: PropertyState<TSixth>, ps7: PropertyState<TSeventh>, ps8: PropertyState<TEighth>, ps9: PropertyState<TNinth>, ps10: PropertyState<TTenth>, ps11: PropertyState<TEleventh>, ps12: PropertyState<TTwelfth>, ps13: PropertyState<TThirteenth>, ps14: PropertyState<TFourteenth>, ps15: PropertyState<TFifteenth>, ps16: PropertyState<TSixteenth>, ps17: PropertyState<TSeventeenth>, ps18: PropertyState<TEighteenth>, ps19: PropertyState<TNineteenth>, ps20: PropertyState<TTwentieth>, ps21: PropertyState<TTwentyFirst>, ps22: PropertyState<TTwentySecond>, isAdditionalStateCorrectFunction: (TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TEighth, TNinth, TTenth, TEleventh, TTwelfth, TThirteenth, TFourteenth, TFifteenth, TSixteenth, TSeventeenth, TEighteenth, TNineteenth, TTwentieth, TTwentyFirst, TTwentySecond) -> Boolean? = null): TResult?
fun <TResult : Any, TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TEighth, TNinth, TTenth, TEleventh, TTwelfth, TThirteenth, TFourteenth, TFifteenth, TSixteenth, TSeventeenth, TEighteenth, TNineteenth, TTwentieth, TTwentyFirst, TTwentySecond, TTwentyThird> toStateOrNull(constructor: (TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TEighth, TNinth, TTenth, TEleventh, TTwelfth, TThirteenth, TFourteenth, TFifteenth, TSixteenth, TSeventeenth, TEighteenth, TNineteenth, TTwentieth, TTwentyFirst, TTwentySecond, TTwentyThird) -> TResult, ps1: PropertyState<TFirst>, ps2: PropertyState<TSecond>, ps3: PropertyState<TThird>, ps4: PropertyState<TFourth>, ps5: PropertyState<TFifth>, ps6: PropertyState<TSixth>, ps7: PropertyState<TSeventh>, ps8: PropertyState<TEighth>, ps9: PropertyState<TNinth>, ps10: PropertyState<TTenth>, ps11: PropertyState<TEleventh>, ps12: PropertyState<TTwelfth>, ps13: PropertyState<TThirteenth>, ps14: PropertyState<TFourteenth>, ps15: PropertyState<TFifteenth>, ps16: PropertyState<TSixteenth>, ps17: PropertyState<TSeventeenth>, ps18: PropertyState<TEighteenth>, ps19: PropertyState<TNineteenth>, ps20: PropertyState<TTwentieth>, ps21: PropertyState<TTwentyFirst>, ps22: PropertyState<TTwentySecond>, ps23: PropertyState<TTwentyThird>, isAdditionalStateCorrectFunction: (TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TEighth, TNinth, TTenth, TEleventh, TTwelfth, TThirteenth, TFourteenth, TFifteenth, TSixteenth, TSeventeenth, TEighteenth, TNineteenth, TTwentieth, TTwentyFirst, TTwentySecond, TTwentyThird) -> Boolean? = null): TResult?
fun <TResult : Any, TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TEighth, TNinth, TTenth, TEleventh, TTwelfth, TThirteenth, TFourteenth, TFifteenth, TSixteenth, TSeventeenth, TEighteenth, TNineteenth, TTwentieth, TTwentyFirst, TTwentySecond, TTwentyThird, TTwentyFourth> toStateOrNull(constructor: (TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TEighth, TNinth, TTenth, TEleventh, TTwelfth, TThirteenth, TFourteenth, TFifteenth, TSixteenth, TSeventeenth, TEighteenth, TNineteenth, TTwentieth, TTwentyFirst, TTwentySecond, TTwentyThird, TTwentyFourth) -> TResult, ps1: PropertyState<TFirst>, ps2: PropertyState<TSecond>, ps3: PropertyState<TThird>, ps4: PropertyState<TFourth>, ps5: PropertyState<TFifth>, ps6: PropertyState<TSixth>, ps7: PropertyState<TSeventh>, ps8: PropertyState<TEighth>, ps9: PropertyState<TNinth>, ps10: PropertyState<TTenth>, ps11: PropertyState<TEleventh>, ps12: PropertyState<TTwelfth>, ps13: PropertyState<TThirteenth>, ps14: PropertyState<TFourteenth>, ps15: PropertyState<TFifteenth>, ps16: PropertyState<TSixteenth>, ps17: PropertyState<TSeventeenth>, ps18: PropertyState<TEighteenth>, ps19: PropertyState<TNineteenth>, ps20: PropertyState<TTwentieth>, ps21: PropertyState<TTwentyFirst>, ps22: PropertyState<TTwentySecond>, ps23: PropertyState<TTwentyThird>, ps24: PropertyState<TTwentyFourth>, isAdditionalStateCorrectFunction: (TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TEighth, TNinth, TTenth, TEleventh, TTwelfth, TThirteenth, TFourteenth, TFifteenth, TSixteenth, TSeventeenth, TEighteenth, TNineteenth, TTwentieth, TTwentyFirst, TTwentySecond, TTwentyThird, TTwentyFourth) -> Boolean? = null): TResult?
fun <TResult : Any, TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TEighth, TNinth, TTenth, TEleventh, TTwelfth, TThirteenth, TFourteenth, TFifteenth, TSixteenth, TSeventeenth, TEighteenth, TNineteenth, TTwentieth, TTwentyFirst, TTwentySecond, TTwentyThird, TTwentyFourth, TTwentyFifth> toStateOrNull(constructor: (TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TEighth, TNinth, TTenth, TEleventh, TTwelfth, TThirteenth, TFourteenth, TFifteenth, TSixteenth, TSeventeenth, TEighteenth, TNineteenth, TTwentieth, TTwentyFirst, TTwentySecond, TTwentyThird, TTwentyFourth, TTwentyFifth) -> TResult, ps1: PropertyState<TFirst>, ps2: PropertyState<TSecond>, ps3: PropertyState<TThird>, ps4: PropertyState<TFourth>, ps5: PropertyState<TFifth>, ps6: PropertyState<TSixth>, ps7: PropertyState<TSeventh>, ps8: PropertyState<TEighth>, ps9: PropertyState<TNinth>, ps10: PropertyState<TTenth>, ps11: PropertyState<TEleventh>, ps12: PropertyState<TTwelfth>, ps13: PropertyState<TThirteenth>, ps14: PropertyState<TFourteenth>, ps15: PropertyState<TFifteenth>, ps16: PropertyState<TSixteenth>, ps17: PropertyState<TSeventeenth>, ps18: PropertyState<TEighteenth>, ps19: PropertyState<TNineteenth>, ps20: PropertyState<TTwentieth>, ps21: PropertyState<TTwentyFirst>, ps22: PropertyState<TTwentySecond>, ps23: PropertyState<TTwentyThird>, ps24: PropertyState<TTwentyFourth>, ps25: PropertyState<TTwentyFifth>, isAdditionalStateCorrectFunction: (TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TEighth, TNinth, TTenth, TEleventh, TTwelfth, TThirteenth, TFourteenth, TFifteenth, TSixteenth, TSeventeenth, TEighteenth, TNineteenth, TTwentieth, TTwentyFirst, TTwentySecond, TTwentyThird, TTwentyFourth, TTwentyFifth) -> Boolean? = null): TResult?

Create an object with a known, correct state, if all the property states are correct. Each property is validated separately, and it is also possible to validate the combination of properties.