1
votes

My application has nested properties stored in applicaion.yml file.
I want to map those properties to POJO at the application boot-up.

Application.yml:

    demo:
     - A:
       - type: A
         prop1: 1
         prop2: 2
         proop3: 3
       - type: B
         prop1: 1
         prop2: 2
         proop3: 3
     - B:
       - type: A
         prop1: 1
         prop2: 2
         proop3: 3
       - type: B
         prop1: 1
         prop2: 2
         proop3: 3

In order to achieve that, I am using below annotations:

@Configuration
@EnableConfigurationProperties
@ConfigurationProperties("demo")

Class Demo:

@Configuration
@EnableConfigurationProperties
@ConfigurationProperties("demo")
public class Demo {
    @JsonProperty("A")
    private List<A> a = null;
    @JsonProperty("B")
    private List<B> b = null;

    @JsonProperty("A")
    public List<A> getA() {
        return a;
    }

    @JsonProperty("A")
    public void setA(List<A> a) {
        this.a = a;
    }

    @JsonProperty("B")
    public List<B> getB() {
        return b;
    }

    @JsonProperty("B")
    public void setB(List<B> b) {
        this.b = b;
    }

    @Override
    public String toString() {
        return "Demo [a=" + a + ", b=" + b + "]";
    }   
}



Class A:

public class A {

    @JsonProperty("type")
    private String type;
    @JsonProperty("prop1")
    private Integer prop1;
    @JsonProperty("prop2")
    private Integer prop2;
    @JsonProperty("proop3")
    private Integer proop3;

    @JsonProperty("type")
    public String getType() {
        return type;
    }

    @JsonProperty("type")
    public void setType(String type) {
        this.type = type;
    }

    @JsonProperty("prop1")
    public Integer getProp1() {
        return prop1;
    }

    @JsonProperty("prop1")
    public void setProp1(Integer prop1) {
        this.prop1 = prop1;
    }

    @JsonProperty("prop2")
    public Integer getProp2() {
        return prop2;
    }

    @JsonProperty("prop2")
    public void setProp2(Integer prop2) {
        this.prop2 = prop2;
    }

    @JsonProperty("proop3")
    public Integer getProop3() {
        return proop3;
    }

    @JsonProperty("proop3")
    public void setProop3(Integer proop3) {
        this.proop3 = proop3;
    }

    @Override
    public String toString() {
        return "A [type=" + type + ", prop1=" + prop1 + ", prop2=" + prop2 + ", proop3=" + proop3 + "]";
    }
}



Class B

public class B {

    @JsonProperty("type")
    private String type;
    @JsonProperty("prop1")
    private Integer prop1;
    @JsonProperty("prop2")
    private Integer prop2;
    @JsonProperty("proop3")
    private Integer proop3;

    @JsonProperty("type")
    public String getType() {
        return type;
    }

    @JsonProperty("type")
    public void setType(String type) {
        this.type = type;
    }

    @JsonProperty("prop1")
    public Integer getProp1() {
        return prop1;
    }

    @JsonProperty("prop1")
    public void setProp1(Integer prop1) {
        this.prop1 = prop1;
    }

    @JsonProperty("prop2")
    public Integer getProp2() {
        return prop2;
    }

    @JsonProperty("prop2")
    public void setProp2(Integer prop2) {
        this.prop2 = prop2;
    }

    @JsonProperty("proop3")
    public Integer getProop3() {
        return proop3;
    }

    @JsonProperty("proop3")
    public void setProop3(Integer proop3) {
        this.proop3 = proop3;
    }

    @Override
    public String toString() {
        return "B [type=" + type + ", prop1=" + prop1 + ", prop2=" + prop2 + ", proop3=" + proop3 + "]";
    }
}



Main Class

@SpringBootApplication
@ComponentScan(basePackages = {"com.microservice.*"})
@EnableJpaRepositories("com.microservice.*")
@EntityScan("com.microservice.*")
public class MainApplication {  
    public static void main(String[] args) {
         SpringApplication app = new SpringApplication(MainApplication.class);
            app.run();
            System.out.println("step 1");
            Demo config = new Demo();
            System.out.println("name: " + config);
        }

