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.
Related
I have a class having Autowired Constructor.
now when i am autowiring this class object in my class. how do i pass arguments for constructor??
example code:
Class having Autowired Constructor:
#Component
public class Transformer {
private String dataSource;
#Autowired
public Transformer(String dataSource)
{
this.dataSource = dataSource;
}
}
Class using autowire for component having constructor with arguments:
#Component
public class TransformerUser {
private String dataSource;
#Autowired
public TransformerUser(String dataSource)
{
this.dataSource = dataSource;
}
#Autowired
Transformer transformer;
}
this code fails with message
"Unsatisfied dependency expressed through constructor parameter 0"
while creating bean of type Transformer.
how do i pass the arguments to Transformer while Autorwiring it??
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import lombok.extern.slf4j.Slf4j;
#Slf4j
public class Transformer {
private String datasource;
#Autowired
public Transformer(String datasource) {
this.datasource=datasource;
log.info(datasource);
}
}
Then create a config file
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class BeanConfig {
#Bean
public Transformer getTransformerBean() {
return new Transformer("hello spring");
}
#Bean
public String getStringBean() {
return new String();
}
}
you can use resource files
1) define a file like database.properties and put a variable like
datasource=example
in this file
2) define a configuration class
#Configuration
#PropertySource(value = {"classpath:resources/database.properties"})
public class PKEServiceFactoryMethod {
private final Environment environment;
#Bean
public String dataSource() {
return environment.getProperty("dataSource");
}
}
also you can use placeholder that is much better of using constructor in this case
#Component
#PropertySource(value = {"classpath:resources/database.properties"})
public class Transformer {
#Value("${dataSource}")
private String dataSource;
}
I am new to Spring MVC and I would like your help on how to read a property file in a WebAppConfig.java using a Map and with #Bean and #AutoWire. The constants in the property file is used as a common strings in different files (like an enum).
myproperty.properties
user.first_name = Jane
user.age = 23
WebAppConfig.java
#Configuration
#ComponentScan( {"com.nokia.care.triggerengine", "com.nokia.care.gui.commons"} )
#EnableWebMvc
#EnableTransactionManagement
#PropertySource( "classpath:application.properties" )
public class WebAppConfig
extends WebMvcConfigurerAdapter
{
...
Furthermore the webappconfig.java already has an existing #propertsource.
Thank you for your help.
With spring-boot you may create a separate config component and then autowire it.
#Component
#ConfigurationProperties(prefix = "user")
public class UserConfig {
private String userFirstName;
private String userAge;
//getters and setters
}
public class WebAppConfig extends WebMvcConfigurerAdapter {
#Autowired
private UserConfig userConfig;
...
}
Without spring-boot you should find needed dependencies for using #ConfigurationProperties
Use this #Value to access value in bean and repository class
#Value("${user.first_name}")
private String userFirstName;
#Value("${user.age}")
private String userAge;
A good way to do this is read all the configuration in an AppConfig class
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
#Configuration
#PropertySource("classpath:myproperty.properties")
public class AppConfig {
#Autowired
private Environment env;
public Environment getEnv(){
return env;
}
}
This way the env variable will have the map of all properties' key value pairs from myproperty.properties.
Now you can inject this AppConfig class in whichever class you like.
Like
public class A{
.
.
#Autowired
private AppConfig appConfig;
.
.
private void method1(){
int age= appConfig.getEnv().getProperty("user.age");
}
This way you can separate property-reading logic at one place, and make your code more modular.
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.
In my repository there are file-properties with this var:
wizard.start.scriptNameAndroid=install-android.bat
This is a part of my file spring-businss.xml:
<bean id="wizardService" class="business.services.WizardServiceImpl">
<property name="nameFileAndroid" value="${wizard.start.scriptNameAndroid}"/>
</bean>
This is my class Java
public class WizardServiceImpl implements WizardService {
private static String nameFileAndroid="";
[...]
public String getNameFileAndroid() {
return nameFileAndroid;
}
public void setNameFileAndroid(String nameFileAndroid) {
this.nameFileAndroid = nameFileAndroid;
}
}
When i use the variable nameFileAndroid the program take always the value that i set into the class.
How can i do priority of file file-properties?
Why you don't Inject it using:
#Value("${wizard.start.scriptNameAndroid}")
private static String nameFileAndroid;
it will take value from your properties file.
If that variable is in .properties file you can refer to its value like this:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
#ComponentScan(basePackages = { "business.services.*" })
#PropertySource("classpath:file.properties")
public class WizardServiceImpl implements WizardService {
#Autowired
private Environment enviro;
private static String nameFileAndroid = enviro.getProperty("wizard.start.scriptNameAndroid");
}
Another way
#ComponentScan(basePackages = { "business.services.*" })
#PropertySource("classpath:file.properties")
public class WizardServiceImpl implements WizardService {
#Value("${wizard.start.scriptNameAndroid}")
private static String nameFileAndroid;
//Register bean to enable ${} value wiring
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Or if you still prefer XML way:
<context:property-placeholder location="resources/file.properties" />
Hope i helped. :)
I am writing a desktop Spring Boot and Data-JPA application.
Initial settings come from application.properties (some spring.datasource.* and spring.jpa.*)
One of the features of my program is possibility to specify database settings (rdbms type,host,port,username,password and so on) via ui.
That's why I want to redefine already initialized db properties at runtime.
That's why I am finding a way to do that.
I tried to do the following:
1) I wrote custom DbConfig where DataSource bean declared in Singleton Scope.
#Configuration
public class DBConfig {
#ConfigurationProperties(prefix = "spring.datasource")
#Bean
#Scope("singleton")
#Primary
public DataSource dataSource() {
return DataSourceBuilder
.create()
.build();
}
}
2) In some DBSettingsController I got the instance of this bean and update new settings:
public class DBSettingsController {
...
#Autowired DataSource dataSource;
...
public void applySettings(){
if (dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource){
org.apache.tomcat.jdbc.pool.DataSource tomcatDataSource = (org.apache.tomcat.jdbc.pool.DataSource) dataSource;
PoolConfiguration poolProperties = tomcatDataSource.getPoolProperties();
poolProperties.setUrl("new url");
poolProperties.setDriverClassName("new driver class name");
poolProperties.setUsername("new username");
poolProperties.setPassword("new password");
}
}
}
But it has no effect. Spring Data Repositories are steel using initialy initialized DataSource properties.
Also I heard about Spring Cloud Config and #RefreshScope. But i think it's a kind of overhead to run http webserver alongside of my small desktop application.
Might it is possible to write custom scope for such beans?
Or by some way bind changes made in application.properties and corresponding beans properties?
Here is my solution (it might be outdated as it was created in 2016th):
DbConfig (It does not really needed, I just added for completeness config)
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.jta.JtaTransactionManager;
import javax.sql.DataSource;
#Configuration
public class DBConfig extends HibernateJpaAutoConfiguration {
#Value("${spring.jpa.orm}")
private String orm; // this is need for my entities declared in orm.xml located in resources directory
#SuppressWarnings("SpringJavaAutowiringInspection")
public DBConfig(DataSource dataSource, JpaProperties jpaProperties, ObjectProvider<JtaTransactionManager> jtaTransactionManagerProvider) {
super(dataSource, jpaProperties, jtaTransactionManagerProvider);
}
#Override
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder factoryBuilder)
{
final LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = super.entityManagerFactory(factoryBuilder);
entityManagerFactoryBean.setMappingResources(orm);
return entityManagerFactoryBean;
}
}
DataSourceConfig
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
#Configuration
public class DataSourceConfig {
#Bean
#Qualifier("default")
#ConfigurationProperties(prefix = "spring.datasource")
protected DataSource defaultDataSource(){
return DataSourceBuilder
.create()
.build();
}
#Bean
#Primary
#Scope("singleton")
public AbstractRoutingDataSource routingDataSource(#Autowired #Qualifier("default") DataSource defaultDataSource){
RoutingDataSource routingDataSource = new RoutingDataSource();
routingDataSource.addDataSource(RoutingDataSource.DEFAULT,defaultDataSource);
routingDataSource.setDefaultTargetDataSource(defaultDataSource);
return routingDataSource;
}
}
My extension of RoutingDataSource:
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
public class RoutingDataSource extends AbstractRoutingDataSource {
static final int DEFAULT = 0;
static final int NEW = 1;
private volatile int key = DEFAULT;
void setKey(int key){
this.key = key;
}
private Map<Object,Object> dataSources = new HashMap();
RoutingDataSource() {
setTargetDataSources(dataSources);
}
void addDataSource(int key, DataSource dataSource){
dataSources.put(new Integer(key),dataSource);
}
#Override
protected Object determineCurrentLookupKey() {
return new Integer(key);
}
#Override
protected DataSource determineTargetDataSource() {
return (DataSource) dataSources.get(key);
}
}
And here it's special spring component to swith datasource in runtime:
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
#Component
public class DBSettingsSwitcher {
#Autowired
private AbstractRoutingDataSource routingDataSource;
#Value("${spring.jpa.orm}")
private String ormMapping;
public void applySettings(DBSettings dbSettings){
if (routingDataSource instanceof RoutingDataSource){
// by default Spring uses DataSource from apache tomcat
DataSource dataSource = DataSourceBuilder
.create()
.username(dbSettings.getUserName())
.password(dbSettings.getPassword())
.url(dbSettings.JDBConnectionURL())
.driverClassName(dbSettings.driverClassName())
.build();
RoutingDataSource rds = (RoutingDataSource)routingDataSource;
rds.addDataSource(RoutingDataSource.NEW,dataSource);
rds.setKey(RoutingDataSource.NEW);
updateDDL(dbSettings);
}
}
private void updateDDL(DBSettings dbSettings){
/** worked on hibernate 5*/
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.applySetting("hibernate.connection.url", dbSettings.JDBConnectionURL())
.applySetting("hibernate.connection.username", dbSettings.getUserName())
.applySetting("hibernate.connection.password", dbSettings.getPassword())
.applySetting("hibernate.connection.driver_class", dbSettings.driverClassName())
.applySetting("hibernate.dialect", dbSettings.dialect())
.applySetting("show.sql", "false")
.build();
Metadata metadata = new MetadataSources()
.addResource(ormMapping)
.addPackage("specify_here_your_package_with_entities")
.getMetadataBuilder(registry)
.build();
new SchemaUpdate((MetadataImplementor) metadata).execute(false,true);
}
}
Where DB settings is just an interface (you should implement it according to your needs):
public interface DBSettings {
int getPort();
String getServer();
String getSelectedDataBaseName();
String getPassword();
String getUserName();
String dbmsType();
String JDBConnectionURL();
String driverClassName();
String dialect();
}
Having your own implementation of DBSettings and builded DBSettingsSwitcher in your Spring context, now you can just call DBSettingsSwitcher.applySettings(dbSettingsIml) and your data requests will be routed to new data source.