0

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).

João Dias
  • 16,277
  • 6
  • 33
  • 45
maximum
  • 1,303
  • 1
  • 8
  • 9

1 Answers1

2

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;
}
João Dias
  • 16,277
  • 6
  • 33
  • 45
  • I guess I don't understand how to use multiple prefixes. I added the main class to my description above. It has the annotation `@EnableConfigurationProperties(ApplicationProperties.class)` which configures the ApplicationProperties class so I can access it. I don't think this annotation can accept multiple classes. Thus, I put all properties into the ApplicationProperties class and used a bean to specify Job with a different prefix. – maximum Nov 02 '21 at 16:24
  • As of Spring Boot 2.2, Spring finds and registers all `@ConfigurationProperties` classes via classpath scanning. Therefore, there is no need to annotate such classes with `@Component` (and other meta-annotations like `@Configuration`), or even use the `@EnableConfigurationProperties` as you are doing. Assuming you are using Spring Boot 2.2 or above my suggestion should work. Give it a try ;) – João Dias Nov 02 '21 at 16:31
  • So, if I remove @EnableConfigurationProperties, I get an error saying ApplicationProperties can't be found. – maximum Nov 02 '21 at 16:48
  • Which Spring Boot version are you using? Are `ApplicationProperties` and `TaskProperties` in a sub-package of the main class `ContentCollectorApplication`? If the answer to the first question is 2.2 or above and the answer to the second one is yes, then try adding `@ConfigurationPropertiesScan` to your main class `ContentCollectorApplication`. – João Dias Nov 02 '21 at 16:53
  • I'm using Spring Boot 2.5.4 ApplicationProperties and TaskProperties are both under sub package `com.nationwide.ess.contentcollector.config` Adding @ConfigurationPropertiesScan to the main class fixed the can't be found issue. But now the list of jobs in taskProperties is null. – maximum Nov 02 '21 at 17:02
  • Then, if `ApplicationProperties` and `TaskProperties` are in a sub-package of the main class `ContentCollectorApplication`, try adding `@ConfigurationPropertiesScan` to your main class `ContentCollectorApplication`. – João Dias Nov 02 '21 at 17:05
  • Sorry, hit enter before finishing my last comment. Adding @ConfigurationPropertiesScan to the main class fixed the can't be found issue. But now the list of jobs in taskProperties is null. – maximum Nov 02 '21 at 17:07
  • I've tried it with Job class embedded in TaskProperties and with Job class in it's own file but still getting null. – maximum Nov 02 '21 at 17:17
  • Is `triggerCron` Task property not null? – João Dias Nov 02 '21 at 17:20
  • Yes, triggerCron is not null. – maximum Nov 02 '21 at 17:22
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/238809/discussion-between-maximum-and-joao-dias). – maximum Nov 02 '21 at 17:25