I am working on a Spring Boot project in Kotlin. I would like to read a list of <String,Int>
pairs from application.yml file to a mutablelist. The type of the list is as follows.
@Configuration
@EnableAutoConfiguration
@ConfigurationProperties(prefix = "user-parameters")
class UserParameters {
/**
* Owners of the knapsacks and their capacity.
*/
var knapsacks = mutableListOf<Pair<String, Int>>()
init {
...
}
}
In the application.yml file, I tried to use the following configuration.
...
user-parameters:
knapsacks:
- "[James]": 102
- "[Mary]": 185
However, this fails with the following error.
***************************
APPLICATION FAILED TO START
***************************
Description:
Binding to target [Bindable@3a7b2e2 type = java.util.List<kotlin.Pair<java.lang.String, java.lang.Integer>>, value = 'provided', annotations = array<Annotation>[[empty]]] failed:
Property: user-parameters.knapsacks[0][James]
Value: 102
Origin: class path resource [application.yml] - 28:17
Reason: The elements [user-parameters.knapsacks[0][James],user-parameters.knapsacks[1][Mary]] were left unbound.
Property: user-parameters.knapsacks[1][Mary]
Value: 185
Origin: class path resource [application.yml] - 29:16
Reason: The elements [user-parameters.knapsacks[0][James],user-parameters.knapsacks[1][Mary]] were left unbound.
Action:
Update your application's configuration
The code works if I change the type to Map<String, Int>
but I need Pair<String, Int>
due to implementation details.
I have also tried the following annotations but to no avail.
...
user-parameters:
knapsacks:
- "[James]": 102
"[Mary]": 185
...
user-parameters:
knapsacks:
"[James]": 102
"[Mary]": 185
...
user-parameters:
knapsacks:
- { "[James]": 102 }
- { "[Mary]": 185 }
How can I achieve reading pairs of String,Int
to a mutable list from application.yml?
CodePudding user response:
As far as I know Spring Boot does not support Pair
of the kotlin-stdlib
out-of-the-box.
Spring cannot know how to parse arbitrary classes in arbitrary ways. Spring does support classes following Bean conventions however.
Thus, there are at least three solutions to your problem:
- Simply parse as
Map
as outlined in the question and convert yourMap<String, Int>
to aList<Pair<String, Int>>
, e.g. by callingmap.toList()
, see the official documentation.
You may provide a custom getter for the list.
val knapsacksList: List<Pair<String, Int>>
get() { knapsacks.toList() }
- Adjust your
application.yml
to conform to the form ofPair
. APair
is a simple data class having two values beingfirst
andsecond
. If you provide these in the .yml-file, Spring can parse them accordingly.
Something along the lines of the following may work.
...
user-parameters:
knapsacks:
- first: "James"
second: 102"
- first: "Mary"
second: 185
- Provide a custom
Converter
for your use case. There are resources online on how to achieve this, for example from baeldung.com.
Note that I've written this answer on my phone, thus I couldn't test any of this and there might be minor typos.