I am trying to use Environment abstraction & @PropertySource of Spring to load and use properties in my @Configuration annotated classes. However I get Environment as null in my PropertyConfig class as it is accessed from another @Configuration class PersistenceConfig which used it to access the properties. Here is my relevant code :
@Configuration
@PropertySource({ "classpath:/properties/email_${environment}.properties" })
@PropertySource({ "classpath:/properties/appconfig.properties" })
@PropertySource({ "classpath:/properties/ApplicationResources.properties" })
@PropertySource({ "classpath:/properties/Database_${environment}.properties" })
@PropertySource({ "classpath:/properties/log4j.properties" })
@PropertySource({ "classpath:/properties/system.properties" })
public class PropertiesConfig {
@Autowired
private Environment env;
private static final PropertiesAccessor propertyAccessor = new PropertiesConfig().new PropertiesAccessor();
public static String getPopertyValue(String property){
return propertyAccessor.getPropertyValue(property);
}
private class PropertiesAccessor{
public String getPropertyValue(String key){
return env.getProperty(key);
}
}
}
My Other @Configuration annotated class PersistenceConfig is as follows :
@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = {"com.template"})
public class PersistenceConfig {
@Bean
public LocalSessionFactoryBean sessionFactory(){
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String [] {"com.template.domain" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
@Bean
public BasicDataSource dataSource(){
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(PropertiesConfig.getPopertyValue("jdbc.driverClassName"));
dataSource.setUrl(PropertiesConfig.getPopertyValue("jdbc.url"));
dataSource.setUsername(PropertiesConfig.getPopertyValue("jdbc.user"));
dataSource.setPassword(PropertiesConfig.getPopertyValue("jdbc.pass"));
return dataSource;
}
@Bean
public HibernateTransactionManager transactionManager(){
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
Properties hibernateProperties(){
return new Properties() {
{
setProperty("hibernate.hbm2ddl.auto", PropertiesConfig.getPopertyValue("hibernate.hbm2ddl.auto"));
setProperty("hibernate.dialect", PropertiesConfig.getPopertyValue("hibernate.dialect"));
setProperty("hibernate.globally_quoted_identifiers", "true");
}
};
}
}
However I get NullpointerException when dataSource() method of PersistenceConfig tries to retrieve properties using PropertiesConfig.getPopertyValue("jdbc.driverClassName") because env of type Environment is null in PropertyConfig.
I am loading both classes as follows in my WebApplicationInitializer :
public class WebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(PropertiesConfig.class,SecurityConfig.class,PersistenceConfig.class,ApplicationConfig.class);
//rootContext.register(ApplicationConfig.class, PersistenceConfig.class, SecurityConfig.class); I have not added security yet
// Manage the life-cycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherServlet = new AnnotationConfigWebApplicationContext();
dispatcherServlet.register(MvcConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherServlet));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
As far as I understand PersistenceConfig is being loaded first before PropertyConfig. Am I right? Or is there any other reason? How to make this work?
Environment
directly? – Excellencystatic
variable is set, I still don't see the added benefit it adds only some indirection. – Excellency@PropertySource
on a single configuration class. They will all be part of the theEnvironment
. You are calling a static method there is no guarantee that the class is already injected and postconstruct called when you call your static method. If it works it is more or less luck then good design. Also withEnvironment.getProperty
you still have a single way, and this class isn't probiiting anything or someone to still use the environment. – Excellency@Value
either as method arguments or as class attributes. – ExcellencyPropertySourcesPlaceholderConfigurer
for proper@Value
resolution.@Bean
methods must not to be private else it won't work anyway. You can put@Value
on regardless what, but the limitation is the@Bean
method. You can always use private instance variables for your config classes. – Excellency