3

I currently have a microservice in Spring Boot, where I have some properties stored in application.properties. Right now, it is configured for one store only. But I want to change the logic so that stores can be added dynamically without needing to change any code.

I have created a model java class for a store, and it looks like this:

public class Store {
    private String username;
    private String password;
    private String hostname;
    private int port;
}

My application.properties looks like this today:

system.connection.username=TestUser
system.connection.password=123456
system.connection.hostname=12.34.56.78
system.connection.port=1234

But I want to be able to specify which store it is, and be able to add more stores by just adding them into the application.properties, like this:

system.connection.Store1.username=TestUser1
system.connection.Store1.password=123456
system.connection.Store1.hostname=12.34.56.78
system.connection.Store1.port=1234

system.connection.Store2.username=TestUser2
system.connection.Store2.password=859382
system.connection.Store2.hostname=34.34.34.34
system.connection.Store2.port=4444

Then add this into some hashmap, and be able to check for and retrieve the variables for a specific store from any of my other classes.

For this, I have tried the following:

@Configuration
@ConfigurationProperties(prefix = "system.connection")
class StoresConfiguration(
    val stores: HashMap<String, Store> = HashMap()
) {

    fun getStore(storeName: String): Store? {
        return stores.get(storeName)
    }


}

But getStore only returns null, and even if I check stores.size it is 0. So where am I doing wrong, and how can I do this effectively? I have thought about just skipping the crap and just making a folder called "stores" and put json files in it, and read from there. So that each Store is just a json file, so at startup the app scans the folder and for every json file makes a Store object. But I don't know if that is a good solution. This is my first time working with Spring Boot. Thanks for any help!

1
  • I've never tried a map with ConfigurationProperties, but I think you could get a list of objects (store name, username, password, host, etc) and then turn that into a map. Check this post out - stackoverflow.com/questions/51378768/…. Commented Jan 3, 2022 at 22:02

2 Answers 2

0

By playing around a little bit, I managed to solve the issue. I reverted my class back to Kotlin, and made some adjustments on how I retrieve the values. This is how you can load dynamic objects from application.properties in Spring Boot with Kotlin:

Suppose you have an object class called Store.kt

data class Store(
    var name: String ?= null,
    var username: String ?= null,
    var password: String ?= null,
    var hostname: String ?= null,
    var port: Int ?= null,
)

In your application.properties

system.stores.Store1.name=Test1
system.stores.Store1.username=test1
system.stores.Store1.password=123456
system.stores.Store1.hostname=12.34.56.78
system.stores.Store1.port=1234

system.stores.Store2.name=Test2
system.stores.Store2.username=test2
system.stores.Store2.password=123456
system.stores.Store2.hostname=12.34.56.78
system.stores.Store2.port=1234

This is in your StoresConfiguration.kt

@Configuration
@ConfigurationProperties(prefix = "system")
class StoreConfiguration(
    var stores: HashMap<String, Store> = HashMap()
) {

    fun getStore(storeName: String) : Store? {
        return stores.get(storeName)
    }


}

Then suppose you want to get the objects and use them in one of your service classes:

@Service
class StoreService(

    private val storeConfiguration: StoreConfiguration,

) { 

fun test() {

val MyStore = storeConfiguration.getStore("Store1")

if (MyStore != null) {

// Do whatever you want to do with your object

} else {

// If your object does not exist

}

}

}
Sign up to request clarification or add additional context in comments.

Comments

-1

Would this be helpful? This is using an indexed list in a ConfigurationProperties class.

@ConfigurationProperties("system.connection")
// use a fitting name here
public class Stores {

    // reference your Store type
    private final List<Store> store = new ArrayList<>();

    public List<Store> getStore() {
        return this.store;
    }

}
system.connection.store[0].username=foo
system.connection.store[0].password=pass1
...
system.connection.store[1].username=bar
system.connection.store[1].password=pass2

Later an example with a map is also given in the above link, but the list approach with the indices might better fit your needs.

6 Comments

I have tried the list approach, but I receive Binding to target [Bindable@210308d5 type = java.util.List<io.teyyihan.service.domain.model.Store>, value = 'provided', annotations = array<Annotation>[[empty]]] failed:
Reason: The elements [system.stores[0].hostname, system.stores[0].name,system.stores[0].password,system.stores[0].port,system.stores[0].username] were left unbound.
Okay it built when I removed @Configuration and only kept @ConfigurationProperties("system")
But it is still 0 in size....
Is your application.properties file correctly loaded? Can you check if other properties from the application.properties are there? E.g. add a simple String field to the above Store class and check if at least this is assigned, if not the problem begins before.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.