I'm trying to load properties using annotations:
#PropertySource({"classpath:application.properties"})
and
#Value("${my.property}")
String myProperty;
as a result, myProperty is always null
While it is working using:
BatchConfiguration.class.getClassLoader().getResourceAsStream("application.properties");
This is my Batch conf class signature :
#Configuration
#ComponentScan
#EnableBatchProcessing
#PropertySource({"classpath:application.properties"})
public class BatchConfiguration {
#Value("${db.url}")
private String url;
...
}
And Application.java:
#SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
I also tried to load it using:
#Autowired
public static Environment env;
But env is also null.
Pass following JVM Argument when running Spring boot application
--spring.config.location=properties file path
Remove {} in your #PropertySource({"classpath:application.properties"})
It should be
#PropertySource("classpath:application.properties")
or
#PropertySource(value="classpath:application.properties")
Related
When I try to run my spring boot project, I get an error like that:
Description:
Parameter 0 of method propertySourcesPlaceholderConfigurer in
AppConfig required a bean of type 'java.io.File' that
could not be found.
Action:
Consider defining a bean of type 'java.io.File' in your configuration.
#SpringBootApplication
#Slf4j
public class AppRunner implements CommandLineRunner {
#Autowired
private BeanFactory beanFactory;
public static void main(String[] args) throws IOException {
SpringApplication.run(AppRunner.class, args);
}
#Override
public void run(String... args) throws Exception {
File file = new File("path\\credentials.properties");
PropertySourcesPlaceholderConfigurer report =
beanFactory.getBean(PropertySourcesPlaceholderConfigurer.class, file);
}
}
My configuration file looks like that:
#Configuration
public class AppConfig {
#Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(File file) throws IOException {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setProperties(Utils.getProperties(file));
propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(true);
propertySourcesPlaceholderConfigurer.setIgnoreResourceNotFound(true);
return propertySourcesPlaceholderConfigurer;
}
}
I want to call singleton bean with parameter. But I try to it like that I get an error like defined above. How can I solve this?
What is your intention for using the PropertySourcesPlaceholderConfigurer? You did already created the Bean, so you are able to inject it via #Autowired.
The method with the #Bean annotation is called via Spring on application startup. If you want to initialize that bean manually, you have to remove the #Bean annotation or create a file based bean in your AppConfig class:
#Bean
public File getFile() {
return new File("path\\credentials.properties");
}
EDIT:
Take a look at this post, if you want to use command line values while creating beans with the #Bean annotation: Spring Boot: get command line argument within #Bean annotated method
Problem is solved according to comment of #M. Deinum like below:
#SpringBootApplication
#Slf4j
public class AppRunner implements CommandLineRunner {
public static void main(String[] args) throws IOException {
System.setProperty("spring.config.additional-location","path\\credentials.properties");
SpringApplication.run(AppRunner.class, args);
}
#Override
public void run(String... args) throws Exception {
...
}
}
Or using Environment:
#Configuration
public class AppConfig implements EnvironmentAware {
Environment env;
#Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() throws IOException {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
Properties properties = Utils.getProperties(new File(env.getProperty("credential")));
properties.setProperty("startDate",env.getProperty("startDate"));
propertySourcesPlaceholderConfigurer.setProperties(properties);
propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(true);
propertySourcesPlaceholderConfigurer.setIgnoreResourceNotFound(true);
return propertySourcesPlaceholderConfigurer;
}
#Override
public void setEnvironment(Environment environment) {
env = environment;
}
}
I have a Spring-Boot-Application as a multimodule-Project in maven. The structure is as follows:
Parent-Project
|--MainApplication
|--Module1
|--ModuleN
In the MainApplication project there is the main() method class annotated with #SpringBootApplication and so on. This project has, as always, an application.properties file which is loaded automatically. So I can access the values with the #Value annotation
#Value("${myapp.api-key}")
private String apiKey;
Within my Module1 I want to use a properties file as well (called module1.properties), where the modules configuration is stored. This File will only be accessed and used in the module. But I cannot get it loaded. I tried it with #Configuration and #PropertySource but no luck.
#Configuration
#PropertySource(value = "classpath:module1.properties")
public class ConfigClass {
How can I load a properties file with Spring-Boot and access the values easily? Could not find a valid solution.
My Configuration
#Configuration
#PropertySource(value = "classpath:tmdb.properties")
public class TMDbConfig {
#Value("${moviedb.tmdb.api-key}")
private String apiKey;
public String getApiKey() {
return apiKey;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Calling the Config
#Component
public class TMDbWarper {
#Autowired
private TMDbConfig tmdbConfig;
private TmdbApi tmdbApi;
public TMDbWarper(){
tmdbApi = new TmdbApi(tmdbConfig.getApiKey());
}
I'm getting an NullPointerException in the constructor when I autowire the warper.
For field injection:
Fields are injected right after construction of a bean, before any config methods are invoked. Such a config field does not have to be public. Refer Autowired annotation for complete usage. Use constructor injection in this case like below:
#Component
public class TMDbWarper {
private TMDbConfig tmdbConfig;
private TmdbApi tmdbApi;
#Autowired
public TMDbWarper(final TMDbConfig tmdbConfig){
this.tmdbConfig = tmdbConfig;
tmdbApi = new TmdbApi(tmdbConfig.getApiKey());
}
(or)
Use #PostConstruct to initialise like below:
#Component
public class TMDbWarper {
#Autowired
private TMDbConfig tmdbConfig;
private TmdbApi tmdbApi;
#PostConstruct
public void init() {
// any initialisation method
tmdbConfig.getConfig();
}
Autowiring is performed just after the creation of the object(after calling the constructor via reflection). So NullPointerException is expected in your constructor as tmdbConfig field would be null during invocation of constructor
You may fix this by using the #PostConstruct callback method as shown below:
#Component
public class TMDbWarper {
#Autowired
private TMDbConfig tmdbConfig;
private TmdbApi tmdbApi;
public TMDbWarper() {
}
#PostConstruct
public void init() {
tmdbApi = new TmdbApi(tmdbConfig.getApiKey());
}
public TmdbApi getTmdbApi() {
return this.tmdbApi;
}
}
Rest of your configuration seems correct to me.
Hope this helps.
Here is a Spring Boot multi-module example where you can get properties in different module.
Let's say I have main application module, dataparse-module, datasave-module.
StartApp.java in application module:
#SpringBootApplication
public class StartApp {
public static void main(String[] args) {
SpringApplication.run(StartApp.class, args);
}
}
Configuration in dataparse-module. ParseConfig.java:
#Configuration
public class ParseConfig {
#Bean
public XmlParseService xmlParseService() {
return new XmlParseService();
}
}
XmlParseService.java:
#Service
public class XmlParseService {...}
Configuration in datasave-module. SaveConfig.java:
#Configuration
#EnableConfigurationProperties(ServiceProperties.class)
#Import(ParseConfig.class)//get beans from dataparse-module - in this case XmlParseService
public class SaveConfig {
#Bean
public SaveXmlService saveXmlService() {
return new SaveXmlService();
}
}
ServiceProperties.java:
#ConfigurationProperties("datasave")
public class ServiceProperties {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
application.properties in datasave-module in resource/config folder:
datasave.message=Multi-module Maven project!
threads.xml.number=5
file.location.on.disk=D:\temp\registry
Then in datasave-module you can use all your properties either through #Value.
SaveXmlService.java:
#Service
public class SaveXmlService {
#Autowired
XmlParseService xmlParseService;
#Value("${file.location.on.disk: none}")
private String fileLocation;
#Value("${threads.xml.number: 3}")
private int numberOfXmlThreads;
...
}
Or through ServiceProperties:
Service.java:
#Component
public class Service {
#Autowired
ServiceProperties serviceProperties;
public String message() {
return serviceProperties.getMessage();
}
}
I had this situation before, I noticed that the properties file was not copied to the jar.
I made the following to get it working:
In the resources folder, I have created a unique package, then stored my application.properties file inside it. e.g: com/company/project
In the configuration file e.g: TMDBConfig.java I have referenced the full path of my .properties file:
#Configuration
#PropertySource("classpath:/com/company/project/application.properties")
public class AwsConfig
Build and run, it will work like magic.
You could autowire and use the Enviornment bean to read the property
#Configuration
#PropertySource(value = "classpath:tmdb.properties")
public class TMDbConfig {
#Autowired
private Environment env;
public String getApiKey() {
return env.getRequiredProperty("moviedb.tmdb.api-key");
}
}
This should guarantee that property is read from the context when you invoke the getApiKey() method regardless of when the #Value expression is resolved by PropertySourcesPlaceholderConfigurer.
I have a basic SpringBoot app., embedded Tomcat, Thymeleaf template engine, and package as an executable JAR file.
I have this main class
package com.tdk.iot;
#SpringBootApplication
#Import({SecurityConfig.class })
public class TdkApplication {
public static void main(String[] args) {
SpringApplication.run(TdkApplication.class, args);
}
}
and this one
package com.tdk.iot.config;
#Configuration
#Profile("dev")
#PropertySource("file:///${user.home}/.tdk/application-dev.properties")
public class DevelopmentConfig {
#Bean
public EmailService emailService() {
return new MockEmailService();
}
#Bean
public ServletRegistrationBean h2ConsoleServletRegistration() {
ServletRegistrationBean bean = new ServletRegistrationBean(new WebServlet());
bean.addUrlMappings("/console/*");
return bean;
}
}
and this value in the application.properties:
spring.profiles.active=dev
But it seems that is not working since I can't access to the page /console/*
You should move #PropertySource to your SecurityConfig or TdkApplication classes, because you try to load profile property "dev" in class which will be included to context only when profile is "dev" - so Spring can't load property file.
I found the error. In the eclipse -> Run configurations -> Arguments the value was also overwritten with other value
-Dspring.profiles.active=acc
I have a project setup using Spring Boot 0.5.0.M5.
In one of the configuration files I am trying to #Autowire Environment but that fails with a NullPointerException.
Here's what I have so far:
Application.java
#EnableAutoConfiguration
#Configuration
#ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
JpaConfig.java where I am trying to #Autowire Environment
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "com.ui.persistence.repository")
public class JpaConfig {
private static final String DATABASE_DRIVER = "db.driver";
private static final String DATABASE_PASSWORD = "db.password";
private static final String DATABASE_URL = "db.url";
private static final String DATABASE_USERNAME = "db.username";
private static final String HIBERNATE_DIALECT = "hibernate.dialect";
private static final String HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String ENTITYMANAGER_PACKAGES_TO_SCAN
= "entitymanager.packages.to.scan";
#Autowired
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty(DATABASE_DRIVER));
dataSource.setUrl(env.getProperty(DATABASE_URL));
dataSource.setUsername(env.getProperty(DATABASE_USERNAME));
dataSource.setPassword(env.getProperty(DATABASE_PASSWORD));
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean
= new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProviderClass(
HibernatePersistence.class);
entityManagerFactoryBean.setPackagesToScan(
env.getProperty(ENTITYMANAGER_PACKAGES_TO_SCAN));
entityManagerFactoryBean.setJpaProperties(hibernateProperties());
return entityManagerFactoryBean;
}
}
I am trying to load the database properties configured in a properties file. However, the Environment is not injected and the code fails with NullPointerException. I do not have any configuration in XML files.
For the properties file I have configured PropertySourcesPlaceholderConfigurer this way:
#Configuration
#PropertySource("classpath:database.properties")
public class PropertyConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
I have tried swapping #Autowired, #Resource and #Inject but nothing has worked so far. Would appreciate any help. Thanks.
Though your specific problem is solved, here's how to get Environment in case Spring's autowiring happens too late.
The trick is to implement org.springframework.context.EnvironmentAware; Spring then passes environment to setEnvironment() method.
This works since Spring 3.1.
An example:
#Configuration
#PropertySource("classpath:myProperties.properties")
public class MyConfiguration implements EnvironmentAware {
private Environment environment;
#Override
public void setEnvironment(final Environment environment) {
this.environment = environment;
}
public void myMethod() {
final String myPropertyValue = environment.getProperty("myProperty");
// ...
}
}
This is not as elegant as #Autowired or #Value, but it works as workaround in some situations.
I believe there were some lifecycle issues with Spring and the EntityManagerFactory, and you might have fallen foul of those (fixed in 4.0.0.RC1) - if your #Configuration class gets instantiated super early, it might not be eligible for autowiring. You can probably tell from the log output if that is the case.
Just out of interest, did you know that the functionality provided by your JpaConfig and PropertyConfig is already presetn out of the box if you use #EnableAutoConfiguration (as long as you #ComponentScan that package where your repositories are defined)? See the JPA sample in Spring Boot for an example.
I had the same problem on Spring Batch. Writers cannot autowire Environment class because Configuration class was instantiated earlier.
So I created a sort of Singleton (old manner) to instantiate Environment and I could access to it every time.
I did this implementation :
#Configuration
#PropertySource(value = { "classpath:kid-batch.properties" }, ignoreResourceNotFound = false)
public class BatchConfiguration implements EnvironmentAware {
private static Environment env;
public static String getProperty(String key) {
return env.getProperty(key);
}
#Override
public void setEnvironment(Environment env) {
BatchConfiguration.env = env;
}
}
And it works
I was having the similar issue to read properties from my application.properties file in spring boot application. I have struggled a lot to figure out the problem and make it work. Finally I have done. Here is my Constants class which will read properties values from properties file. I hope it will help to someone.
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
#Configuration
#PropertySource("classpath:application.properties")
public class Constants implements EnvironmentAware {
static Environment environment;
#Override
public void setEnvironment(Environment environment) {
Constants.environment = environment;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
public static String getActiveMQHost() {
System.out.println(environment.getProperty("spring.activemq.broker-host"));
return environment.getProperty("spring.activemq.broker-host");
}
public static String getActiveMQPort() {
System.out.println(environment.getProperty("spring.activemq.broker-port"));
return environment.getProperty("spring.activemq.broker-port");
}
public static String getActiveMQUser() {
System.out.println(environment.getProperty("spring.activemq.user"));
return environment.getProperty("spring.activemq.user");
}
public static String getActiveMQPassword() {
System.out.println(environment.getProperty("spring.activemq.password"));
return environment.getProperty("spring.activemq.password");
}
}
These are the property key's declared in my application.properties,
spring.activemq.broker-host
spring.activemq.broker-port
spring.activemq.user
spring.activemq.password
In my spring boot application, I have following configuration:
server:
host: a.com
port: 5922
enable-log: true
I want to read the above as a java.util.Properties. I tried putting following class:
#ConfigurationProperties(prefix = "server")
public class ServerConfig {
private Properties serverProps;
// ... Getter/setter
}
The boot config files look like:
#Configuration
#ComponentScan("com.demo")
#EnableAspectJAutoProxy(proxyTargetClass = true)
#EnableConfigurationProperties({ServerConfig.class})
#Profile({"dev"})
public class TestAppConfiguration {
}
#EnableAutoConfiguration
#SpringBootApplication
public class TestAppInitializer {
public static void main(final String[] args) {
SpringApplication.run(TestAppInitializer.class, args);
}
}
Unit test class:
#SpringApplicationConfiguration(classes = {TestAppInitializer.class})
#ActiveProfiles("dev")
public class ServerConfigTest extends AbstractTestNGSpringContextTests {
#Autowired
private ServerConfig serverConfig;
#Test
public void printDetails() {
logger.debug("ServerConfig.properties --> {}", serverConfig.getProperties());
}
}
The output is
ServerConfig.properties --> null.
I am not sure why is this happening. The only idea that comes to my mind is, the configuration parameters underneath server are basically flat strings. Is there any way I can read those as Properties?
#Bean({"kaptchaProperties"})
#ConfigurationProperties(prefix = "custom.kaptcha")
public Properties getProperties() {
return new Properties();
}
AFAIK, you can't load them into java.util.Properties with annotation #ConfigurationProperties.
You need to create this:
#Component
#ConfigurationProperties(prefix = "server")
public class ServerConfig {
private String host;
private String port;
private String enableLog;
// ... Getter/setter
}