        public void run(String... args) throws Exception {
            System.out.println("step 2");

        }
}

But I am getting below o/p:
step 1
name: Demo [a=null, b=null]

4
what is in the demo class that you are using ?Ramachandran.A.G
Demo class contains List<A> and List<B>. A & B are classes.mayank bisht

4 Answers

3
votes

When you create instanse of your properties POJO manually, Spring doesn't know about it and properties binding doesn't happens.

 SpringApplication app = new SpringApplication(MainApplication.class);
    app.run();
    System.out.println("step 1");
    Demo config = new Demo(); // Not a Spring managed bean!
    System.out.println("name: " + config);
}

Instead of annotating configuration with @EnableConfigurationProperties, you could make Demo a bean, as shown in Type-safe Configuration Properties.

@Component
@ConfigurationProperties("demo")
public class Demo {
    ...
}

And then you could get Demo bean from context:

@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class, args);
        Demo demo = (Demo) context.getBean("demo");
        System.out.println(demo.getName());
    }
}

UPD: there must be no hyphen before 'a' and 'b':

demo:
  a:
    - type: A
      prop1: 1
      prop2: 2
      proop3: 3
    - type: B
      prop1: 1
      prop2: 2
      proop3: 3
  b:
    - type: B
      prop1: 1
      prop2: 2
      proop3: 3

UPD2: Answer to comment. You can build JSON from Demo bean with ObjectMapper:

@SpringBootApplication
public class MainApplication {

    @Bean
    public ObjectMapper objectMapper() {
        return new ObjectMapper();
    }

    public static void main(String[] args) throws JsonProcessingException {
        ...
        ObjectMapper objectMapper = (ObjectMapper) context.getBean("objectMapper");
        System.out.println(objectMapper.writeValueAsString(demo));
    }
}

With spring-boot-starter-web there no need for additional dependencies. Else, you could add jackson:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.0.1</version>
</dependency>
1
votes

It's incorrect in you yml file.You can read the reference onto Merging YAML lists,link here.

I write a demo and it works.

demo:
        a:
            b:
                prop1: prop1
                prop2: prop2
            blist:
                - prop1: prop1
                  prop2: prop2
        alist:
            - b:
                  prop1: prop1
                  prop2: prop2
              blist:
                  - prop1: prop1
                    prop2: prop2
            - b:
                  prop1: prop1
                  prop2: prop2

``

@ConfigurationProperties(prefix = "demo")
public class Demo {
    private A a;
    private List<A> alist;
    // omitted getter/setter
}

``

public class A {
    private B b;
    private List<B> blist;
    // omitted getter/setter
}

``

public class B {
    private String prop1;
    private String prop2;
    // omitted getter/setter
}
0
votes

If you would like to read properties from a .yml or .properties file I propose you to create a class it could be called PropertiesBooter where you would keep all your values retrieved from those files. To retrieve a value from a properties file you can write

@Value("${value}")
private String 
0
votes

From Mikhail answer just write json using Jackson ObjectMapper and you get your json format:

public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(YamlTestApplication.class, args);
        Demo demo = (Demo) context.getBean("demo");
        System.out.println("name: " + demo);

        ObjectMapper mapper = new ObjectMapper();
        try {
            String test = mapper.writeValueAsString(demo);
            System.out.println("json: "+test);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

output:

name: Demo [a=[A [type=A, prop1=1, prop2=2, proop3=3], A [type=B, prop1=1, prop2=2, proop3=3]], b=[B [type=A, prop1=1, prop2=2, proop3=3], B [type=B, prop1=1, prop2=2, proop3=3]]]
json: {"A":[{"type":"A","prop1":1,"prop2":2,"proop3":3},{"type":"B","prop1":1,"prop2":2,"proop3":3}],"B":[{"type":"A","prop1":1,"prop2":2,"proop3":3},{"type":"B","prop1":1,"prop2":2,"proop3":3}]}