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;
}
}
Related
I cannot access #Value("${app.version}") or event environment.getProperty("app.version") or any property in my controllers or services.
My project structure looks like this
src/main/java
-configuration/
AppConfig.java
EnvConfig.java
JpaConfig.java
UiConfig.java
ServicesConfig.java
UiAppInitializer.java
-repositories/
....
-models/
....
-services/
....
-controllers/
....
My UiAppInitializer is pretty straight forward,
getRootConfigClassess() returns AppConfig.class and getServletConfigClasses() returns UiConfig.class
AppConfig.java
#Configuration
#Import({
EnvConfig.class,
UiConfig.class,
ServicesConfig.class
})
public class AppConfig{}
EnvConfig
#Configuration
public class EnvConfig implements InitializingBean {
#Value("${app.version}")
private String appVersion
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer();
pc.setLocations(new ClassPathResource("application.properties"));
return pc;
}
#Override
public void afterpropertiesSet() throws Exception {
log.debug("App Version is " + appVersion);
}
}
A simple controller
#RestController
#RequestMapping(value = "/version")
public class VersionContoller {
#Value("${app.version}")
private String version;
#GetMapping()
public String getVersion() {
return version;
}
}
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {
"my.packages.path.ui"
})
public class UiConfig implements WebMvcConfigurer {
....
}
The controller just returns "${app.version}" but the afterpropertiesSet correctly logs the version.
What am I doing wrong here? I have other controllers that connect to the repository successfully which was setup in JpaConfig that usues #Value for all the properties also
Note not using Spring Boot
It seems the controller is getting initialised as a bean before the properties() bean has had setLocations() called.
You could remove classpath scanning (I assume you have it on to find the controller bean?) and in your EnvConfig declare a new method that is a bean declaration for the Controller that passes in the version String. Obviously requiring a change to the controller constructor too
#Configuration
public class EnvConfig implements InitializingBean {
#Value("${app.version}")
private String appVersion
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer();
pc.setLocations(new ClassPathResource("application.properties"));
return pc;
}
#Bean
public VersionContoller controller() {
return new VersionController(appVersion);
}
#Override
public void afterpropertiesSet() throws Exception {
log.debug("App Version is " + appVersion);
}
}
Assuming you have the following spring configuration:
#Configuration
public class Config {
#Bean
public SomeBean someBean() {
SomeBean someBean = new SomeBean();
someBean.setVar("foobar");
return someBean;
}
}
Then I can use this configuration in some other class for example by importing it with #Import(Config.class). Now, say you don't want to hardcode the string "foobar" but pass it as a parameter to that configuration. How would I do that? It would be nice to create a custom annotation like #FooBarConfiguration(var = "foobar"). Is that possible?
The #Ben answer is the classic and better approach. But if you don't want to use a property file, you can use a #Bean for that. Each #Bean holds a value that you would like to inject.
Full code example:
#SpringBootApplication
public class So49053082Application implements CommandLineRunner {
#Bean
String beanValueFooBar() {
return "fooBar";
}
#Bean
String beanValueBarFoo() {
return "barFoo";
}
private class SomeBean {
private String var;
public void setVar(final String var) {
this.var = var;
}
}
#Configuration
public class Config {
#Bean
public SomeBean someBean(String beanValueBarFoo) {
SomeBean someBean = new SomeBean();
System.out.println(beanValueBarFoo);
someBean.setVar(beanValueBarFoo);
return someBean;
}
}
#Override
public void run(String... args) {
}
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(So49053082Application.class, args);
context.close();
}
}
Consider using the #Value annotation:
#Configuration
public class Config {
#Value("${myParamValue}")
public String myParam;
#Bean
public SomeBean someBean() {
SomeBean someBean = new SomeBean();
someBean.setVar(myParam);
return someBean;
}
}
you'll need to put the parameters into the environment somehow: there are various techniques using the OS environment, runtime parameters or configuration files, as suits your purposes.
I would like to read some properties, like DB access configs, when initializing bean or service in spring boot.
Anyone knows good ways ?
This is my current code snippet.
public class SampleApplication implements ApplicationRunner
{
#Autowired
private YAMLConfig myConfig;
#Override
public void run(ApplicationArguments args) throws Exception
{
System.out.println(myConfig != null); //YAMLConfig has been intialized here
}
public SampleApplication()
{
System.out.println(myConfig == null); //myConfig is null
}
#Configuration
public static class Config
{
#Bean
#ConditionalOnProperty(value = {"batch.execute"}, havingValue = "SampleApplication")
public SampleApplication sampleApplication()
{
return new SampleApplication();
}
}
}
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties
public class YAMLConfig
{
private String environment;
public String getEnvironment()
{
return environment;
}
public void setEnvironment(String environment)
{
this.environment = environment;
}
}
Thanks for taking a look at this!
create this method inside your SampleApplication class
#PostConstruct
public void init() {
// at this point, all the dependency injection has happened already
myConfig.doStuff()
}
it will be called by spring automatically after all bean initialization has been done.
I have a java configuration file (class with #configuration annotation). It has one method with #Bean annotation and I would like to instantiate this bean based on some arguments. In other words I would like to get a bean by name (passed via argument) and instantiate this bean.
Is it possible to do this in #configuration class?
#Configuration
public class ApplicationConfig {
#Resource
private Config config;
#Bean
public Object application() throws ParseException {
return new SampleApp(/*get the bean by name*/);
}
}
config contains the argument and I would like to use this argument and get the bean by that name.
Something like this should work:
#Configuration
public class ApplicationConfig {
#Resource
private Config config;
#Autowired
private ApplicationContext appContext;
#Bean
public Object application() throws ParseException {
return new SampleApp(
(appContext.getBean("beanNameFromConfig"));
}
}
I am trying to build a new annotation based spring boot application.
On the DAO-level I have a configuration class with Dao beans:
#Configuration
#EnableTransactionManagement
public class DatabaseConfig {
#Bean
public DataSource dataSource(){
...
return dataSource;
}
#Bean
public JdbcTemplate jdbcTemplate(){
JdbcTemplate template = new JdbcTemplate();
template.setDataSource(dataSource());
return template;
}
#Bean
public DataSourceInitializer dataSourceInitializer(DataSource dataSource)
{
....
}
#Bean
public PersonDao personDao(){
return new PersonDao();
}
}
On the server level a controller and a Mein class.
#SpringBootApplication (exclude = SecurityAutoConfiguration.class)
#ComponentScan("my.package")
#Import(DataBaseConfig.class)
public class Main {
private static Logger log = Logger.getLogger(Main.class);
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
The problem is that the main class does not see the beans got from the DatabaseConfig and that's why cannot start the application (because they are user in the controller). How can I correctly import them?