Can not read properties file value in Spring Configuration class - java

I am trying to simple spring program that has a class named PersistenceConfig annotated with #Configuration
#Configuration
#PropertySource("classpath:application.properties")
public class PersistanceConfig {
#Value("${dbPassword}")
private String dbPassword;
// Set of Beans and Code
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
dataSource.setUrl("jdbc:sqlserver://localhost;databaseName=GovernmentPayment;integratedSecurity=false;");
dataSource.setUsername("sa");
dataSource.setPassword(dbPassword);
return dataSource;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
When i run my program, the value dbPassword is always null but if i try to read the same value inside one my Controllers it reads the value without any issues.
I have tried autowiring Environment variable and using it instead of #Value but it didn't work either. (Spring didn't inject value to the Environment Variable)
I am using Spring 4
What is basically want is to externalize the database username and password in a separate property file.

i don't see any problem with given code.i wrote a simple unit test to your class to prove it works.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=PersistanceConfig.class)
public class PersistanceConfigTest {
#Autowired
private DriverManagerDataSource dataSource;
private final String password = "mydbPassword";
#Test
public void testDriverManagerDataSourcePassword() {
System.out.println("dataSource Password :: " + dataSource.getPassword());
assertNotNull(dataSource);
assertTrue(password.equals(dataSource.getPassword()));
}
}
assuming you have application.properties in src/main/resources and dbPassword=mydbPassword is presented in that file.

Credit goes to Chad Darby
This is an issue with Spring versions.
If you are using Spring 4.2 and lower, you will need to add the code in marked with(**).
package com.luv2code.springdemo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
#Configuration
// #ComponentScan("com.luv2code.springdemo")
#PropertySource("classpath:sport.properties")
public class SportConfig {
// add support to resolve ${...} properties
**#Bean
public static PropertySourcesPlaceholderConfigurer
propertySourcesPlaceHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}**
// define bean for our sad fortune service
#Bean
public FortuneService sadFortuneService() {
return new SadFortuneService();
}
// define bean for our swim coach AND inject dependency
#Bean
public Coach swimCoach() {
SwimCoach mySwimCoach = new SwimCoach(sadFortuneService());
return mySwimCoach;
}
}
````
In Spring 4.3 and higher, they removed this requirement. As a result, you don't need this code.

I have solved this by moving that two annotations to the main file.
package com.luv2code.springdemo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan(basePackages = "com.luv2code.springdemo.SportConfig")
public class SwimJavaConfigDemoApp {
public static void main(String[] args) {
// read spring config java class
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(SportConfig.class);
// get the bean from spring container
Coach theCoach = context.getBean("swimCoach", Coach.class);
// call a method on the bean
System.out.println(theCoach.getDailyWorkout());
// call method to get the daily fortune
System.out.println(theCoach.getDailyFortune());
// close the context
context.close();
}
}
Configure the main file.
Use component scan and specified the path to the cofig class.
Next, write some Bean's to the config file.
package com.luv2code.springdemo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
public class SportConfig {
// define a bean for sad fortune service
#Bean
public FortuneService sadFortuneService() {
return new SadFortuneService();
}
// define bean for our swim coach and inject dependency
#Bean
public Coach swimCoach() {
return new SwimCoach(sadFortuneService());
}
}
For futher learning : Component Scan.

Related

Consider defining a bean of type 'Dao interface' in your configuration

