Home > database >  How do I set and read properties in a SpringBoot application using Kotlin?
How do I set and read properties in a SpringBoot application using Kotlin?

Time:04-01

I'm a Java developer new to Kotlin and I'm trying to access values that I set in an application.yml file.

application.yml

q:
   client:
      apiUrl: https://app.abc.com/api/integr/v1.0
      apiToken: abc
      apiSecret: abc
      authEmail: [email protected]
      sourceName: abc

This is my configuration class, which follows a similar pattern to Java.

@Component
@FeignClient(name = "q", url = "\${q.client.api-url}")
interface QClient {

@PostMapping("/user/get")
fun findUser(@RequestBody request: QRequest?): 
QResponse<List<QUser?>?>

@PostMapping("/user/delete")
fun deleteUser(@RequestBody request: QRequest?): QResponse<DeleteResponse?>?

@Configuration
class QConfig {
    @Value("\${q.client.apiToken}")
    private val apiToken: String? = null

    @Value("\${q.client.apiSecret}")
    private val apiSecret: String? = null

    @Value("\${q.client.authEmail}")
    private val authEmail: String? = null

    @Value("\${q.client.sourceName}")
    private val sourceName: String? = null

    fun createAuthRequest(): QAuth {
        return QAuth(apiToken, apiSecret, authEmail, sourceName)
    }
 }

I don't want to assign null as default values for the instance variables, but Kotlin wants me to declare them like this to avoid null references.

I need to create an auth request and I'm calling the config class from the main class.

private fun generateRequest(email: String): QRequest {
    val config = QClient.QConfig()
    val auth = config.createAuthRequest()
    return QRequest(auth, email)
}

But when debugging it just returns null values.

So after googling, I changed my approach and set all the key values into parameters of QConfig class like this:

 @Configuration
 class QConfig(
  @Value("\${q.client.apiToken}") private val apiToken: String,
  @Value("\${q.client.apiSecret}") private val apiSecret: String,
  @Value("\${q.client.authEmail}") private val authEmail: String,
  @Value("\${q.client.sourceName}") private val sourceName: String
  ) {
      fun createAuthRequest(): QAuth {
        return QAuth(apiToken, apiSecret, authEmail, sourceName)
    }
  }

The problem I faced here was it acts as a constructor and expects me to pass arguments while creating an instance for the QConfig class on the main class, which I wont have in the main class.

How can I get the values from the application.yml and access them as from instance variables?

CodePudding user response:

You can use @ConfigurationProperties (ref)

@ConfigurationProperties("q.client")
@ConstructorBinding
data class ClientConfig(
    val apiUrl: String, // variable name should be same as the one defined in application.yaml
    val apiToken: String,
    ...other properties
)


@SpringBootApplication
@ConfigurationPropertiesScan
class SpringStackoverflowApplication {

    @Autowired
    private lateinit var clientConfig: ClientConfig

    @EventListener(ApplicationReadyEvent::class)
    fun doSomething() {
        println("FOOBAR: $clientConfig")
    }
}

fun main(args: Array<String>) {
    runApplication<SpringStackoverflowApplication>(*args)
}

CodePudding user response:

I solved this with Joffrey's reply, I used this format of config file

@Component
@Configuration
class QConfig {

    @Value("\${q.client.apiToken}")
    private val apiToken: String? = null

    @Value("\${q.client.apiSecret}")
    private val apiSecret: String? = null

    @Value("\${q.client.authEmail}")
    private val authEmail: String? = null

    @Value("\${q.client.sourceName}")
    private val sourceName: String? = null

    fun createAuthRequest(): QAuth {
    return QAuth(apiToken, apiSecret, authEmail, sourceName)
    }
}

Then created the instance of QConfig like this on main class

@Autowired
val config = QConfig()

My bad, tried creating reference of class manually instead of using AutoWire. When ran it pulled all the variables set on yml file into the local variables.

  • Related