wearebob
wearebob

Reputation: 415

Add list element to Spring properties at runtime

I have an application.yml file with the following:

topics:
  input:
    - name: topic1
      partitions: 3
      replicas: 1
    - name: topic2
      partitions: 6
      replicas: 2

I would like to be able to update or add a new topic object at runtime.

I have tried the following for updating an existing object:

java -jar app.jar --topics.input[0].name="topicX"

and the following for adding another object to the list:

java -jar app.jar --topics.input[2].name="topicX" --topics.input[2].partitions=6 --topics.input[2].replicas=2

I am accessing the properties in the following way:

@Component
@ConfigurationProperties(prefix = "topics")
@Validated
public class TopicsConfiguration {

  @NotEmpty
  @NotNull
  private List<TopicConfiguration> input = new ArrayList<>();

  public List<TopicConfiguration> getInputTopics() {
    return input;
  }

  public void setFacts(List<TopicConfiguration> input) {
    this.input = input;
  }

}

Where TopicConfiguration is just a POJO with the 3 fields listed.

When I don't try and modify any of the property objects at runtime this works exactly as I expect, however I can not update the property list at all. When I try and update an existing object I get an NPE. When I try and add a new object to the list I get:

Property: topics.input[2].name
    Value: lmnop
    Origin: "topics.input[2].name" from property source "commandLineArgs"
    Reason: The elements [topics.input[2].name,topics.input[2].partitions,topics.input[2].replicas] were left unbound.

I would just like to know if there is any way to update or add an element to the list at runtime so that users of my project don't have to modify application.yml if they want to update this configuration.

Upvotes: 0

Views: 1771

Answers (2)

Toerktumlare
Toerktumlare

Reputation: 14820

okey so i did some research and some testing and came up with the following:

you cannot update a defined list in application.yml

if you run:

java -jar myApp.jar -my-list[2].name=foo

it will fail, because as soon as you want to pass the list the list will override the current list in application.yml and you are trying to pass in the 3rd item in the list when there is nothing at index 0 and 1.

it is not a dynamic list, it as an array.

You need to pass the entire list:

java -jar myApp.jar -my-list[0].name=foo -my-list[1].name=bar -my-list[2].name=foobar 

So if you are going to pass a list in from cmd, you must always define the list from scratch.

Upvotes: 2

Killer Beast
Killer Beast

Reputation: 509

So you want to reload your application.properties or application.yml in your Spring Boot application on the fly without having to make another code commit to another deployment? If I understood that right then here is how you can do it.

Read the these links and also google more on Spring Boot Actuator Reload Properties or Spring Scheduling. We can't provide you an out-written code to get this working but there is plenty of examples to examine and try out.

Links:

  1. Actuator Refresh
  2. Spring Scheduling

If I were you, I would prefer Actuator method as it avoids confusion and is cleaner.

Upvotes: 0

Related Questions