Skip to content

Instantly share code, notes, and snippets.

@toefel18
Created August 2, 2022 15:18
Show Gist options
  • Save toefel18/caf5f219f5850117a975b3e43eb4c7e1 to your computer and use it in GitHub Desktop.
Save toefel18/caf5f219f5850117a975b3e43eb4c7e1 to your computer and use it in GitHub Desktop.
Hoplite configuration
// configuration properties
implementation("com.sksamuel.hoplite:hoplite-core:2.4.0")
implementation("com.sksamuel.hoplite:hoplite-yaml:2.4.0")
implementation("com.sksamuel.hoplite:hoplite-datetime:2.4.0")
object ConfigurationLoader {
val log: Logger = LoggerFactory.getLogger(ConfigurationLoader::class.java)
/** Applications should rely on overriding env vars in the default profiles. This mechanism can be simplified */
private val profileKeys = listOf("profileOverride") // used to be "profile", "profiles", "spring.profiles.active"
private fun lazyCheckSystemProperty(name: String): Lazy<String?> = checkProfileVia("system property", name) { System.getProperty(name) }
private fun lazyCheckEnvVar(name: String): Lazy<String?> = checkProfileVia("environment var", name) { System.getenv(name) }
private fun checkProfileVia(source: String, name: String, supplier: () -> String?) = lazy {
val profile = supplier()
if (profile == null) {
log.info("did not find application config profile via $source '$name'")
} else {
log.info("found application config profile '$profile' via $source '$name'")
}
profile
}
/**
* Contains the configured profile from the environment.
* The following locations will be checked in order:
* ```
* jvm arg: -DprofileOverride=acc,local
* env var: PROFILEOVERRIDE=acc,local
* ```
* First config location wins.
* - If no profileOverride is found, only the default 'application.yaml' will be loaded
* - If there are multiple values present, such as 'acc,local' then both are loaded but local will overwrite the values form acc.
*/
val configuredProfiles: List<String> = profileKeys
.asSequence()
.flatMap { name ->
listOf(
lazyCheckSystemProperty(name),
lazyCheckEnvVar(name.uppercase().replace('.', '_'))
)
}
.firstOrNull { it.value != null }
?.value?.split(",") ?: listOf()
fun load(): ApplicationConfig = readConfigFilesWithConfiguredProfiles()
/**
* Reads the config files using the configured profiles via system properties or environment variables
*/
inline fun <reified T> readConfigFilesWithConfiguredProfiles(): T = readConfigWithProfiles(*configuredProfiles.toTypedArray())
/**
* Reads application.yaml + the other given profiles and maps the configuration to the object it is assigned to.
* The last profile has highest priority and overwrites values in earlier profiles.
*
* `val obj : MyConfigType = readConfigWithProfiles("acc")`
*
*/
inline fun <reified T> readConfigWithProfiles(vararg profiles: String): T {
// highest prio config files need to be fed first to the config loader
val resourceFiles = profiles.reversed().map { "/application-$it.yaml" } + "/application.yaml"
log.info("reading config files $resourceFiles")
return ConfigLoader.builder()
.addDefaults()
.build()
.loadConfigOrThrow(resourceFiles)
}
}
// dto's read from yaml
data class ApplicationConfig(
val server: ServerConfig,
val profile: String,
val applicationName: String
)
// dto's read from yaml.
data class ServerConfig(val port: Int)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment