mirror of
https://github.com/corda/corda.git
synced 2025-06-16 06:08:13 +00:00
[CORDA-1528]: Node configuration not containing property "rpcSettings.address" fails with error "No configuration setting found for key 'address'" (fix). (#3229)
This commit is contained in:
committed by
GitHub
parent
3136e973a7
commit
61fedb5fd2
@ -2,7 +2,12 @@
|
||||
|
||||
package net.corda.nodeapi.internal.config
|
||||
|
||||
import com.typesafe.config.*
|
||||
import com.typesafe.config.Config
|
||||
import com.typesafe.config.ConfigException
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import com.typesafe.config.ConfigUtil
|
||||
import com.typesafe.config.ConfigValueFactory
|
||||
import com.typesafe.config.ConfigValueType
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.noneOrSingle
|
||||
import net.corda.core.internal.uncheckedCast
|
||||
@ -39,7 +44,7 @@ operator fun <T : Any> Config.getValue(receiver: Any, metadata: KProperty<*>): T
|
||||
return getValueInternal(metadata.name, metadata.returnType, UnknownConfigKeysPolicy.IGNORE::handle)
|
||||
}
|
||||
|
||||
fun <T : Any> Config.parseAs(clazz: KClass<T>, onUnknownKeys: ((Set<String>, logger: Logger) -> Unit) = UnknownConfigKeysPolicy.FAIL::handle): T {
|
||||
fun <T : Any> Config.parseAs(clazz: KClass<T>, onUnknownKeys: ((Set<String>, logger: Logger) -> Unit) = UnknownConfigKeysPolicy.FAIL::handle, nestedPath: String? = null): T {
|
||||
require(clazz.isData) { "Only Kotlin data classes can be parsed. Offending: ${clazz.qualifiedName}" }
|
||||
val constructor = clazz.primaryConstructor!!
|
||||
val parameters = constructor.parameters
|
||||
@ -59,11 +64,11 @@ fun <T : Any> Config.parseAs(clazz: KClass<T>, onUnknownKeys: ((Set<String>, log
|
||||
onUnknownKeys.invoke(unknownConfigurationKeys, logger)
|
||||
|
||||
val args = parameters.filterNot { it.isOptional && !hasPath(it.name!!) }.associateBy({ it }) { param ->
|
||||
// Get the matching property for this parameter
|
||||
val property = clazz.memberProperties.first { it.name == param.name }
|
||||
val path = defaultToOldPath(property)
|
||||
getValueInternal<Any>(path, param.type, onUnknownKeys)
|
||||
}
|
||||
// Get the matching property for this parameter
|
||||
val property = clazz.memberProperties.first { it.name == param.name }
|
||||
val path = defaultToOldPath(property)
|
||||
getValueInternal<Any>(path, param.type, onUnknownKeys, nestedPath)
|
||||
}
|
||||
try {
|
||||
return constructor.callBy(args)
|
||||
} catch (e: InvocationTargetException) {
|
||||
@ -91,68 +96,83 @@ fun Config.toProperties(): Properties {
|
||||
{ it.value.unwrapped().toString() })
|
||||
}
|
||||
|
||||
private fun <T : Any> Config.getValueInternal(path: String, type: KType, onUnknownKeys: ((Set<String>, logger: Logger) -> Unit)): T {
|
||||
return uncheckedCast(if (type.arguments.isEmpty()) getSingleValue(path, type, onUnknownKeys) else getCollectionValue(path, type, onUnknownKeys))
|
||||
private fun <T : Any> Config.getValueInternal(path: String, type: KType, onUnknownKeys: ((Set<String>, logger: Logger) -> Unit), nestedPath: String? = null): T {
|
||||
return uncheckedCast(if (type.arguments.isEmpty()) getSingleValue(path, type, onUnknownKeys, nestedPath) else getCollectionValue(path, type, onUnknownKeys, nestedPath))
|
||||
}
|
||||
|
||||
private fun Config.getSingleValue(path: String, type: KType, onUnknownKeys: (Set<String>, logger: Logger) -> Unit): Any? {
|
||||
private fun Config.getSingleValue(path: String, type: KType, onUnknownKeys: (Set<String>, logger: Logger) -> Unit, nestedPath: String? = null): Any? {
|
||||
if (type.isMarkedNullable && !hasPath(path)) return null
|
||||
val typeClass = type.jvmErasure
|
||||
return when (typeClass) {
|
||||
String::class -> getString(path)
|
||||
Int::class -> getInt(path)
|
||||
Long::class -> getLong(path)
|
||||
Double::class -> getDouble(path)
|
||||
Boolean::class -> getBoolean(path)
|
||||
LocalDate::class -> LocalDate.parse(getString(path))
|
||||
Duration::class -> getDuration(path)
|
||||
Instant::class -> Instant.parse(getString(path))
|
||||
NetworkHostAndPort::class -> NetworkHostAndPort.parse(getString(path))
|
||||
Path::class -> Paths.get(getString(path))
|
||||
URL::class -> URL(getString(path))
|
||||
UUID::class -> UUID.fromString(getString(path))
|
||||
CordaX500Name::class -> {
|
||||
when (getValue(path).valueType()) {
|
||||
ConfigValueType.OBJECT -> getConfig(path).parseAs(onUnknownKeys)
|
||||
else -> CordaX500Name.parse(getString(path))
|
||||
return try {
|
||||
when (typeClass) {
|
||||
String::class -> getString(path)
|
||||
Int::class -> getInt(path)
|
||||
Long::class -> getLong(path)
|
||||
Double::class -> getDouble(path)
|
||||
Boolean::class -> getBoolean(path)
|
||||
LocalDate::class -> LocalDate.parse(getString(path))
|
||||
Duration::class -> getDuration(path)
|
||||
Instant::class -> Instant.parse(getString(path))
|
||||
NetworkHostAndPort::class -> NetworkHostAndPort.parse(getString(path))
|
||||
Path::class -> Paths.get(getString(path))
|
||||
URL::class -> URL(getString(path))
|
||||
UUID::class -> UUID.fromString(getString(path))
|
||||
CordaX500Name::class -> {
|
||||
when (getValue(path).valueType()) {
|
||||
ConfigValueType.OBJECT -> getConfig(path).parseAs(onUnknownKeys)
|
||||
else -> CordaX500Name.parse(getString(path))
|
||||
}
|
||||
}
|
||||
Properties::class -> getConfig(path).toProperties()
|
||||
Config::class -> getConfig(path)
|
||||
else -> if (typeClass.java.isEnum) {
|
||||
parseEnum(typeClass.java, getString(path))
|
||||
} else {
|
||||
getConfig(path).parseAs(typeClass, onUnknownKeys, nestedPath?.let { "$it.$path" } ?: path)
|
||||
}
|
||||
}
|
||||
Properties::class -> getConfig(path).toProperties()
|
||||
Config::class -> getConfig(path)
|
||||
else -> if (typeClass.java.isEnum) {
|
||||
parseEnum(typeClass.java, getString(path))
|
||||
} else {
|
||||
getConfig(path).parseAs(typeClass, onUnknownKeys)
|
||||
}
|
||||
} catch (e: ConfigException.Missing) {
|
||||
throw e.relative(path, nestedPath)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Config.getCollectionValue(path: String, type: KType, onUnknownKeys: (Set<String>, logger: Logger) -> Unit): Collection<Any> {
|
||||
private fun ConfigException.Missing.relative(path: String, nestedPath: String?): ConfigException.Missing {
|
||||
return when {
|
||||
nestedPath != null -> throw ConfigException.Missing("$nestedPath.$path")
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
private fun Config.getCollectionValue(path: String, type: KType, onUnknownKeys: (Set<String>, logger: Logger) -> Unit, nestedPath: String? = null): Collection<Any> {
|
||||
val typeClass = type.jvmErasure
|
||||
require(typeClass == List::class || typeClass == Set::class) { "$typeClass is not supported" }
|
||||
val elementClass = type.arguments[0].type?.jvmErasure ?: throw IllegalArgumentException("Cannot work with star projection: $type")
|
||||
if (!hasPath(path)) {
|
||||
return if (typeClass == List::class) emptyList() else emptySet()
|
||||
}
|
||||
val values: List<Any> = when (elementClass) {
|
||||
String::class -> getStringList(path)
|
||||
Int::class -> getIntList(path)
|
||||
Long::class -> getLongList(path)
|
||||
Double::class -> getDoubleList(path)
|
||||
Boolean::class -> getBooleanList(path)
|
||||
LocalDate::class -> getStringList(path).map(LocalDate::parse)
|
||||
Instant::class -> getStringList(path).map(Instant::parse)
|
||||
NetworkHostAndPort::class -> getStringList(path).map(NetworkHostAndPort.Companion::parse)
|
||||
Path::class -> getStringList(path).map { Paths.get(it) }
|
||||
URL::class -> getStringList(path).map(::URL)
|
||||
UUID::class -> getStringList(path).map { UUID.fromString(it) }
|
||||
CordaX500Name::class -> getStringList(path).map(CordaX500Name.Companion::parse)
|
||||
Properties::class -> getConfigList(path).map(Config::toProperties)
|
||||
else -> if (elementClass.java.isEnum) {
|
||||
getStringList(path).map { parseEnum(elementClass.java, it) }
|
||||
} else {
|
||||
getConfigList(path).map { it.parseAs(elementClass, onUnknownKeys) }
|
||||
val values: List<Any> = try {
|
||||
when (elementClass) {
|
||||
String::class -> getStringList(path)
|
||||
Int::class -> getIntList(path)
|
||||
Long::class -> getLongList(path)
|
||||
Double::class -> getDoubleList(path)
|
||||
Boolean::class -> getBooleanList(path)
|
||||
LocalDate::class -> getStringList(path).map(LocalDate::parse)
|
||||
Instant::class -> getStringList(path).map(Instant::parse)
|
||||
NetworkHostAndPort::class -> getStringList(path).map(NetworkHostAndPort.Companion::parse)
|
||||
Path::class -> getStringList(path).map { Paths.get(it) }
|
||||
URL::class -> getStringList(path).map(::URL)
|
||||
UUID::class -> getStringList(path).map { UUID.fromString(it) }
|
||||
CordaX500Name::class -> getStringList(path).map(CordaX500Name.Companion::parse)
|
||||
Properties::class -> getConfigList(path).map(Config::toProperties)
|
||||
else -> if (elementClass.java.isEnum) {
|
||||
getStringList(path).map { parseEnum(elementClass.java, it) }
|
||||
} else {
|
||||
getConfigList(path).map { it.parseAs(elementClass, onUnknownKeys) }
|
||||
}
|
||||
}
|
||||
} catch (e: ConfigException.Missing) {
|
||||
throw e.relative(path, nestedPath)
|
||||
}
|
||||
return if (typeClass == Set::class) values.toSet() else values
|
||||
}
|
||||
@ -219,7 +239,7 @@ private fun Any.toConfigMap(): Map<String, Any> {
|
||||
private fun Iterable<*>.toConfigIterable(field: Field): Iterable<Any?> {
|
||||
val elementType = (field.genericType as ParameterizedType).actualTypeArguments[0] as Class<*>
|
||||
return when (elementType) {
|
||||
// For the types already supported by Config we can use the Iterable as is
|
||||
// For the types already supported by Config we can use the Iterable as is
|
||||
String::class.java -> this
|
||||
Integer::class.java -> this
|
||||
java.lang.Long::class.java -> this
|
||||
|
Reference in New Issue
Block a user