0

I've got a library that has a configuration class (no spring configuration class) defined as a data class. I want a Bean of that configuration which can be configured via application.properties. The problem is that I don't know how to tell Spring to create ConfigurationProperties according to that external data class. I am not the author of the configuration class so I can't annotate the class itself. @ConfigurationProperties in conjunction with @Bean does not work as the properties are immutable. Is this even possible?

Ceryni
  • 371
  • 1
  • 5
  • 18

2 Answers2

0

Maybe change scan packages to inlcude the packages that do you want.

 @SpringBootApplication( scanBasePackages = )

take a look this: Configuration using annotation @SpringBootApplication

jonas.lima
  • 116
  • 11
  • Sorry this wasn't very clear in my description but the class is no spring configuration class. – Ceryni Apr 12 '21 at 15:32
  • use @Bean public AppName getAppName(@Value("${app.name}") String appName) { return () -> appName; } – jonas.lima Apr 12 '21 at 15:54
  • yeah but for a lot of options this would be a lot of boilerplate and I thought there might be a convenient way to mark a class of an external dependency to be a ConfigurationPorperties class. – Ceryni Apr 12 '21 at 16:09
  • I understood, but if your external class doesn't have a spring annotation, this is only way to do this. – jonas.lima Apr 12 '21 at 16:54
  • 1
    Seems to be the only possibility – Ceryni Apr 13 '21 at 20:21
0

If I understand correctly, do you need a way to turn a third-party object into a bean with properties from your application.properties file ?

Given an application.properties file:

third-party-config.params.simpleParam=foo
third-party-config.params.nested.nestedOne=bar1
third-party-config.params.nested.nestedTwo=bar2

Create a class to receive your params from properties file

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Configuration

@Configuration
@ConfigurationProperties(prefix = "third-party-config")
data class ThirdPartConfig(val params: Map<String, Any>)

Here is an example of the object that you want to use

class ThirdPartyObject(private val simpleParam: String, private val nested: Map<String, String>) {

fun printParams() =
    "This is the simple param: $simpleParam and the others nested ${nested["nestedOne"]} and ${nested["nestedTwo"]}"

}

Create the configuration class with a method that turns your third-party object into an injectable bean.

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration
class ThirdPartObjectConfig(private val thirdPartConfig: ThirdPartConfig) {

@Bean
fun thirdPartyObject(): ThirdPartyObject {
    return ThirdPartObject(
        simpleParam = thirdPartConfig.params["simpleParam"].toString(),
        nested = getMapFromAny(
            thirdPartConfig.params["nested"]
                ?: throw IllegalStateException("'nested' parameter must be declared in the app propertie file")
            )
        )
    }

    private fun getMapFromAny(unknownType: Any): Map<String, String> {
        val asMap = unknownType as Map<*, *>
        return mapOf(
            "nestedOne" to asMap["nestedOne"].toString(),
            "nestedTwo" to asMap["nestedTwo"].toString()
        )
    }
}

So now you can inject your third-party object as a bean with custom configurated params from your application.properties files

@SpringBootApplication
class StackoverflowAnswerApplication(private val thirdPartObject: ThirdPartObject): CommandLineRunner {
  override fun run(vararg args: String?) {
    println("Running --> ${thirdPartObject.printParams()}")
  }
}