Spring Boot ConfigurationProperties issues - spring-boot

I have been having issues getting my properties to load in a spring boot app. I made a very simple version and it still fails. I have been going over other questions from the site and just have not been able to figure it out.
application.properties is in main/java/resources
rim.dbuser=RIM_API_USER
rim.dbpassword=rimpassword
rim.dbconnection=jdbc:oracle:thin:#kuga.myrim.com:1515:dev179
rim.dbdriver=oracle.jdbc.driver.OracleDriver
A simple class for the properties
#ConfigurationProperties(prefix = "rim")
public class RIMProperties {
private String driver;
private String dbURL;
private String user;
private String password;
<getters and setters>
My object using the RIMproperties
#Component
public class RIMObject {
#Autowired
private RIMProperties rimProperties;
public void print(){
System.out.println("dbuser = "+rimProperties.getUser());
System.out.println("password = "+rimProperties.getPassword());
System.out.println("driver = "+ rimProperties.getDriver());
System.out.println("DBURL = "+rimProperties.getDbURL());
}
}
and my app class
#SpringBootApplication
#EnableConfigurationProperties(RIMProperties.class)
public class App {
public static void main(String[] args)
{
ApplicationContext context = SpringApplication.run(App.class, args);
RIMObject rimObject = context.getBean(RIMObject.class);
rimObject.print();
RIMProperties prop = context.getBean(RIMProperties.class);
System.out.println(prop.getDriver());
System.out.println(prop.getDbURL());
}
}
I get nulls on everything. Not sure why it is not picking up the properties.

I think the problem is with your variable names, change them to match your props file.
private String driver; to private String dbdriver;
you get the idea...

I assume, you have posted correct code.
As mentioned in some other answer looks like your java field names differ to the properties fields.
For more info take a look at https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties
Spring Boot Autoconfiguration
Moreover, as you are using spring-boot, is there a reason you are not using spring-boot's out of the box auto configuration feature?
In you example you are mapping datasource properties in your java class.
You just need to use spring-boot's standard datasource fields in properties and it will automatically create a DataSource and even JdbcTemplate instance which you can simply autowire anywhere in your app.
Please have a look for more https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-connect-to-production-database

Related

SpringBoot Failed to bind properties under app

I have a SpringBoot 2.1.7.RELEASE project with gradle. I'm getting an error when I try to use #ConfigurationProperties
The property that I'm trying to bind is existing in my application-default.properties and if I run the project using Itellij I can see that the property is ingested in my component.
If I enable #EnableConfigurationProperties I got an error.
My application-default.properties
app.forwarding-endpoint=localhost:8080
My AppProperties.java
#ConfigurationProperties(prefix = "app", ignoreUnknownFields = false)
#Validated
#Data
public class AppProperties {
#NotBlank
#Pattern(regexp = "^(.+):\\d+$")
private String forwardingEndpoint;
}
My Application.java
#SpringBootApplication
#EnableConfigurationProperties(AppProperties.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application .class, args);
}
}
My component that is using the property:
public MyComponent(#Value("${app.forwarding-endpoint}") String forwardingEndpoint) {
log.info("Forwarding endpoint {}", forwardingEndpoint);
}
The error that I get is:
Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'app' to com.config.AppProperties failed:
Property: app.forwardingEndpoint
Value: null
Reason: must not be blank
What am I missing?
The cause is in the order of initialization.
You did not fill AppProperties but start to use it in components. You need to annotate this class also as a component but it's not a good approach from point of view of an architecture.
The concept of #ConfigurationProperties is quite raw for Spring and without some manipulations, you will quite difficult to force it to work correctly. I propose a simple 'trick' (or 'another approach'):
#Data
public class AppProperties {
#NotBlank
#Pattern(regexp = "^(.+):\\d+$")
private String forwardingEndpoint;
}
(I think the place of #validated is not in the entitity/DO).
And place in your #Configuration next code:
#Bean
#ConfigurationProperties(prefix = "app", ignoreUnknownFields = false)
public AppProperties setAppProperties() {
return new AppProperties();
}
And next, you can inject AppProperties bean in any component.

How to read a property on a static field in a spring-boot application?

I want to convert the following code snippet using spring boot.
String message = propertiesService.getProperty("app.directory.errorcode." + errorNumber);
where propertiesService is used to read the application.properties.
How do I read this in Spring boot as I have previously declared the properties
using static keyword where class variables are declared ?
#Value("${app.directory.errorcode.fatal}")
private static String fatalCode;
I need to generate the property name and read it dynamically.
You can achieve this using the class Environment from the package org.springframework.core.env.
Example :
#SpringBootApplication
public class Example {
// autowire the Environment
#Autowired
private Environment environment;
private static String fatalCode;
public void someMethod(String errorNumber) {
fatalCode = environment.getProperty("app.directory.errorcode." + errorNumber);
}
public static void main(String[] args) {
SpringApplication.run(Example.class, args);
}
}
I hope this may help you.
Thanks :)

