Search code examples
javaspringpropertiesnestedconfigurationproperties

Nested @ConfigurationProperties missing from parent class


I have a somewhat complex application configuration that I'm trying to map to a POJO but it's not working. I've looked at examples and thought this was the correct way to do it.

application.properties:

app.activeEnv=dev
debug=true
logging.level.com.nationwide.ess.contentcollector=DEBUG

app.nas1Root=/Users/userid/devl/ICC_DEV
app.nas2Root=ohlewnas0130.nwie.net

task.triggerCron=* * * * * *

task.job[0].name=CCC
task.job[0].monitor[0]=${app.nas1Root}/Claims/CCC/index
task.job[0].monitor[1]=${app.nas2Root}/Folder/CCC/index
task.job[0].processed=${app.nas2Root}/Processed/CCC_Claims
task.job[0].errors=${app.nas1Root}/Errors/CCC_Claims
task.job[0].triggerTimes[0]=15:55
task.job[0].triggerTimes[1]=16:00

task.job[1].name=CIF
task.job[1].monitor[0]=${app.nas1Root}/Policy/CIF_OV
task.job[1].processed=${app.nas1Root}/Processed/CIF_Dist
task.job[1].errors=${nas1Root}/Errors/CIF_Dist
task.job[1].triggerTimes[0]=12:00

ApplicationProperties.java:

package com.nationwide.ess.contentcollector.config;

import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@ConfigurationProperties(prefix="app")
public class ApplicationProperties {
  private String activeEnv;
  private String nas1Root;
  private String nas2Root;

  @Bean
  @ConfigurationProperties(prefix = "task")
    public static Task task() {
    return new Task();
  }
  
  @Data
  @NoArgsConstructor
  public static class Task {
    private String triggerCron;
    private List<Job> job;

    @Data
    @NoArgsConstructor
    public static class Job {
      private String name;

      private List<String> monitor;

      private String processed;

      private String errors;

      private List<String> triggerTimes;
    }
  }
}

ContentCollectorApplication.java:

package com.nationwide.ess.contentcollector;

import com.nationwide.ess.contentcollector.config.ApplicationProperties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
@EnableConfigurationProperties(ApplicationProperties.class)
public class ContentCollectorApplication {
  static final Logger log = LoggerFactory.getLogger(SpringApplication.class);

  public static void main(String[] args) {
    SpringApplication.run(ContentCollectorApplication.class, args);
  }

}

But when it runs, the ApplicationProperties only has the "app" level values (no task and task.job).


Solution

  • Move the Task class to a file of its own and then whenever you need these properties you just need to declare a dependency to TaskProperties Spring-managed bean so that Spring injects it (assuming it is a dependency on another Spring-managed bean):

    @Data
    @NoArgsConstructor
    @ConfigurationProperties(prefix = "task")
    public class TaskProperties {
      private String triggerCron;
      private List<Job> job;
    
      @Data
      @NoArgsConstructor
      public static class Job {
        private String name;
        private List<String> monitor;
        private String processed;
        private String errors;
        private List<String> triggerTimes;
      }
    }
    

    Since I am not entirely sure about the static nested Job class, if the previous does not work, then try moving Job to a file of its own as well as follows:

    @Data
    @NoArgsConstructor
    @ConfigurationProperties(prefix = "task")
    public class TaskProperties {
      private String triggerCron;
      private List<Job> job;
    }
    
    @Data
    @NoArgsConstructor
    public static class Job {
      private String name;
      private List<String> monitor;
      private String processed;
      private String errors;
      private List<String> triggerTimes;
    }