Issue
I'm trying to bind a list of objects to my entity class using @ConfigurationProperties annotation. Spring Boot framework seems to ignore that annotation, and it literally does nothing.
Here is my application.yml properties file:
spring:
datasource:
url: jdbc:mysql://localhost:3306/search-engine
username: landsreyk
password: 12345678
jpa:
database-platform: org.hibernate.dialect.MySQLDialect
show-sql: false
hibernate:
ddl-auto: none
sites:
- url: http://someurl1.com
name: somename1
- url: https://someurl2.com
name: somename2
- url: https://someurl3.com
name: somename3
And here is my entity class:
package main.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.sql.Timestamp;
@Getter
@Setter
@ToString
@Entity
@Table(name = "_site")
public class Site {
@Column(nullable = false)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Enumerated(EnumType.STRING)
@Column(name = "status")
private Status status;
@Column(name = "status_time")
private Timestamp statusTime;
@Column(name = "last_error")
private String lastError;
private String url;
private String name;
public enum Status {
INDEXING, INDEXED, FAILED
}
}
Binding is pretty straight forward:
package main.utilities;
import lombok.Getter;
import lombok.Setter;
import main.model.Site;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
@ConfigurationProperties
public class ApplicationProperties {
@Getter
@Setter
private List<Site> sites;
}
Somewhere in application I'm testing that binding, let's say I created end point in my API to test that binding, i.e. my controller calls a method which just prints all objects in a list:
package main.application.indexer;
import main.utilities.ApplicationProperties;
import org.springframework.beans.factory.annotation.Autowired;
public class IndexBuilder {
@Autowired
private ApplicationProperties properties;
public void run() {
System.out.println(properties.getSites());
}
}
Expected:
After launch, ApplicationProperties instance is not null. Calling properties.getSites() returns a list of Site objects. Each Site object has url and name fields initialized from yaml source.
Actual:
After launch ApplicationProperties instance is null.
I was shocked to realize that Spring wasn't able to accomplish such a simple binding. Knowing that just parsing a yaml file is not such a hard task to accomplish, I thought that Spring Framework should have this feature build-in. How do I bind my list?
By the way, here is my project structure.
UPDATE:
I edited IndexBuilder class. Added @Configuration and @Bean annotations. Now it looks like this:
package main.application.indexer;
import main.utilities.ApplicationProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class IndexBuilder {
@Autowired
private ApplicationProperties properties;
@Bean
public void run() {
System.out.println(properties.getSites());
}
}
That fixed the problem with initialization, but Spring Framework just call run() immideately after launch. That isn't an expected behavior.
UPDATE 2:
Answer of this user is completely authentic. He is right.
Solution
Instead of using @Configuration
you should use @Component
on your IndexBuilder
class.
@Configuration
should only be used for configuration classes that define the application‘s beans. Here it is actually expected that the methods annotated with @Bean
are executed immediately on application start. This is the phase where spring creates all needed beans. However I’m wondering spring accepts a void
method with the @Bean
annotation.
What’s your expected time when the run method should be executed? With a normal bean/component/service you could for example use the @PostConstruct
annotation on methods. These will however be executed in the very same phase as the @Bean
methods or at least not much later.
Answered By - dpr
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.