Spring boot junit test #JpaDataTest not working due to missing dependency

I'm trying to write a test using my actual configuration.
In the normal spring context, I'm loading the dataSource using a #Autowired service that decrypts the database password from the properties.
It looks like this
#Configuration
public class DataBaseConfig {
#Value("${swat.datasource.url}")
private String dbURL;
#Value("${swat.datasource.driver-class-name}")
private String driverName;
#Value("${swat.datasource.username}")
private String userName;
#Value("${swat.datasource.password}")
private String hashedPassword;
#Autowired
EncryptionService encryptionService;
#Bean
public DataSource primaryDataSource() {
String password = encryptionService.decriptPassword(hashedPassword);
return DataSourceBuilder.create().url(dbURL).driverClassName(driverName).username(userName).password(password).build();
}
im now trying to run a test using #JpaDataTest (not the #SpringBootTest)
doing the following
#RunWith(SpringRunner.class)
#DataJpaTest
#AutoConfigureTestDatabase(replace=Replace.NONE)
#Import(DataBaseConfig.class)
#TestPropertySource(value = "file:./executor.properties")
public class NewDeviceTest {
#Autowired
NewDeviceService newDeviceService;
#Test
public void loadNewDevices() {
List<NewDevice> devices = newDeviceService.findAll();
assertEquals(1, devices.size());
assertTrue(devices.get(0).isNew());
}
}
im getting a problem since the EncryptionService in the DataBaseConfig cannot be resolved
how do i tell the Test to first load this
i tried
#ComponentScan("com.wisemon.compliance.executor.service")
but it loads all the components and some of them have a behaviour that i dont want in my test (load initial db data... scheduling etc)

Elegant way to init or inject string into a static field beforeClass (JUNIT) from spring configuration?

The annotation #Value("${my.field}") work well if you want to inject data into a non static field. In my case, I'm building test for my spring boot application. I'm using Junit. I have some task to do #BeforeClass and I need some properties from spring application configuration. I'm looking for a elegant way to get my properties.
You can load the properties file in the static setup method on your own and select the values needed in your tests. For some, it might be less convenient than injection with #Value, but it will do the trick.
public class SomeTestClass {
private static String myProperty;
#BeforeClass
public static void setUpClass() throws Exception {
Properties prop = new Properties();
prop.load(new FileInputStream("src/main/resources/application.properties"));
myProperty = prop.getProperty("your.property.key");
}
#Test
public void shouldLoadProperty() throws Exception {
assertEquals("expectedValue", myProperty);
}
}

Spring #ConfigurationProperties not populated

I am experiencing problems using the #ConfigurationProperties feature.
Probably, I am missing something, since the mechanism seems very simple, but for me, it does not work.
I am using Spring Boot with the following main Application class
#SpringBootApplication
#EnableAspectJAutoProxy
#EnableConfigurationProperties(QueuesProperties.class)
#PropertySource("file:config/queues.properties")
#ImportResource("classpath:/spring-config.xml")
public class Application {
public static void main(String... args) {
ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
with QueuesProperties
#ConfigurationProperties(prefix = "wmq.in.queue")
public class QueuesProperties {
private static final Logger LOGGER = LoggerFactory.getLogger(QueuesProperties.class);
private String descr;
public String getDescr() {
return descr;
}
public void setDescr(String descr) {
this.descr = descr;
}
}
The properties file is very simple (I am trying to isolate the problem)
wmq.in.queue.descr = description
Then, I am trying to #Autowired the QueuesProperties in a #Component that I use in a spring-integration flow with a .
The QueuesProperties is correctly injected but the descr attribute is null.
#Autowired
private QueuesProperties queuesConfiguration;
while this
#Value("${wmq.in.queue.descr}")
private String descr;
is correctly evaluated.
I have made a lot of attempt with different configurations or code, but the result is the same. I get the QueuesProperties bean but it is not populated.
What am I missing?
Reading the question isn't very clear if the wmq.in.queue.descr = description properties is written in applciation.properties file. I said it because you say that the properties is correctly evaluated with #Value and not with
#Autowired
private QueuesProperties queuesConfiguration;
Even the #PropertySource("file:config/queues.properties") let me to think that probably the your wmq.in.queue.descr = description properties isn't written in applciation.properties but in file:config/queues.properties.
Summing
For use #ConfigurationProperties feature you have write the properties in application.properties and use #EnableConfigurationProperties(QueuesProperties.class) on #Component, #Configuration and so on annotated classes like below.
#Component
#EnableConfigurationProperties(QueuesProperties.class)
public class YourBean {
....
private final QueuesProperties queuesProperties;
public YourBean(QueuesProperties queuesProperties){
this.queuesProperties = queuesProperties;
}
.....
}
actually you can change the application.properties file name customizing spring boot properties evaluation but for your local app I discourage. I consider application.properties a good name for naming a place in which you put the configuration properties of your application
I hope that it can help you

Resources