mirror of
https://github.com/corda/corda.git
synced 2025-06-13 04:38:19 +00:00
[CORDA-1993]: Replace reflection-based NodeConfiguration parsing with versioned property-based parsing mechanism. (#4132)
This commit is contained in:
committed by
GitHub
parent
9277042db8
commit
6c749889d0
@ -4,6 +4,7 @@ import com.typesafe.config.Config
|
||||
import com.typesafe.config.ConfigException
|
||||
import com.typesafe.config.ConfigObject
|
||||
import com.typesafe.config.ConfigValue
|
||||
import com.typesafe.config.ConfigValueFactory
|
||||
import net.corda.common.configuration.parsing.internal.versioned.VersionExtractor
|
||||
import net.corda.common.validation.internal.Validated
|
||||
import net.corda.common.validation.internal.Validated.Companion.invalid
|
||||
@ -24,7 +25,7 @@ object Configuration {
|
||||
/**
|
||||
* Describes a [Config] hiding sensitive data.
|
||||
*/
|
||||
fun describe(configuration: Config): ConfigValue
|
||||
fun describe(configuration: Config, serialiseValue: (Any) -> ConfigValue = { value -> ConfigValueFactory.fromAnyRef(value.toString()) }): ConfigValue?
|
||||
}
|
||||
|
||||
object Value {
|
||||
@ -112,6 +113,11 @@ object Configuration {
|
||||
*/
|
||||
interface Definition<TYPE> : Configuration.Property.Metadata, Configuration.Validator, Configuration.Value.Extractor<TYPE>, Configuration.Describer, Configuration.Value.Parser<TYPE> {
|
||||
|
||||
/**
|
||||
* Validates target [Config] with default [Configuration.Validation.Options].
|
||||
*/
|
||||
fun validate(target: Config): Valid<Config> = validate(target, Configuration.Validation.Options.defaults)
|
||||
|
||||
override fun isSpecifiedBy(configuration: Config): Boolean = configuration.hasPath(key)
|
||||
|
||||
/**
|
||||
@ -120,9 +126,9 @@ object Configuration {
|
||||
interface Required<TYPE> : Definition<TYPE> {
|
||||
|
||||
/**
|
||||
* Returns an optional property with given [defaultValue]. This property does not produce errors in case the value is unspecified, returning the [defaultValue] instead.
|
||||
* Returns an optional property. This property does not produce errors in case the value is unspecified.
|
||||
*/
|
||||
fun optional(defaultValue: TYPE? = null): Definition<TYPE?>
|
||||
fun optional(): Optional<TYPE>
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,6 +142,17 @@ object Configuration {
|
||||
fun list(): Required<List<TYPE>>
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a property that might be missing, resulting in a null value.
|
||||
*/
|
||||
interface Optional<TYPE> : Definition<TYPE?> {
|
||||
|
||||
/**
|
||||
* Allows to specify a [defaultValue], returning a required [Configuration.Property.Definition].
|
||||
*/
|
||||
fun withDefaultValue(defaultValue: TYPE): Definition<TYPE>
|
||||
}
|
||||
|
||||
/**
|
||||
* Default property definition, required and single-value.
|
||||
*/
|
||||
@ -219,7 +236,7 @@ object Configuration {
|
||||
|
||||
/**
|
||||
* Returns a [Configuration.Property.Definition.Standard] with value of type [ENUM].
|
||||
* This property expects the exact [ENUM] value specified as text for the relevant key.
|
||||
* This property expects a value in the configuration matching one of the cases of [ENUM], as text, in uppercase.
|
||||
*/
|
||||
fun <ENUM : Enum<ENUM>> enum(key: String, enumClass: KClass<ENUM>, sensitive: Boolean = false): Standard<ENUM> = StandardProperty(key, enumClass.java.simpleName, { conf: Config, propertyKey: String -> conf.getEnum(enumClass.java, propertyKey) }, { conf: Config, propertyKey: String -> conf.getEnumList(enumClass.java, propertyKey) }, sensitive)
|
||||
}
|
||||
@ -246,6 +263,13 @@ object Configuration {
|
||||
*/
|
||||
val properties: Set<Property.Definition<*>>
|
||||
|
||||
/**
|
||||
* Validates target [Config] with default [Configuration.Validation.Options].
|
||||
*/
|
||||
fun validate(target: Config): Valid<Config> = validate(target, Configuration.Validation.Options.defaults)
|
||||
|
||||
override fun describe(configuration: Config, serialiseValue: (Any) -> ConfigValue): ConfigValue
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
@ -270,7 +294,7 @@ object Configuration {
|
||||
* A [Configuration.Schema] that is also able to parse a raw [Config] object into a [VALUE].
|
||||
* It is an abstract class to allow extension with delegated properties e.g., object Settings: Specification() { val address by string().optional("localhost:8080") }.
|
||||
*/
|
||||
abstract class Specification<VALUE>(name: String?, private val prefix: String? = null) : Configuration.Schema, Configuration.Value.Parser<VALUE> {
|
||||
abstract class Specification<VALUE>(override val name: String, private val prefix: String? = null) : Configuration.Schema, Configuration.Value.Parser<VALUE> {
|
||||
|
||||
private val mutableProperties = mutableSetOf<Property.Definition<*>>()
|
||||
|
||||
@ -321,17 +345,20 @@ object Configuration {
|
||||
|
||||
/**
|
||||
* Returns a delegate for a [Configuration.Property.Definition.Standard] of type [ENUM].
|
||||
* This property expects the exact [ENUM] value specified as text for the relevant key.
|
||||
* This property expects a value in the configuration matching one of the cases of [ENUM], as text, in uppercase.
|
||||
*/
|
||||
fun <ENUM : Enum<ENUM>> enum(key: String? = null, enumClass: KClass<ENUM>, sensitive: Boolean = false): PropertyDelegate.Standard<ENUM> = PropertyDelegate.enum(key, prefix, enumClass, sensitive) { mutableProperties.add(it) }
|
||||
|
||||
override val name: String? get() = schema.name
|
||||
/**
|
||||
* @see enum
|
||||
*/
|
||||
fun <ENUM : Enum<ENUM>> enum(enumClass: KClass<ENUM>, sensitive: Boolean = false): PropertyDelegate.Standard<ENUM> = enum(key = null, enumClass = enumClass, sensitive = sensitive)
|
||||
|
||||
override fun description() = schema.description()
|
||||
|
||||
override fun validate(target: Config, options: Validation.Options?) = schema.validate(target, options)
|
||||
override fun validate(target: Config, options: Validation.Options) = schema.validate(target, options)
|
||||
|
||||
override fun describe(configuration: Config) = schema.describe(configuration)
|
||||
override fun describe(configuration: Config, serialiseValue: (Any) -> ConfigValue) = schema.describe(configuration, serialiseValue)
|
||||
|
||||
final override fun parse(configuration: Config, options: Configuration.Validation.Options): Valid<VALUE> = validate(configuration, options).mapValid(::parseValid)
|
||||
|
||||
@ -397,9 +424,11 @@ object Configuration {
|
||||
val containingPathAsString: String = containingPath.joinToString(".")
|
||||
|
||||
/**
|
||||
* [pathstr] joined by "." characters.
|
||||
* [path] joined by "." characters.
|
||||
*/
|
||||
val pathAsString: String = path.joinToString(".")
|
||||
val pathAsString: String get() = path.joinToString(".")
|
||||
|
||||
internal fun withContainingPathPrefix(vararg containingPath: String): Error = withContainingPath(*(containingPath.toList() + this.containingPath).toTypedArray())
|
||||
|
||||
internal abstract fun withContainingPath(vararg containingPath: String): Error
|
||||
|
||||
@ -415,12 +444,14 @@ object Configuration {
|
||||
*/
|
||||
class WrongType private constructor(override val keyName: String, override val typeName: String, message: String, containingPath: List<String> = emptyList()) : Configuration.Validation.Error(keyName, typeName, message, containingPath) {
|
||||
|
||||
internal companion object {
|
||||
companion object {
|
||||
|
||||
internal fun of(message: String, keyName: String = UNKNOWN, typeName: String = UNKNOWN, containingPath: List<String> = emptyList()): WrongType = contextualize(keyName, containingPath).let { (key, path) -> WrongType(key, typeName, message, path) }
|
||||
fun of(message: String, keyName: String? = null, typeName: String = UNKNOWN, containingPath: List<String> = emptyList()): WrongType = contextualize(keyName ?: UNKNOWN, containingPath).let { (key, path) -> WrongType(key, typeName, message, path) }
|
||||
|
||||
fun forKey(keyName: String, expectedTypeName: String, actualTypeName: String): WrongType = of("$keyName has type ${actualTypeName.toUpperCase()} rather than ${expectedTypeName.toUpperCase()}")
|
||||
}
|
||||
|
||||
override fun withContainingPath(vararg containingPath: String) = WrongType(keyName, typeName, message, containingPath.toList() + this.containingPath)
|
||||
override fun withContainingPath(vararg containingPath: String) = WrongType(keyName, typeName, message, containingPath.toList())
|
||||
|
||||
override fun with(keyName: String, typeName: String): WrongType = WrongType.of(message, keyName, typeName, containingPath)
|
||||
}
|
||||
@ -430,12 +461,14 @@ object Configuration {
|
||||
*/
|
||||
class MissingValue private constructor(override val keyName: String, override val typeName: String, message: String, containingPath: List<String> = emptyList()) : Configuration.Validation.Error(keyName, typeName, message, containingPath) {
|
||||
|
||||
internal companion object {
|
||||
companion object {
|
||||
|
||||
internal fun of(message: String, keyName: String = UNKNOWN, typeName: String = UNKNOWN, containingPath: List<String> = emptyList()): MissingValue = contextualize(keyName, containingPath).let { (key, path) -> MissingValue(key, typeName, message, path) }
|
||||
fun of(message: String, keyName: String? = null, typeName: String = UNKNOWN, containingPath: List<String> = emptyList()): MissingValue = contextualize(keyName ?: UNKNOWN, containingPath).let { (key, path) -> MissingValue(key, typeName, message, path) }
|
||||
|
||||
fun forKey(keyName: String): MissingValue = of("No configuration setting found for key '$keyName'", keyName)
|
||||
}
|
||||
|
||||
override fun withContainingPath(vararg containingPath: String) = MissingValue(keyName, typeName, message, containingPath.toList() + this.containingPath)
|
||||
override fun withContainingPath(vararg containingPath: String) = MissingValue(keyName, typeName, message, containingPath.toList())
|
||||
|
||||
override fun with(keyName: String, typeName: String): MissingValue = MissingValue.of(message, keyName, typeName, containingPath)
|
||||
}
|
||||
@ -445,12 +478,12 @@ object Configuration {
|
||||
*/
|
||||
class BadValue private constructor(override val keyName: String, override val typeName: String, message: String, containingPath: List<String> = emptyList()) : Configuration.Validation.Error(keyName, typeName, message, containingPath) {
|
||||
|
||||
internal companion object {
|
||||
companion object {
|
||||
|
||||
internal fun of(message: String, keyName: String = UNKNOWN, typeName: String = UNKNOWN, containingPath: List<String> = emptyList()): BadValue = contextualize(keyName, containingPath).let { (key, path) -> BadValue(key, typeName, message, path) }
|
||||
fun of(message: String, keyName: String? = null, typeName: String = UNKNOWN, containingPath: List<String> = emptyList()): BadValue = contextualize(keyName ?: UNKNOWN, containingPath).let { (key, path) -> BadValue(key, typeName, message, path) }
|
||||
}
|
||||
|
||||
override fun withContainingPath(vararg containingPath: String) = BadValue(keyName, typeName, message, containingPath.toList() + this.containingPath)
|
||||
override fun withContainingPath(vararg containingPath: String) = BadValue(keyName, typeName, message, containingPath.toList())
|
||||
|
||||
override fun with(keyName: String, typeName: String): BadValue = BadValue.of(message, keyName, typeName, containingPath)
|
||||
}
|
||||
@ -460,12 +493,12 @@ object Configuration {
|
||||
*/
|
||||
class BadPath private constructor(override val keyName: String, override val typeName: String, message: String, containingPath: List<String> = emptyList()) : Configuration.Validation.Error(keyName, typeName, message, containingPath) {
|
||||
|
||||
internal companion object {
|
||||
companion object {
|
||||
|
||||
internal fun of(message: String, keyName: String = UNKNOWN, typeName: String = UNKNOWN, containingPath: List<String> = emptyList()): BadPath = contextualize(keyName, containingPath).let { (key, path) -> BadPath(key, typeName, message, path) }
|
||||
fun of(message: String, keyName: String? = null, typeName: String = UNKNOWN, containingPath: List<String> = emptyList()): BadPath = contextualize(keyName ?: UNKNOWN, containingPath).let { (key, path) -> BadPath(key, typeName, message, path) }
|
||||
}
|
||||
|
||||
override fun withContainingPath(vararg containingPath: String) = BadPath(keyName, typeName, message, containingPath.toList() + this.containingPath)
|
||||
override fun withContainingPath(vararg containingPath: String) = BadPath(keyName, typeName, message, containingPath.toList())
|
||||
|
||||
override fun with(keyName: String, typeName: String): BadPath = BadPath.of(message, keyName, typeName, containingPath)
|
||||
}
|
||||
@ -475,12 +508,12 @@ object Configuration {
|
||||
*/
|
||||
class MalformedStructure private constructor(override val keyName: String, override val typeName: String, message: String, containingPath: List<String> = emptyList()) : Configuration.Validation.Error(keyName, typeName, message, containingPath) {
|
||||
|
||||
internal companion object {
|
||||
companion object {
|
||||
|
||||
internal fun of(message: String, keyName: String = UNKNOWN, typeName: String = UNKNOWN, containingPath: List<String> = emptyList()): MalformedStructure = contextualize(keyName, containingPath).let { (key, path) -> MalformedStructure(key, typeName, message, path) }
|
||||
fun of(message: String, keyName: String? = null, typeName: String = UNKNOWN, containingPath: List<String> = emptyList()): MalformedStructure = contextualize(keyName ?: UNKNOWN, containingPath).let { (key, path) -> MalformedStructure(key, typeName, message, path) }
|
||||
}
|
||||
|
||||
override fun withContainingPath(vararg containingPath: String) = MalformedStructure(keyName, typeName, message, containingPath.toList() + this.containingPath)
|
||||
override fun withContainingPath(vararg containingPath: String) = MalformedStructure(keyName, typeName, message, containingPath.toList())
|
||||
|
||||
override fun with(keyName: String, typeName: String): MalformedStructure = MalformedStructure.of(message, keyName, typeName, containingPath)
|
||||
}
|
||||
@ -490,16 +523,14 @@ object Configuration {
|
||||
*/
|
||||
class Unknown private constructor(override val keyName: String, containingPath: List<String> = emptyList()) : Configuration.Validation.Error(keyName, null, message(keyName), containingPath) {
|
||||
|
||||
internal companion object {
|
||||
companion object {
|
||||
|
||||
private fun message(keyName: String) = "Unknown property \"$keyName\"."
|
||||
private fun message(keyName: String) = "Unknown property \'$keyName\'"
|
||||
|
||||
internal fun of(keyName: String = UNKNOWN, containingPath: List<String> = emptyList()): Unknown = contextualize(keyName, containingPath).let { (key, path) -> Unknown(key, path) }
|
||||
fun of(keyName: String = UNKNOWN, containingPath: List<String> = emptyList()): Unknown = contextualize(keyName, containingPath).let { (key, path) -> Unknown(key, path) }
|
||||
}
|
||||
|
||||
override val message = message(pathAsString)
|
||||
|
||||
override fun withContainingPath(vararg containingPath: String) = Unknown(keyName, containingPath.toList() + this.containingPath)
|
||||
override fun withContainingPath(vararg containingPath: String) = Unknown(keyName, containingPath.toList())
|
||||
|
||||
override fun with(keyName: String, typeName: String): Unknown = Unknown.of(keyName, containingPath)
|
||||
}
|
||||
@ -509,12 +540,12 @@ object Configuration {
|
||||
*/
|
||||
class UnsupportedVersion private constructor(val version: Int, containingPath: List<String> = emptyList()) : Configuration.Validation.Error(null, null, "Unknown configuration version $version.", containingPath) {
|
||||
|
||||
internal companion object {
|
||||
companion object {
|
||||
|
||||
internal fun of(version: Int): UnsupportedVersion = UnsupportedVersion(version)
|
||||
fun of(version: Int): UnsupportedVersion = UnsupportedVersion(version)
|
||||
}
|
||||
|
||||
override fun withContainingPath(vararg containingPath: String) = UnsupportedVersion(version, containingPath.toList() + this.containingPath)
|
||||
override fun withContainingPath(vararg containingPath: String) = UnsupportedVersion(version, containingPath.toList())
|
||||
|
||||
override fun with(keyName: String, typeName: String): UnsupportedVersion = this
|
||||
}
|
||||
@ -526,16 +557,16 @@ object Configuration {
|
||||
/**
|
||||
* Defines the contract from extracting a specification version from a [Config] object.
|
||||
*/
|
||||
interface Extractor : Configuration.Value.Parser<Int?> {
|
||||
interface Extractor : Configuration.Value.Parser<Int> {
|
||||
|
||||
companion object {
|
||||
|
||||
const val DEFAULT_VERSION_VALUE = 1
|
||||
|
||||
/**
|
||||
* Returns a [Configuration.Version.Extractor] that reads the value from given [versionKey], defaulting to [versionDefaultValue] when [versionKey] is unspecified.
|
||||
* Returns a [Configuration.Version.Extractor] that reads the value from given [versionPath], defaulting to [versionDefaultValue] when [versionPath] is unspecified.
|
||||
*/
|
||||
fun fromKey(versionKey: String, versionDefaultValue: Int? = DEFAULT_VERSION_VALUE): Configuration.Version.Extractor = VersionExtractor(versionKey, versionDefaultValue)
|
||||
fun fromPath(versionPath: String, versionDefaultValue: Int = DEFAULT_VERSION_VALUE): Configuration.Version.Extractor = VersionExtractor(versionPath, versionDefaultValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,17 @@
|
||||
package net.corda.common.configuration.parsing.internal
|
||||
|
||||
import com.typesafe.config.*
|
||||
import com.typesafe.config.Config
|
||||
import com.typesafe.config.ConfigException
|
||||
import com.typesafe.config.ConfigObject
|
||||
import com.typesafe.config.ConfigValue
|
||||
import com.typesafe.config.ConfigValueFactory
|
||||
import net.corda.common.validation.internal.Validated
|
||||
import net.corda.common.validation.internal.Validated.Companion.invalid
|
||||
import net.corda.common.validation.internal.Validated.Companion.valid
|
||||
|
||||
internal class LongProperty(key: String, sensitive: Boolean = false) : StandardProperty<Long>(key, Long::class.javaObjectType.simpleName, Config::getLong, Config::getLongList, sensitive) {
|
||||
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options?): Valid<Config> {
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> {
|
||||
|
||||
val validated = super.validate(target, options)
|
||||
if (validated.isValid && target.getValue(key).unwrapped().toString().contains(".")) {
|
||||
@ -17,7 +21,7 @@ internal class LongProperty(key: String, sensitive: Boolean = false) : StandardP
|
||||
}
|
||||
}
|
||||
|
||||
internal open class StandardProperty<TYPE>(override val key: String, typeNameArg: String, private val extractSingleValue: (Config, String) -> TYPE, internal val extractListValue: (Config, String) -> List<TYPE>, override val isSensitive: Boolean = false, final override val schema: Configuration.Schema? = null) : Configuration.Property.Definition.Standard<TYPE> {
|
||||
internal open class StandardProperty<TYPE : Any>(override val key: String, typeNameArg: String, private val extractSingleValue: (Config, String) -> TYPE, internal val extractListValue: (Config, String) -> List<TYPE>, override val isSensitive: Boolean = false, final override val schema: Configuration.Schema? = null) : Configuration.Property.Definition.Standard<TYPE> {
|
||||
|
||||
override fun valueIn(configuration: Config) = extractSingleValue.invoke(configuration, key)
|
||||
|
||||
@ -25,21 +29,21 @@ internal open class StandardProperty<TYPE>(override val key: String, typeNameArg
|
||||
|
||||
override fun <MAPPED : Any> mapValid(mappedTypeName: String, convert: (TYPE) -> Valid<MAPPED>): Configuration.Property.Definition.Standard<MAPPED> = FunctionalProperty(this, mappedTypeName, extractListValue, convert)
|
||||
|
||||
override fun optional(defaultValue: TYPE?): Configuration.Property.Definition<TYPE?> = OptionalProperty(this, defaultValue)
|
||||
override fun optional(): Configuration.Property.Definition.Optional<TYPE> = OptionalDelegatedProperty(this)
|
||||
|
||||
override fun list(): Configuration.Property.Definition.Required<List<TYPE>> = ListProperty(this)
|
||||
|
||||
override fun describe(configuration: Config): ConfigValue {
|
||||
override fun describe(configuration: Config, serialiseValue: (Any) -> ConfigValue): ConfigValue {
|
||||
|
||||
if (isSensitive) {
|
||||
return ConfigValueFactory.fromAnyRef(Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER)
|
||||
return valueDescription(Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER, serialiseValue)
|
||||
}
|
||||
return schema?.describe(configuration.getConfig(key)) ?: ConfigValueFactory.fromAnyRef(valueIn(configuration))
|
||||
return schema?.describe(configuration.getConfig(key), serialiseValue) ?: valueDescription(valueIn(configuration), serialiseValue)
|
||||
}
|
||||
|
||||
override val isMandatory = true
|
||||
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options?): Valid<Config> {
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> {
|
||||
|
||||
val errors = mutableSetOf<Configuration.Validation.Error>()
|
||||
errors += errorsWhenExtractingValue(target)
|
||||
@ -47,7 +51,7 @@ internal open class StandardProperty<TYPE>(override val key: String, typeNameArg
|
||||
schema?.let { nestedSchema ->
|
||||
val nestedConfig: Config? = target.getConfig(key)
|
||||
nestedConfig?.let {
|
||||
errors += nestedSchema.validate(nestedConfig, options).errors.map { error -> error.withContainingPath(*key.split(".").toTypedArray()) }
|
||||
errors += nestedSchema.validate(nestedConfig, options).errors.map { error -> error.withContainingPathPrefix(*key.split(".").toTypedArray()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -57,63 +61,63 @@ internal open class StandardProperty<TYPE>(override val key: String, typeNameArg
|
||||
override fun toString() = "\"$key\": \"$typeName\""
|
||||
}
|
||||
|
||||
private class ListProperty<TYPE>(delegate: StandardProperty<TYPE>) : RequiredDelegatedProperty<List<TYPE>, StandardProperty<TYPE>>(delegate) {
|
||||
private class ListProperty<TYPE : Any>(delegate: StandardProperty<TYPE>) : RequiredDelegatedProperty<List<TYPE>, StandardProperty<TYPE>>(delegate) {
|
||||
|
||||
override val typeName: String = "List<${delegate.typeName}>"
|
||||
|
||||
override fun valueIn(configuration: Config): List<TYPE> = delegate.extractListValue.invoke(configuration, key)
|
||||
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options?): Valid<Config> {
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> {
|
||||
|
||||
val errors = mutableSetOf<Configuration.Validation.Error>()
|
||||
errors += errorsWhenExtractingValue(target)
|
||||
if (errors.isEmpty()) {
|
||||
delegate.schema?.let { schema ->
|
||||
errors += valueIn(target).asSequence().map { element -> element as ConfigObject }.map(ConfigObject::toConfig).mapIndexed { index, targetConfig -> schema.validate(targetConfig, options).errors.map { error -> error.withContainingPath(key, "[$index]") } }.reduce { one, other -> one + other }
|
||||
errors += valueIn(target).asSequence().map { element -> element as ConfigObject }.map(ConfigObject::toConfig).mapIndexed { index, targetConfig -> schema.validate(targetConfig, options).errors.map { error -> error.withContainingPath(*error.containingPath(index).toTypedArray()) } }.fold(emptyList<Configuration.Validation.Error>()) { one, other -> one + other }.toSet()
|
||||
}
|
||||
}
|
||||
return Validated.withResult(target, errors)
|
||||
}
|
||||
|
||||
override fun describe(configuration: Config): ConfigValue {
|
||||
override fun describe(configuration: Config, serialiseValue: (Any) -> ConfigValue): ConfigValue {
|
||||
|
||||
if (isSensitive) {
|
||||
return ConfigValueFactory.fromAnyRef(Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER)
|
||||
return valueDescription(Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER, serialiseValue)
|
||||
}
|
||||
return when {
|
||||
delegate.schema != null -> {
|
||||
val elementsDescription = valueIn(configuration).asSequence().map { it as ConfigObject }.map(ConfigObject::toConfig).map { delegate.schema.describe(it, serialiseValue) }.toList()
|
||||
ConfigValueFactory.fromIterable(elementsDescription)
|
||||
}
|
||||
else -> valueDescription(valueIn(configuration), serialiseValue)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Configuration.Validation.Error.containingPath(index: Int): List<String> {
|
||||
val newContainingPath = listOf(key, "[$index]")
|
||||
return when {
|
||||
containingPath.size > 1 -> newContainingPath + containingPath.subList(1, containingPath.size)
|
||||
else -> newContainingPath
|
||||
}
|
||||
return delegate.schema?.let { schema -> ConfigValueFactory.fromAnyRef(valueIn(configuration).asSequence().map { element -> element as ConfigObject }.map(ConfigObject::toConfig).map { schema.describe(it) }.toList()) } ?: ConfigValueFactory.fromAnyRef(valueIn(configuration))
|
||||
}
|
||||
}
|
||||
|
||||
private class OptionalProperty<TYPE>(delegate: Configuration.Property.Definition.Required<TYPE>, private val defaultValue: TYPE?) : DelegatedProperty<TYPE?, Configuration.Property.Definition.Required<TYPE>>(delegate) {
|
||||
private class OptionalPropertyWithDefault<TYPE : Any>(delegate: Configuration.Property.Definition.Optional<TYPE>, private val defaultValue: TYPE) : DelegatedProperty<TYPE, Configuration.Property.Definition.Optional<TYPE>>(delegate) {
|
||||
|
||||
override val isMandatory: Boolean = false
|
||||
|
||||
override val typeName: String = "${super.typeName}?"
|
||||
override val typeName: String = delegate.typeName.removeSuffix("?")
|
||||
|
||||
override fun describe(configuration: Config) = delegate.describe(configuration)
|
||||
override fun describe(configuration: Config, serialiseValue: (Any) -> ConfigValue): ConfigValue? = delegate.describe(configuration, serialiseValue) ?: valueDescription(if (isSensitive) Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER else defaultValue, serialiseValue)
|
||||
|
||||
override fun valueIn(configuration: Config): TYPE? {
|
||||
override fun valueIn(configuration: Config): TYPE = delegate.valueIn(configuration) ?: defaultValue
|
||||
|
||||
return when {
|
||||
isSpecifiedBy(configuration) -> delegate.valueIn(configuration)
|
||||
else -> defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options?): Valid<Config> {
|
||||
|
||||
val result = delegate.validate(target, options)
|
||||
val error = result.errors.asSequence().filterIsInstance<Configuration.Validation.Error.MissingValue>().singleOrNull()
|
||||
return when {
|
||||
error != null -> if (result.errors.size > 1) result else valid(target)
|
||||
else -> result
|
||||
}
|
||||
}
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> = delegate.validate(target, options)
|
||||
}
|
||||
|
||||
private class FunctionalProperty<TYPE, MAPPED : Any>(delegate: Configuration.Property.Definition.Standard<TYPE>, private val mappedTypeName: String, internal val extractListValue: (Config, String) -> List<TYPE>, private val convert: (TYPE) -> Valid<MAPPED>) : RequiredDelegatedProperty<MAPPED, Configuration.Property.Definition.Standard<TYPE>>(delegate), Configuration.Property.Definition.Standard<MAPPED> {
|
||||
|
||||
override fun valueIn(configuration: Config) = convert.invoke(delegate.valueIn(configuration)).valueOrThrow()
|
||||
override fun valueIn(configuration: Config) = convert.invoke(delegate.valueIn(configuration)).orThrow()
|
||||
|
||||
override val typeName: String = if (super.typeName == "#$mappedTypeName") super.typeName else "$mappedTypeName(${super.typeName})"
|
||||
|
||||
@ -121,7 +125,7 @@ private class FunctionalProperty<TYPE, MAPPED : Any>(delegate: Configuration.Pro
|
||||
|
||||
override fun list(): Configuration.Property.Definition.Required<List<MAPPED>> = FunctionalListProperty(this)
|
||||
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options?): Valid<Config> {
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> {
|
||||
|
||||
val errors = mutableSetOf<Configuration.Validation.Error>()
|
||||
errors += delegate.validate(target, options).errors
|
||||
@ -131,7 +135,7 @@ private class FunctionalProperty<TYPE, MAPPED : Any>(delegate: Configuration.Pro
|
||||
return Validated.withResult(target, errors)
|
||||
}
|
||||
|
||||
override fun describe(configuration: Config) = delegate.describe(configuration)
|
||||
override fun describe(configuration: Config, serialiseValue: (Any) -> ConfigValue) = delegate.describe(configuration, serialiseValue)
|
||||
}
|
||||
|
||||
private class FunctionalListProperty<RAW, TYPE : Any>(delegate: FunctionalProperty<RAW, TYPE>) : RequiredDelegatedProperty<List<TYPE>, FunctionalProperty<RAW, TYPE>>(delegate) {
|
||||
@ -140,7 +144,7 @@ private class FunctionalListProperty<RAW, TYPE : Any>(delegate: FunctionalProper
|
||||
|
||||
override fun valueIn(configuration: Config): List<TYPE> = delegate.extractListValue.invoke(configuration, key).asSequence().map { configObject(key to ConfigValueFactory.fromAnyRef(it)) }.map(ConfigObject::toConfig).map(delegate::valueIn).toList()
|
||||
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options?): Valid<Config> {
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> {
|
||||
|
||||
val list = try {
|
||||
delegate.extractListValue.invoke(target, key)
|
||||
@ -151,16 +155,24 @@ private class FunctionalListProperty<RAW, TYPE : Any>(delegate: FunctionalProper
|
||||
throw e
|
||||
}
|
||||
}
|
||||
val errors = list.asSequence().map { configObject(key to ConfigValueFactory.fromAnyRef(it)) }.mapIndexed { index, value -> delegate.validate(value.toConfig(), options).errors.map { error -> error.withContainingPath(key, "[$index]") } }.reduce { one, other -> one + other }.toSet()
|
||||
val errors = list.asSequence().map { configObject(key to ConfigValueFactory.fromAnyRef(it)) }.mapIndexed { index, value -> delegate.validate(value.toConfig(), options).errors.map { error -> error.withContainingPath(*error.containingPath(index).toTypedArray()) } }.fold(emptyList<Configuration.Validation.Error>()) { one, other -> one + other }.toSet()
|
||||
return Validated.withResult(target, errors)
|
||||
}
|
||||
|
||||
override fun describe(configuration: Config): ConfigValue {
|
||||
private fun Configuration.Validation.Error.containingPath(index: Int): List<String> {
|
||||
val newContainingPath = listOf(key, "[$index]")
|
||||
return when {
|
||||
containingPath.size > 1 -> newContainingPath + containingPath.subList(1, containingPath.size)
|
||||
else -> newContainingPath
|
||||
}
|
||||
}
|
||||
|
||||
override fun describe(configuration: Config, serialiseValue: (Any) -> ConfigValue): ConfigValue {
|
||||
|
||||
if (isSensitive) {
|
||||
return ConfigValueFactory.fromAnyRef(Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER)
|
||||
return valueDescription(Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER, serialiseValue)
|
||||
}
|
||||
return delegate.schema?.let { schema -> ConfigValueFactory.fromAnyRef(valueIn(configuration).asSequence().map { element -> element as ConfigObject }.map(ConfigObject::toConfig).map { schema.describe(it) }.toList()) } ?: ConfigValueFactory.fromAnyRef(valueIn(configuration))
|
||||
return delegate.schema?.let { schema -> valueDescription(valueIn(configuration).asSequence().map { element -> valueDescription(element, serialiseValue) }.map { it as ConfigObject }.map(ConfigObject::toConfig).map { schema.describe(it, serialiseValue) }.toList(), serialiseValue) } ?: valueDescription(valueIn(configuration), serialiseValue)
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,12 +181,45 @@ private abstract class DelegatedProperty<TYPE, DELEGATE : Configuration.Property
|
||||
final override fun toString() = "\"$key\": \"$typeName\""
|
||||
}
|
||||
|
||||
private abstract class RequiredDelegatedProperty<TYPE, DELEGATE : Configuration.Property.Definition.Required<*>>(delegate: DELEGATE) : DelegatedProperty<TYPE, DELEGATE>(delegate), Configuration.Property.Definition.Required<TYPE> {
|
||||
private class OptionalDelegatedProperty<TYPE : Any>(private val delegate: Configuration.Property.Definition<TYPE>) : Configuration.Property.Metadata by delegate, Configuration.Property.Definition.Optional<TYPE> {
|
||||
|
||||
final override fun optional(defaultValue: TYPE?): Configuration.Property.Definition<TYPE?> = OptionalProperty(this, defaultValue)
|
||||
override val isMandatory: Boolean = false
|
||||
|
||||
override val typeName: String = "${delegate.typeName}?"
|
||||
|
||||
override fun describe(configuration: Config, serialiseValue: (Any) -> ConfigValue) = if (isSpecifiedBy(configuration)) delegate.describe(configuration, serialiseValue) else null
|
||||
|
||||
override fun valueIn(configuration: Config): TYPE? {
|
||||
|
||||
return when {
|
||||
isSpecifiedBy(configuration) -> delegate.valueIn(configuration)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> {
|
||||
|
||||
val result = delegate.validate(target, options)
|
||||
val errors = result.errors
|
||||
val missingValueError = errors.asSequence().filterIsInstance<Configuration.Validation.Error.MissingValue>().filter { it.pathAsString == key }.singleOrNull()
|
||||
return when {
|
||||
missingValueError != null -> if (errors.size > 1) result else valid(target)
|
||||
else -> result
|
||||
}
|
||||
}
|
||||
|
||||
override fun withDefaultValue(defaultValue: TYPE): Configuration.Property.Definition<TYPE> = OptionalPropertyWithDefault(this, defaultValue)
|
||||
|
||||
override fun toString() = "\"$key\": \"$typeName\""
|
||||
}
|
||||
|
||||
private fun ConfigException.toValidationError(keyName: String, typeName: String): Configuration.Validation.Error {
|
||||
|
||||
private abstract class RequiredDelegatedProperty<TYPE : Any, DELEGATE : Configuration.Property.Definition.Required<*>>(delegate: DELEGATE) : DelegatedProperty<TYPE, DELEGATE>(delegate), Configuration.Property.Definition.Required<TYPE> {
|
||||
|
||||
final override fun optional(): Configuration.Property.Definition.Optional<TYPE> = OptionalDelegatedProperty(this)
|
||||
}
|
||||
|
||||
fun ConfigException.toValidationError(keyName: String? = null, typeName: String): Configuration.Validation.Error {
|
||||
|
||||
val toError = when (this) {
|
||||
is ConfigException.Missing -> Configuration.Validation.Error.MissingValue.Companion::of
|
||||
@ -202,4 +247,6 @@ private fun Configuration.Property.Definition<*>.errorsWhenExtractingValue(targe
|
||||
|
||||
private val expectedExceptionTypes = setOf(ConfigException.Missing::class, ConfigException.WrongType::class, ConfigException.BadValue::class, ConfigException.BadPath::class, ConfigException.Parse::class)
|
||||
|
||||
private fun isErrorExpected(error: ConfigException) = expectedExceptionTypes.any { expected -> expected.isInstance(error) }
|
||||
private fun isErrorExpected(error: ConfigException) = expectedExceptionTypes.any { expected -> expected.isInstance(error) }
|
||||
|
||||
private fun valueDescription(value: Any, serialiseValue: (Any) -> ConfigValue) = serialiseValue.invoke(value)
|
@ -16,10 +16,12 @@ internal class Schema(override val name: String?, unorderedProperties: Iterable<
|
||||
}
|
||||
}
|
||||
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options?): Valid<Config> {
|
||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> {
|
||||
|
||||
val propertyErrors = properties.flatMap { property -> property.validate(target, options).errors }.toMutableSet()
|
||||
if (options?.strict == true) {
|
||||
val propertyErrors = properties.flatMap { property ->
|
||||
property.validate(target, options).errors
|
||||
}.toMutableSet()
|
||||
if (options.strict) {
|
||||
val unknownKeys = target.root().keys - properties.map(Configuration.Property.Definition<*>::key)
|
||||
propertyErrors += unknownKeys.map { Configuration.Validation.Error.Unknown.of(it) }
|
||||
}
|
||||
@ -45,9 +47,9 @@ internal class Schema(override val name: String?, unorderedProperties: Iterable<
|
||||
return description.toString()
|
||||
}
|
||||
|
||||
override fun describe(configuration: Config): ConfigValue {
|
||||
override fun describe(configuration: Config, serialiseValue: (Any) -> ConfigValue): ConfigValue {
|
||||
|
||||
return properties.asSequence().map { it.key to it.describe(configuration) }.fold(configObject()) { config, (key, value) -> config.withValue(key, value) }
|
||||
return properties.asSequence().map { it.key to it.describe(configuration, serialiseValue) }.filter { it.second != null }.fold(configObject()) { config, (key, value) -> config.withValue(key, value) }
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
|
@ -14,7 +14,7 @@ interface PropertyDelegate<TYPE> {
|
||||
|
||||
operator fun provideDelegate(thisRef: Any?, property: KProperty<*>): ReadOnlyProperty<Any?, Configuration.Property.Definition.Required<TYPE>>
|
||||
|
||||
fun optional(defaultValue: TYPE? = null): PropertyDelegate<TYPE?>
|
||||
fun optional(): PropertyDelegate.Optional<TYPE>
|
||||
}
|
||||
|
||||
interface Single<TYPE> {
|
||||
@ -24,6 +24,13 @@ interface PropertyDelegate<TYPE> {
|
||||
fun list(): Required<List<TYPE>>
|
||||
}
|
||||
|
||||
interface Optional<TYPE> {
|
||||
|
||||
operator fun provideDelegate(thisRef: Any?, property: KProperty<*>): ReadOnlyProperty<Any?, Configuration.Property.Definition.Optional<TYPE>>
|
||||
|
||||
fun withDefaultValue(defaultValue: TYPE): PropertyDelegate<TYPE>
|
||||
}
|
||||
|
||||
interface Standard<TYPE> : Required<TYPE>, Single<TYPE> {
|
||||
|
||||
override operator fun provideDelegate(thisRef: Any?, property: KProperty<*>): ReadOnlyProperty<Any?, Configuration.Property.Definition.Standard<TYPE>>
|
||||
@ -67,35 +74,52 @@ private class PropertyDelegateImpl<TYPE>(private val key: String?, private val p
|
||||
}
|
||||
}
|
||||
|
||||
override fun list(): PropertyDelegate.Required<List<TYPE>> = ListPropertyDelegateImpl(key, sensitive, addToProperties, { k, s -> construct.invoke(k, s).list() })
|
||||
override fun list(): PropertyDelegate.Required<List<TYPE>> = ListPropertyDelegateImpl(key, prefix, sensitive, addToProperties, { k, s -> construct.invoke(k, s).list() })
|
||||
|
||||
override fun optional(defaultValue: TYPE?): PropertyDelegate<TYPE?> = OptionalPropertyDelegateImpl(key, sensitive, addToProperties, { k, s -> construct.invoke(k, s).optional(defaultValue) })
|
||||
override fun optional(): PropertyDelegate.Optional<TYPE> = OptionalPropertyDelegateImpl(key, prefix, sensitive, addToProperties, { k, s -> construct.invoke(k, s).optional() })
|
||||
|
||||
override fun <MAPPED : Any> mapValid(mappedTypeName: String, convert: (TYPE) -> Valid<MAPPED>): PropertyDelegate.Standard<MAPPED> = PropertyDelegateImpl(key, prefix, sensitive, addToProperties, { k, s -> construct.invoke(k, s).mapValid(mappedTypeName) { value -> convert.invoke(value) } })
|
||||
}
|
||||
|
||||
private class OptionalPropertyDelegateImpl<TYPE>(private val key: String?, private val sensitive: Boolean = false, private val addToProperties: (Configuration.Property.Definition<*>) -> Unit, private val construct: (String, Boolean) -> Configuration.Property.Definition<TYPE?>) : PropertyDelegate<TYPE?> {
|
||||
private class OptionalPropertyDelegateImpl<TYPE>(private val key: String?, private val prefix: String?, private val sensitive: Boolean = false, private val addToProperties: (Configuration.Property.Definition<*>) -> Unit, private val construct: (String, Boolean) -> Configuration.Property.Definition.Optional<TYPE>) : PropertyDelegate.Optional<TYPE> {
|
||||
|
||||
override operator fun provideDelegate(thisRef: Any?, property: KProperty<*>): ReadOnlyProperty<Any?, Configuration.Property.Definition<TYPE?>> {
|
||||
override operator fun provideDelegate(thisRef: Any?, property: KProperty<*>): ReadOnlyProperty<Any?, Configuration.Property.Definition.Optional<TYPE>> {
|
||||
|
||||
val prop = construct.invoke(key ?: property.name, sensitive).also(addToProperties)
|
||||
return object : ReadOnlyProperty<Any?, Configuration.Property.Definition<TYPE?>> {
|
||||
val shortName = key ?: property.name
|
||||
val prop = construct.invoke(prefix?.let { "$prefix.$shortName" } ?: shortName, sensitive).also(addToProperties)
|
||||
return object : ReadOnlyProperty<Any?, Configuration.Property.Definition.Optional<TYPE>> {
|
||||
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): Configuration.Property.Definition<TYPE?> = prop
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): Configuration.Property.Definition.Optional<TYPE> = prop
|
||||
}
|
||||
}
|
||||
|
||||
override fun withDefaultValue(defaultValue: TYPE): PropertyDelegate<TYPE> = OptionalWithDefaultPropertyDelegateImpl(key, prefix, sensitive, addToProperties, { k, s -> construct.invoke(k, s).withDefaultValue(defaultValue) })
|
||||
}
|
||||
|
||||
private class OptionalWithDefaultPropertyDelegateImpl<TYPE>(private val key: String?, private val prefix: String?, private val sensitive: Boolean = false, private val addToProperties: (Configuration.Property.Definition<*>) -> Unit, private val construct: (String, Boolean) -> Configuration.Property.Definition<TYPE>) : PropertyDelegate<TYPE> {
|
||||
|
||||
override operator fun provideDelegate(thisRef: Any?, property: KProperty<*>): ReadOnlyProperty<Any?, Configuration.Property.Definition<TYPE>> {
|
||||
|
||||
val shortName = key ?: property.name
|
||||
val prop = construct.invoke(prefix?.let { "$prefix.$shortName" } ?: shortName, sensitive).also(addToProperties)
|
||||
return object : ReadOnlyProperty<Any?, Configuration.Property.Definition<TYPE>> {
|
||||
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): Configuration.Property.Definition<TYPE> = prop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ListPropertyDelegateImpl<TYPE>(private val key: String?, private val sensitive: Boolean = false, private val addToProperties: (Configuration.Property.Definition<*>) -> Unit, private val construct: (String, Boolean) -> Configuration.Property.Definition.Required<TYPE>) : PropertyDelegate.Required<TYPE> {
|
||||
private class ListPropertyDelegateImpl<TYPE>(private val key: String?, private val prefix: String?, private val sensitive: Boolean = false, private val addToProperties: (Configuration.Property.Definition<*>) -> Unit, private val construct: (String, Boolean) -> Configuration.Property.Definition.Required<TYPE>) : PropertyDelegate.Required<TYPE> {
|
||||
|
||||
override operator fun provideDelegate(thisRef: Any?, property: KProperty<*>): ReadOnlyProperty<Any?, Configuration.Property.Definition.Required<TYPE>> {
|
||||
|
||||
val prop = construct.invoke(key ?: property.name, sensitive).also(addToProperties)
|
||||
val shortName = key ?: property.name
|
||||
val prop = construct.invoke(prefix?.let { "$prefix.$shortName" } ?: shortName, sensitive).also(addToProperties)
|
||||
return object : ReadOnlyProperty<Any?, Configuration.Property.Definition.Required<TYPE>> {
|
||||
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): Configuration.Property.Definition.Required<TYPE> = prop
|
||||
}
|
||||
}
|
||||
|
||||
override fun optional(defaultValue: TYPE?): PropertyDelegate<TYPE?> = OptionalPropertyDelegateImpl(key, sensitive, addToProperties, { k, s -> construct.invoke(k, s).optional(defaultValue) })
|
||||
override fun optional(): PropertyDelegate.Optional<TYPE> = OptionalPropertyDelegateImpl(key, prefix, sensitive, addToProperties, { k, s -> construct.invoke(k, s).optional() })
|
||||
}
|
@ -15,6 +15,10 @@ operator fun <TYPE> Config.get(property: Configuration.Property.Definition<TYPE>
|
||||
|
||||
inline fun <reified NESTED : Any> Configuration.Specification<*>.nested(specification: Configuration.Specification<NESTED>, key: String? = null, sensitive: Boolean = false): PropertyDelegate.Standard<NESTED> = nestedObject(schema = specification, key = key, sensitive = sensitive).map(ConfigObject::toConfig).mapValid { value -> specification.parse(value) }
|
||||
|
||||
fun <TYPE> Configuration.Property.Definition.Single<TYPE>.listOrEmpty(): Configuration.Property.Definition<List<TYPE>> = list().optional().withDefaultValue(emptyList())
|
||||
|
||||
fun <TYPE> PropertyDelegate.Single<TYPE>.listOrEmpty(): PropertyDelegate<List<TYPE>> = list().optional().withDefaultValue(emptyList())
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal fun configObject(vararg entries: Pair<String, Any?>): ConfigObject {
|
||||
|
||||
|
@ -5,18 +5,21 @@ import net.corda.common.configuration.parsing.internal.Configuration
|
||||
import net.corda.common.configuration.parsing.internal.Valid
|
||||
import net.corda.common.configuration.parsing.internal.valid
|
||||
|
||||
internal class VersionExtractor(versionKey: String, versionDefaultValue: Int?) : Configuration.Version.Extractor {
|
||||
internal class VersionExtractor(versionPath: String, versionDefaultValue: Int) : Configuration.Version.Extractor {
|
||||
|
||||
private val spec = Spec(versionKey, versionDefaultValue)
|
||||
private val containingPath = versionPath.split(".").let { if (it.size > 1) it.subList(0, it.size - 1) else null }
|
||||
private val key = versionPath.split(".").last()
|
||||
|
||||
override fun parse(configuration: Config, options: Configuration.Validation.Options): Valid<Int?> {
|
||||
private val spec = Spec(key, versionDefaultValue, containingPath?.joinToString("."))
|
||||
|
||||
override fun parse(configuration: Config, options: Configuration.Validation.Options): Valid<Int> {
|
||||
|
||||
return spec.parse(configuration)
|
||||
}
|
||||
|
||||
private class Spec(versionKey: String, versionDefaultValue: Int?) : Configuration.Specification<Int?>("Version") {
|
||||
private class Spec(key: String, versionDefaultValue: Int, prefix: String?) : Configuration.Specification<Int>("Version", prefix) {
|
||||
|
||||
private val version by int(key = versionKey).optional(versionDefaultValue)
|
||||
private val version by int(key = key).optional().withDefaultValue(versionDefaultValue)
|
||||
|
||||
override fun parseValid(configuration: Config) = valid(version.valueIn(configuration))
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ class PropertyTest {
|
||||
val configuration = configObject(key to null).toConfig()
|
||||
|
||||
val defaultValue = listOf(1L, 2L, 3L)
|
||||
val property = Configuration.Property.Definition.long(key).list().optional(defaultValue)
|
||||
val property = Configuration.Property.Definition.long(key).list().optional().withDefaultValue(defaultValue)
|
||||
println(property)
|
||||
|
||||
assertThat(property.key).isEqualTo(key)
|
||||
@ -173,7 +173,7 @@ class PropertyTest {
|
||||
val configuration = configObject(key to null).toConfig()
|
||||
|
||||
val defaultValue = 23L
|
||||
val property = Configuration.Property.Definition.long(key).optional(defaultValue)
|
||||
val property = Configuration.Property.Definition.long(key).optional().withDefaultValue(defaultValue)
|
||||
println(property)
|
||||
|
||||
assertThat(property.key).isEqualTo(key)
|
||||
|
@ -1,9 +1,7 @@
|
||||
package net.corda.common.configuration.parsing.internal
|
||||
|
||||
import com.typesafe.config.Config
|
||||
import net.corda.common.validation.internal.Validated.Companion.invalid
|
||||
import net.corda.common.validation.internal.Validated.Companion.valid
|
||||
import net.corda.common.validation.internal.Validator
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
@ -15,7 +13,7 @@ class PropertyValidationTest {
|
||||
val key = "a.b.c"
|
||||
val configuration = configObject().toConfig()
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.long(key)
|
||||
val property = Configuration.Property.Definition.long(key)
|
||||
|
||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
||||
|
||||
@ -34,7 +32,7 @@ class PropertyValidationTest {
|
||||
val key = "a.b.c"
|
||||
val configuration = configObject(key to null).toConfig()
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.long(key)
|
||||
val property = Configuration.Property.Definition.long(key)
|
||||
|
||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
||||
|
||||
@ -53,7 +51,7 @@ class PropertyValidationTest {
|
||||
val key = "a.b.c"
|
||||
val configuration = configObject().toConfig()
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.long(key).list()
|
||||
val property = Configuration.Property.Definition.long(key).list()
|
||||
|
||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
||||
|
||||
@ -72,7 +70,7 @@ class PropertyValidationTest {
|
||||
val key = "a.b.c"
|
||||
val configuration = configObject(key to null).toConfig()
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.long(key).list()
|
||||
val property = Configuration.Property.Definition.long(key).list()
|
||||
|
||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
||||
|
||||
@ -90,7 +88,7 @@ class PropertyValidationTest {
|
||||
|
||||
val key = "a.b.c"
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.long(key)
|
||||
val property = Configuration.Property.Definition.long(key)
|
||||
|
||||
val configuration = configObject(key to false).toConfig()
|
||||
|
||||
@ -110,7 +108,7 @@ class PropertyValidationTest {
|
||||
|
||||
val key = "a.b.c"
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.long(key)
|
||||
val property = Configuration.Property.Definition.long(key)
|
||||
|
||||
val configuration = configObject(key to 1.2).toConfig()
|
||||
|
||||
@ -130,7 +128,7 @@ class PropertyValidationTest {
|
||||
|
||||
val key = "a.b.c"
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.double(key)
|
||||
val property = Configuration.Property.Definition.double(key)
|
||||
|
||||
val configuration = configObject(key to 1).toConfig()
|
||||
|
||||
@ -142,7 +140,7 @@ class PropertyValidationTest {
|
||||
|
||||
val key = "a.b.c"
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.long(key).list()
|
||||
val property = Configuration.Property.Definition.long(key).list()
|
||||
|
||||
val configuration = configObject(key to listOf(false, true)).toConfig()
|
||||
|
||||
@ -162,7 +160,7 @@ class PropertyValidationTest {
|
||||
|
||||
val key = "a.b.c"
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.long(key)
|
||||
val property = Configuration.Property.Definition.long(key)
|
||||
|
||||
val configuration = configObject(key to listOf(1, 2, 3)).toConfig()
|
||||
|
||||
@ -182,7 +180,7 @@ class PropertyValidationTest {
|
||||
|
||||
val key = "a.b.c"
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.long(key).list()
|
||||
val property = Configuration.Property.Definition.long(key).list()
|
||||
|
||||
val configuration = configObject(key to 1).toConfig()
|
||||
|
||||
@ -205,7 +203,7 @@ class PropertyValidationTest {
|
||||
val nestedKey = "d"
|
||||
val nestedPropertySchema = Configuration.Schema.withProperties(Configuration.Property.Definition.long(nestedKey))
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.nestedObject(key, nestedPropertySchema)
|
||||
val property = Configuration.Property.Definition.nestedObject(key, nestedPropertySchema)
|
||||
|
||||
val configuration = configObject(key to configObject(nestedKey to false)).toConfig()
|
||||
|
||||
@ -228,7 +226,7 @@ class PropertyValidationTest {
|
||||
val nestedKey = "d"
|
||||
val nestedPropertySchema = Configuration.Schema.withProperties(Configuration.Property.Definition.long(nestedKey))
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.nestedObject(key, nestedPropertySchema)
|
||||
val property = Configuration.Property.Definition.nestedObject(key, nestedPropertySchema)
|
||||
|
||||
val configuration = configObject(key to configObject()).toConfig()
|
||||
|
||||
@ -251,7 +249,7 @@ class PropertyValidationTest {
|
||||
val nestedKey = "d"
|
||||
val nestedPropertySchema = Configuration.Schema.withProperties(Configuration.Property.Definition.long(nestedKey))
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.nestedObject(key, nestedPropertySchema)
|
||||
val property = Configuration.Property.Definition.nestedObject(key, nestedPropertySchema)
|
||||
|
||||
val configuration = configObject(key to configObject(nestedKey to null)).toConfig()
|
||||
|
||||
@ -273,7 +271,7 @@ class PropertyValidationTest {
|
||||
|
||||
val nestedKey = "d"
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.nestedObject(key)
|
||||
val property = Configuration.Property.Definition.nestedObject(key)
|
||||
|
||||
val configuration = configObject(key to configObject(nestedKey to false)).toConfig()
|
||||
|
||||
@ -285,7 +283,7 @@ class PropertyValidationTest {
|
||||
|
||||
val key = "a"
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.string(key).mapValid(::parseAddress)
|
||||
val property = Configuration.Property.Definition.string(key).mapValid(::parseAddress)
|
||||
|
||||
val host = "localhost"
|
||||
val port = 8080
|
||||
@ -301,7 +299,7 @@ class PropertyValidationTest {
|
||||
|
||||
val key = "a.b.c"
|
||||
|
||||
val property: Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options> = Configuration.Property.Definition.string(key).mapValid(::parseAddress)
|
||||
val property = Configuration.Property.Definition.string(key).mapValid(::parseAddress)
|
||||
|
||||
val host = "localhost"
|
||||
val port = 8080
|
||||
|
@ -39,7 +39,7 @@ class SpecificationTest {
|
||||
val rpcSettings = RpcSettingsSpec.parse(configuration)
|
||||
|
||||
assertThat(rpcSettings.isValid).isTrue()
|
||||
assertThat(rpcSettings.valueOrThrow()).satisfies { value ->
|
||||
assertThat(rpcSettings.orThrow()).satisfies { value ->
|
||||
|
||||
assertThat(value.useSsl).isEqualTo(useSslValue)
|
||||
assertThat(value.addresses).satisfies { addresses ->
|
||||
|
@ -9,8 +9,8 @@ import org.junit.Test
|
||||
|
||||
class VersionExtractorTest {
|
||||
|
||||
private val versionExtractor = Configuration.Version.Extractor.fromKey("configuration.metadata.version")
|
||||
private val extractVersion: (Config) -> Valid<Int?> = { config -> versionExtractor.parse(config) }
|
||||
private val versionExtractor = Configuration.Version.Extractor.fromPath("configuration.metadata.version")
|
||||
private val extractVersion: (Config) -> Valid<Int> = { config -> versionExtractor.parse(config) }
|
||||
|
||||
@Test
|
||||
fun version_header_extraction_present() {
|
||||
@ -18,7 +18,7 @@ class VersionExtractorTest {
|
||||
val versionValue = Configuration.Version.Extractor.DEFAULT_VERSION_VALUE + 1
|
||||
val rawConfiguration = configObject("configuration" to configObject("metadata" to configObject("version" to versionValue), "node" to configObject("p2pAddress" to "localhost:8080"))).toConfig()
|
||||
|
||||
val version = extractVersion.invoke(rawConfiguration).valueOrThrow()
|
||||
val version = extractVersion.invoke(rawConfiguration).orThrow()
|
||||
assertThat(version).isEqualTo(versionValue)
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ class VersionExtractorTest {
|
||||
|
||||
val rawConfiguration = configObject("configuration" to configObject("node" to configObject("p2pAddress" to "localhost:8080"))).toConfig()
|
||||
|
||||
val version = extractVersion.invoke(rawConfiguration).valueOrThrow()
|
||||
val version = extractVersion.invoke(rawConfiguration).orThrow()
|
||||
assertThat(version).isEqualTo(Configuration.Version.Extractor.DEFAULT_VERSION_VALUE)
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ class VersionExtractorTest {
|
||||
|
||||
val rawConfiguration = configObject("configuration" to configObject("metadata" to configObject(), "node" to configObject("p2pAddress" to "localhost:8080"))).toConfig()
|
||||
|
||||
val version = extractVersion.invoke(rawConfiguration).valueOrThrow()
|
||||
val version = extractVersion.invoke(rawConfiguration).orThrow()
|
||||
|
||||
assertThat(version).isEqualTo(Configuration.Version.Extractor.DEFAULT_VERSION_VALUE)
|
||||
}
|
||||
@ -46,7 +46,7 @@ class VersionExtractorTest {
|
||||
|
||||
val rawConfiguration = configObject("configuration" to configObject("metadata" to configObject("version" to null), "node" to configObject("p2pAddress" to "localhost:8080"))).toConfig()
|
||||
|
||||
val version = extractVersion.invoke(rawConfiguration).valueOrThrow()
|
||||
val version = extractVersion.invoke(rawConfiguration).orThrow()
|
||||
|
||||
assertThat(version).isEqualTo(Configuration.Version.Extractor.DEFAULT_VERSION_VALUE)
|
||||
}
|
||||
@ -56,7 +56,7 @@ class VersionExtractorTest {
|
||||
|
||||
val rawConfiguration = configObject().toConfig()
|
||||
|
||||
val version = extractVersion.invoke(rawConfiguration).valueOrThrow()
|
||||
val version = extractVersion.invoke(rawConfiguration).orThrow()
|
||||
|
||||
assertThat(version).isEqualTo(Configuration.Version.Extractor.DEFAULT_VERSION_VALUE)
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ class VersionedParsingExampleTest {
|
||||
@Test
|
||||
fun correct_parsing_function_is_used_for_present_version() {
|
||||
|
||||
val versionParser = Configuration.Version.Extractor.fromKey("configuration.metadata.version", null)
|
||||
val versionParser = Configuration.Version.Extractor.fromPath("configuration.metadata.version")
|
||||
val extractVersion: (Config) -> Valid<Int> = { config -> versionParser.parseRequired(config) }
|
||||
val parseConfiguration = VersionedSpecificationRegistry.mapping(extractVersion, 1 to RpcSettingsSpec.V1, 2 to RpcSettingsSpec.V2)
|
||||
|
||||
@ -35,7 +35,7 @@ class VersionedParsingExampleTest {
|
||||
fun default_value_is_used_for_absent_version() {
|
||||
|
||||
val defaultVersion = 2
|
||||
val versionParser = Configuration.Version.Extractor.fromKey("configuration.metadata.version", defaultVersion)
|
||||
val versionParser = Configuration.Version.Extractor.fromPath("configuration.metadata.version", defaultVersion)
|
||||
val extractVersion: (Config) -> Valid<Int> = { config -> versionParser.parseRequired(config) }
|
||||
val parseConfiguration = VersionedSpecificationRegistry.mapping(extractVersion, 1 to RpcSettingsSpec.V1, 2 to RpcSettingsSpec.V2)
|
||||
|
||||
@ -52,7 +52,7 @@ class VersionedParsingExampleTest {
|
||||
private fun assertResult(result: Valid<RpcSettings>, principalAddressValue: Address, adminAddressValue: Address) {
|
||||
|
||||
assertThat(result.isValid).isTrue()
|
||||
assertThat(result.valueOrThrow()).satisfies { value ->
|
||||
assertThat(result.orThrow()).satisfies { value ->
|
||||
|
||||
assertThat(value.principal).isEqualTo(principalAddressValue)
|
||||
assertThat(value.admin).isEqualTo(adminAddressValue)
|
||||
|
Reference in New Issue
Block a user