I am planning to break all the DAO layer code into a separate Spring boot data project.
So I created two projects one of which will have all the database related code and the other will have service code which will then use the first project as a dependency to interact for any database-related actions.
Project1: DatabaseInteractionService
Project2: InsuranceCleanupService
InsuranceCleanupService startup class
package com.ics;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.scheduling.annotation.EnableScheduling;
#SpringBootApplication
#EnableScheduling
#EntityScan(basePackages = {"com.ms.base.entity", "com.dis", "com.dis.config", "com.dis.dao", "com.dis.dao.Impl" })
public class InsuranceCleanupServiceApplication {
public static void main(String[] args) {
SpringApplication.run(InsuranceCleanupServiceApplication.class, args);
}
}
DatabaseInteractionService startup class
package com.dis;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
#SpringBootApplication
#EntityScan("com.ms.base.entity")
public class DatabaseInteractionServiceApplication {
public static void main(String[] args) {
SpringApplication.run(DatabaseInteractionServiceApplication.class, args);
}
#Value("spring.datasource.driverClassName")
String driverClassName;
#Value("spring.datasource.url")
String url;
#Value("spring.datasource.username")
String username;
#Value("spring.datasource.password")
String password;
#Bean
public DataSource dataSource()
{
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
#Bean
public JdbcTemplate jdbcTemplate()
{
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource());
return jdbcTemplate;
}
}
I am using the Mysql database and Spring-data. When worked independently there seems no issue.
After separation, I am facing the below issue.
Consider defining a bean of type 'com.dis.dao.EmployeeDao' in your configuration.
Why you have 2 #SpringBootApplication classes since one project will be used as dependency? It seems to me that DatabaseInteractionServiceApplication is more a #Configuration class rather than a #SpringBootApplication.
Apart from this the error
Consider defining a bean of type 'com.dis.dao.EmployeeDao' in your configuration
means that somewhere you inject (#Autowire) a EmployeeDao bean but it doesn't exist in your Spring context. I suppose it exists in InsuranceCleanupServiceApplication project since there you have annotated:
#EntityScan(basePackages = {"com.ms.base.entity", "com.dis", "com.dis.config", "com.dis.dao", "com.dis.dao.Impl" })
#EntityScan annotation works only for #Entity annotated classes. If you want to scan for services/repositories/components you should change it to #ComponentScan. You need to add #ComponentScan since your #SpringBootApplication class belongs to a different package, com.ics than com.dis and as such it won't automatically pick up classes that are annotated with #Service, #Component or #Repository belonging to com.dis package. So I suppose just
#ComponentScan(basePackages = {"com.dis"})
will suffice since it will also scan subpackages e.g. "com.dis.config", "com.dis.dao", "com.dis.dao.Impl"
Leave #EntityScan only for your entity package (it already exists in DatabaseInteractionServiceApplication):
#EntityScan("com.ms.base.entity")

No bean named '' is defined [duplicate]

This question already has an answer here:
Is it possible to set a bean name using annotations in Spring Framework?
(1 answer)
Closed 4 years ago.
I am testing out simple AOP use case in Spring but am getting the below error,
Exception in thread "main"
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean named 'bean1' is defined
Below are my source files,
DemoConfig.java
package com.luv2code.aopdemo;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import com.luv2code.aopdemo.aspect.MyDemoLoggingAspect;
import com.luv2code.aopdemo.dao.AccountDAO;
#Configuration
#EnableAspectJAutoProxy
#ComponentScan("com.luv2code.aopdemo")
public class DemoConfig {
#Bean
#Qualifier("bean1")
public AccountDAO accDao() {
return new AccountDAO();
}
#Bean
#Qualifier("bean2")
public MyDemoLoggingAspect myAscpect() {
return new MyDemoLoggingAspect();
}
}
MyDemoLoggingAspect.java
package com.luv2code.aopdemo.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class MyDemoLoggingAspect {
// this is where we add all of our related advices for logging
// let's start with an #Before advice
#Before("execution(** com.luv2code.aopdemo.dao.AccountDAO.addAccount(..))")
public void beforeAddAccountAdvice() {
System.out.println("\n=====>>> Executing #Before advice on addAccount()");
}
}
MainDemoApp.java
package com.luv2code.aopdemo;
import com.luv2code.aopdemo.dao.AccountDAO;
public class MainDemoApp {
public static void main(String[] args) {
// read spring config java class
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoConfig.class);
// get the bean from spring container
AccountDAO theAccountDAO = context.getBean("bean1", AccountDAO.class);
// call the business method
theAccountDAO.addAccount();
// do it again!
System.out.println("\nlet's call it again!\n");
// call the business method again
theAccountDAO.addAccount();
// close the context
context.close();
}
}
I have given my bean ID "bean1", even after that Spring is not able to find my bean in the context. Why am I getting this error and how to resolve this?
The #Qualifier tag is used with the #Autowired annotation.
What you need is
#Bean(name="bean1")
public AccountDAO accDao() {
return new AccountDAO();
}

