Skip to content

Commit

Permalink
Do not call hash code on generated values (#392)
Browse files Browse the repository at this point in the history
  • Loading branch information
sksamuel committed Sep 18, 2023
1 parent 30550dc commit ccea565
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ data class DecoderContext(
// these are the dot paths for every config value - overrided or not, that was used
val usedPaths: MutableSet<DotPath> = mutableSetOf(),
// this tracks the types that a node was marshalled into
val used: MutableSet<NodeState> = mutableSetOf(),
val used: MutableMap<DotPath, NodeState> = mutableMapOf(),
val metadata: MutableMap<String, Any?> = mutableMapOf(),
val config: DecoderConfig = DecoderConfig(false),
val environment: Environment? = null,
Expand All @@ -49,7 +49,7 @@ data class DecoderContext(
* Makes a node as marshalled into the given [type] with the resolved value [value].
*/
fun used(node: Node, type: KType, value: Any?) {
this.used.add(NodeState(node, true, value, type))
this.used[node.path] = NodeState(node, true, value, type)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class Decoding(
}
}

fun createDecodingState(
internal fun createDecodingState(
root: Node,
context: DecoderContext,
secretsPolicy: SecretsPolicy?
Expand All @@ -48,7 +48,7 @@ private fun createNodeStates(
): List<NodeState> {
return root.traverse().map { node ->

val state = context.used.find { it.node.path == node.path }
val state = context.used.entries.find { it.key == node.path }?.value

val secret = secretsPolicy?.isSecret(node, state?.type) ?: false

Expand Down
47 changes: 47 additions & 0 deletions hoplite-core/src/test/kotlin/com/sksamuel/hoplite/Github389.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.sksamuel.hoplite

import com.sksamuel.hoplite.decoder.Decoder
import com.sksamuel.hoplite.fp.invalid
import com.sksamuel.hoplite.fp.valid
import com.sksamuel.hoplite.parsers.PropsPropertySource
import io.kotest.core.spec.style.FunSpec
import java.util.Properties
import kotlin.reflect.KType
import kotlin.reflect.full.isSubtypeOf
import kotlin.reflect.full.starProjectedType

// https://github.com/sksamuel/hoplite/issues/389
class Github389 : FunSpec() {
init {
test("NullPointerException on Config load #389") {
val props = Properties()
props["someInt"] = 1
props["test"] = "a"
ConfigLoaderBuilder.default()
.addPropertySource(PropsPropertySource(props))
.addDecoder(MyDecoder)
.build()
.loadConfigOrThrow<MyConfig>()
}
}

}

object MyDecoder : Decoder<MyClass> {
override fun decode(node: Node, type: KType, context: DecoderContext): ConfigResult<MyClass> =
when (node) {
is StringNode -> MyClass(node.value).valid()
else -> ConfigFailure.DecodeError(node, type).invalid()
}

override fun supports(type: KType): Boolean = type.isSubtypeOf(MyClass::class.starProjectedType)
}

class MyClass(val value: String) {
override fun hashCode(): Int = error("do not run at config loadtime")
}

data class MyConfig(
val someInt: Int,
val test: MyClass,
)

0 comments on commit ccea565

Please sign in to comment.