How to use #PropertySource with Java Spring 4.0.4?

I would like to add the source of database.properties which is in ProjectName/src/database.properties to AppConfig.class which is in ProjectName/src/device/spring/configaccording to https://www.journaldev.com/17053/spring-jdbctemplate-example
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import tekranchecklist.model.*;
#Configuration
#ComponentScan("device.spring.dao","device.model","device.spring.config","device.Main")
public class AppConfig {
#Autowired
Environment environment;
private final String URL = "URL";
private final String USER = "root";
private final String DRIVER = "DRIVER";
private final String PASSWORD = "PASSWORD";
#Bean
DataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUrl(environment.getProperty(URL));
driverManagerDataSource.setUsername(environment.getProperty(USER));
driverManagerDataSource.setPassword(environment.getProperty(PASSWORD));
driverManagerDataSource.setDriverClassName(environment.getProperty(DRIVER));
return driverManagerDataSource;
}
}
I tried to use #PropertySource("classpath:database.properties") but it is syntax error that: class, interface or enum expected. Can someone help me how I should add my .properties file path with #PropertySource?
#PropertySource is an annotation that can be used only on types, that is interface, class, enum :
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Repeatable(PropertySources.class)
public #interface PropertySource {...}
This class, interface or enum expected message is a compilation error that means that you specified the annotation on a target that doesn't match to a type.
So move it at the correct place :
#PropertySource("classpath:database.properties")
public class AppConfig {
....
}
You can use #PropertySource with either #Value or Environment as shown below.
Assuming this is your application property file.
app.value.example=v1
app.environment.example=e1
Using #PropertySource with #Value
#Configuration
#PropertySource("classpath:application.properties")
public class ApplicationContig {
#Value("${app.value.example:defaultValueCanBeHere}")
private String propertyValue;
public void usePropertyValue() {
// You can use it here
}
}
Using #PropertySource with Environment
#Configuration
#PropertySource("classpath:application.properties")
public class ApplicationContig {
#Autowired
private Environment environmentValue;
private void useEnvironmentValue() {
String value = environmentValue.getProperty("app.environment.example");
// You can then use it here.
}
}
With Spring >= 4
#Configuration
#PropertySources({
#PropertySource(value = "classpath:application.properties"),
#PropertySource(value = "classpath:another.properties"),
#PropertySource(value = "classpath:missing-file.properties",
ignoreResourceNotFound = true)})
public class ApplicationContig {
// You can either use #Value or Environment as demonstrated above
}
I hope this will help.

Spring Read value from properties file into #SpringBootApplication class

I've a SpringBootApplication and I want read a value from my property file.
My #SpringBootApplication class is this:
#SpringBootApplication
#ComponentScan(basePackages = "it.test")
#PropertySource("classpath:application.properties")
public class Application {
private static Logger log = LogManager.getLogger();
#Value("${server.modem.delay}")
private int modemSmsDelay;
#Order(Ordered.HIGHEST_PRECEDENCE)
#Bean(initMethod = "start", destroyMethod = "stop")
public Service smsService() {
settings();
Service service = Service.getInstance();
return service;
}
private void settings() {
log.debug("Delay per invio sms " + modemSmsDelay +"ms");
Settings.gatewayDispatcherYield = modemSmsDelay;
}
}
Unfortunately in in method called "settings" the value of property modemSmsDelay is 0 also if in my application.properties file it's 1000.
In other parts of my app I can read values without problems.
==== UPDATE =====
I solved the problem. Infact my code works, is not needed #PostConstruct to make #Value tag work, also if it's desiderable in several circustances.
I had a problem in my Spring configuration that prevented the execution of all annotation as #PostConstruct,#Autowire, etc.
I noticed this from log where Spring printed a Warning message.
Try putting the #PostConstruct annotation on your settings() method rather than calling it from the constructor. This will cause the method to be called automagically after the constructor exits.
This works for me :
#Resource private Environment environment;
import javax.annotation.Resource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import my.beautiful.code.SomeClient;
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Resource
private Environment environment;
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.sources(Application.class);
}
#Bean(name = "someClient")
public SomeClient loadSomeClient() {
SomeClient bean = new SomeClient();
...
bean.setHeaderContentType(environment.getProperty("contentType"));
bean.setRestUrl(environment.getProperty("rest.url"));
...
return bean;
}
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
}
And in my application.properties
contentType=some_value
rest.url=http://localhost/....
HTH

Setting up Spring 4.1 profile environment using YAML instead of Properties and #Profile

I'm trying to set up my profiles using YAML configuration files. Rather than having different #Configuration classes annotated with #Profile for different ones (or even a same #Configuration class with different annotated #Beans), i would like to have one #Configuration class using Placeholder with YAML configuration file.
Taking a look at Spring boot documentation, YamlPropertiesFactoryBean javadoc and this Stackoverflow topic, i've came up with the following code:
A simple YAML file: application-default-config.yml
foo: myFoo
A #Configuration file:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
#Configuration
public class ApplicationConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer ymlProperties() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer =
new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("config/application-${spring.profiles.active:default}-config.yml"));
propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
return propertySourcesPlaceholderConfigurer;
}
#Value("${foo}")
private String fooValue;
#Bean
public String fooValue() {
return fooValue;
}
}
A test file:
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = ApplicationConfig.class)
public class ApplicationConfigTest {
#Autowired
Environment environment;
#Autowired
String fooValue;
#Test
public void testFooViaEnvironment() {
Assert.assertEquals("myFoo", environment.getProperty("foo"));
}
#Test
public void testFooViaWiredValue() {
Assert.assertEquals("myFoo", fooValue);
}
}
And, finally, a main file:
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.io.ClassPathResource;
public class Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ApplicationConfig.class);
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("config/application-${spring.profiles.active:default}-config.yml"));
ConfigurableEnvironment environment = ctx.getEnvironment();
environment.getPropertySources()
.addFirst(new PropertiesPropertySource("custom", yaml.getObject()));
ctx.refresh();
String fooViaWiredValue = (String) ctx.getBean("fooValue");
System.out.println(String.format("fooViaEnvironment=%s", environment.getProperty("foo")));
System.out.println(String.format("fooViaWiredValue=%s", fooViaWiredValue));
}
}
I've noticed that in my test class, i can access the 'foo' property via #Value annotation but not via Environment.
As well explained in some Stackoverflow topics like this and that, annotating a PropertySourcesPlaceholderConfigurer as a #Bean is not enough to tight it with the Environment. It is necessary to do it programmatically as i did in Application class. In contrast, annotated #Values are wired accordingly.
My questions are, in fact, about best practices working with Spring.
I would prefer using Environment rather than #Value annotation.
Is there any way to load my YAML configuration files into Spring application context inside a test environment without needing to do it programmatically as i did in Application class ?
Is there any reason i should prefer using #Value (or any other profile configuration) over Environment + YAML configuration files ? As i said, i would like to have a unique #Bean using placeholders rather than multiples #Beans annotated with #Profiles.
I found this SPR where Chris Beams states why PropertySourcesPlaceholderConfigurer should not be registered automatically by Spring and why one should prefer user Environment over #value.
In addition, on Spring reference documentation, the Spring Testing Annotation section shows how to use ApplicationContextInitializer, which could be used to setup YamlPropertiesFactoryBean properly.

Categories

Resources