I have a hard time loading properties from my properties file. I'm trying to load a property into my configuration class which is listed below.
package dk.fitfit.budget.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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 ApplicationConfig {
private static final Logger logger = LoggerFactory.getLogger(ApplicationConfig.class);
#Autowired
private Environment env;
#Value("${snot:test}")
private String snot;
public ApplicationConfig() {
logger.info("Application config loaded!"); // Displays as expected
logger.info("snot: {}", snot); // snot: null
logger.info("env: {}", env); // env: null
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
If I change the name of the file (application.properties) or "#PropertySource("classpath:application.properties")" I get an error about the file not being present. So clearly it's being loaded (to some extend anyway).
I was at least expecting to see the default string "test" injected into the variable snot. But not even that is done. I'm not able to autowire Environment either... not sure if there is a relation.
The content of my application.properties is as below.
snot=snog
My application.properties file is placed in src/main/resources/.
Anyone got a clue about what I'm doing wrong?
The purpose of a constructor is to initialize a class instance. You have to construct and initialize the class instance before Spring can do anything to it. As such, you cannot expect the env and snot fields to have anything other than the default null value within the constructor.
Spring (and all dependency-injection tools) can't inject fields before the instance is created with new, which is one reason why constructor injection should be preferred to field injection. Generally, you can use #Value on constructor parameters, but there are certain issues with #Configuration classes that make constructor injection impractical.
However, there's a solution meant for exactly this situation: #PostConstruct. This method will be called after the DI framework has done all its magic to the bean:
#PostConstruct
public void log() {
logger.info("Application config loaded!"); // Displays as expected
logger.info("snot: {}", snot); // snot: null
logger.info("env: {}", env); // env: null
}
Related
The war application uses JEE/CDI/JAX RS stack, managed by/deployed to Wildfly.
I want to simplify some parts of the app, for instance to let Spring handle configuration from properties file. So I need to combine JEE with Spring together.
Here is Spring Configuration:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
#Configuration
#PropertySource("classpath:test.properties")
public class Config {
#Value( "${hostName}" )
private String hostName;
public String getHostName() {
return hostName;
}
}
Config is injected via CDI annotion:
import javax.inject.Inject;
public class Consumer {
#Inject
Config config;
public String test(){
return "test +" + config.getHostName();
}
}
Config is injected successfully, but its getHostName method returns always null. In Maven dependencies I've included spring-core, spring-context, spring-beans to the dependencies.
Now the test.properties file does not exist in the classpath.
How to trigger the file loading by Spring and throw an exception that a file does not exist. To make sure it works.
I have some strange behavior in my Spring App, here is my Java Spring Boot application structure:
in package com.somethingsomething.packageA, I have 2 files
First is ParentA.java
package com.somethingsomething.packageA;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class ParentA {
#Autowired
private ChildA childA;
public ChildA getChildA() {
return childA;
}
#PostConstruct
public void ParentAPostConstruct() {
System.out.println("ParentA PostConstruct were called");
}
}
Second is ChildA.java
package com.somethingsomething.packageA;
import org.springframework.stereotype.Component;
#Component
public class ChildA {
public ChildA() {
System.out.println("ChildA were called");
}
}
and then under package com.somethingsomething.packageB, I also have two similar files.
First is ParentB.java
package com.somethingsomething.packageB;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class ParentB {
#Autowired
private ChildB childB;
public ChildB getChildB() {
return childB;
}
#PostConstruct
public void ParentBPostConstruct() {
System.out.println("ParentB PostConstruct were called");
}
}
Second is ChildB.java
package com.somethingsomething.packageB;
import org.springframework.stereotype.Component;
#Component
public class ChildB {
public ChildB() {
System.out.println("ChildB were called");
}
}
Both of packageA and packageB have similar structure. Then under com.somethingsomething I have two main function for both package:
ForPackageA.java
package com.somethingsomething;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import com.somethingsomething.packageA.ParentA;
#SpringBootApplication
public class ForPackageA {
public static void main(String[] args) {
ApplicationContext applicationContext =
SpringApplication.run(ForPackageA.class, args);
ParentA parentA =
applicationContext.getBean(ParentA.class);
System.out.println(parentA);
System.out.println(parentA.getChildA());
}
}
and ForPackageB.java
package com.somethingsomething;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import com.somethingsomething.packageB.ParentB;
#SpringBootApplication
public class ForPackageB {
public static void main(String[] args) {
ApplicationContext applicationContext =
SpringApplication.run(ForPackageB.class, args);
ParentB parentB =
applicationContext.getBean(ParentB.class);
System.out.println(parentB);
System.out.println(parentB.getChildB());
}
}
When i run ForPackageA.java, this will appear in log:
ChildA were called
ParentA PostConstruct were called
ChildB were called
ParentB PostConstruct were called
com.somethingsomething.packageA.ParentA#88d6f9b
com.somethingsomething.packageA.ChildA#47d93e0d
The ChildB were called and ParentB PostConstruct were called were not suppose to be there, since ForPackageA.java doesn't depend on those beans. Why is this happening?
The same thing also happening when i run ForPackageB.java, which will log following:
ChildA were called
ParentA PostConstruct were called
ChildB were called
ParentB PostConstruct were called
com.somethingsomething.packageB.ParentB#610db97e
com.somethingsomething.packageB.ChildB#6f0628de
But in this case ChildA were called and ParentA PostConstruct were called were not suppose to be logged.
So, why is this peculiar behavior is happening? Is this default behavior of Spring?
Edit:
If let say i add following line
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) to ParentB.java
(after #Component)
It will not make ParentB PostConstruct were called appear when i run
ForPackageA.java.
and also, if i add those line to ChildB.java it will also not
make ChildB were called appear when i run ForPackageA.java
Why are the beans act differently in prototype mode, i.e. they are not getting called like when they are in singleton mode?
Yes, this is default behaviour of Spring. At application start all Beans with a #Component annotation get created, no matter if you use them or not.
The call applicationContext.getBean(ParentB.class) then simply returns the already created Bean.
To answer your edit:
Spring Beans are by default Singletons, so theres always only one instance of the bean per applicationContext. This is Inversion of Control, meaning that Spring handles object instantiation, not you.
Beans with the Prototype scope can have multiple object instances and can, in a way, be instantiated by you. (By calling applicationContext.getBean(ParentA.class)). This is similar to doing something like ParentA a = new ParentA().
I suggest you read this to get a deeper understanding of scopes.
The bean object creation doesn't depends on which object you are trying to get. Whenever spring application gets launched, its all components object are created automatically and you are getting already created component object using applicationContext.getBean(componentClass) method. Hope this will help you to understand why you are getting logs for every object.
Why is this happening?
When you start your Spring app the ApplicationContext is initialised by component scanning your application and registering all Spring annotated beans in the context. This allows them to be injected as required.
Is this default behaviour of Spring?
Yes. You can change this behaviour by configuring the component scanning to only look at specified packages if you wish (although the use cases for this are few and far between).
I am using the findbugs Eclipse plugin (3.0.1.20150306-5afe4d1), spring (4.2.2.RELEASE), and eclipse (Mars.1 (4.5.1)) together and I am receiving the following FindBugs bug in Eclipse.
Non-null field env is not initialized by new
org.test.app.config.AppConfiguration() [Scary(8), Normal confidence]
I am using using the default constructor and using autowiring to initialize the env variable. I also have a PostConstruct annotation which gets called after everything is wired and accesses the env variable to make sure it was initialized correctly.
How can I make this error disappear without turning off the FindBugs plugin and still using the #Autowired annotation?
package org.test.app.config;
import java.util.Arrays;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
#Configuration
#ComponentScan(basePackages = { "org.test.app" })
#PropertySource("classpath:/${spring.profiles.active:local}.properties")
public class AppConfiguration {
private static final Logger log = LoggerFactory.getLogger(AppConfiguration.class);
#Autowired
private Environment env;
/**
* Dump profile info.
*/
#PostConstruct
public void details() {
log.debug("** App application context, active profile(s)={}", Arrays.toString(env.getActiveProfiles()));
}
}
Update
I tried using a constructor per #spoonybard896 suggestion, but it did not work. I received the following error.
java.lang.NoSuchMethodException: org.test.app.config. AppConfiguration $$EnhancerBySpringCGLIB$$cbece1d7.<init>()
[STDOUT] at java.lang.Class.getConstructor0(Class.java:3082) ~[na:1.8.0_60]
[STDOUT] at java.lang.Class.getDeclaredConstructor(Class.java:2178) ~[na:1.8.0_60]
[STDOUT] at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:80) ~[na:na]
How about using a non-default constructor instead?
private final Environment env;
#Autowired
public AppConfiguration(final Environment env) {
this.env = env;
}
EDIT
The above approach would work for a #Controller instance, but will not work for #Configuration. After doing some quick research it turns out that:
#Configuration is meta-annotated with #Component, therefore #Configuration classes are candidates for component scanning (typically using Spring XML's <context:component-scan/> element) and therefore may also take advantage of #Autowired/#Inject at the field and method level (but not at the constructor level).
I'm thinking that unless there is some kind of addon for FindBugs that understands Spring annotations (I do not know of one) then you may just need to apply a filter to the FindBugs plugin and have it ignore that particular error in that particular file(or in any Configuration class in general). In Eclipse check out Preferences -> Java -> Findbugs -> Filter Files, and check out this link which describes a similar problem and resolution, but just make sure to filter out only the error you want. The goal would not be turn FindBugs off, but instead have it just ignore this one case.
EDIT 2
Adding an annotation to the class will suppress the FindBugs error for this file only.
#SuppressFBWarnings(
value="NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR",
justification="Overriding the check on the env variable because Spring will automatically initialize the variable after the constructor is called and before any public methods are called.")
I was expecting following code to throw some kind of Initialization or Circular dependency exception but it seems to work. I can #Autowire SomeOtherBean in other classes and I checked that it wasn't null.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class MyConfig {
#Autowired
private MyBean myBean;
#Bean
public MyBean createMyBean() {
return new MyBean();
}
#Bean
public SomeOtherBean createSomeOtherBean() {
return new SomeOtherBean(this.myBean);
}
}
3.4.1.3 Dependency resolution process says,
You can generally trust Spring to do the right thing. It detects configuration problems, such as references to non-existent beans and circular dependencies, at container load-time. Spring sets properties and resolves dependencies as late as possible, when the bean is actually created. This means that a Spring container which has loaded correctly can later generate an exception when you request an object if there is a problem creating that object or one of its dependencies.
I'm not sure how this applies to my code. Can someone help me understand this better?
Thanks in advance.
I am studying for the Spring Core certification and I have the followind doubt with an exercice related to the beans configuration using the Java configuration way.
So I have the following RewardsConfig class that configure my beans (this class is into the application folder src/main/java):
package config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import rewards.RewardNetwork;
import rewards.internal.RewardNetworkImpl;
import rewards.internal.account.AccountRepository;
import rewards.internal.account.JdbcAccountRepository;
import rewards.internal.restaurant.JdbcRestaurantRepository;
import rewards.internal.restaurant.RestaurantRepository;
import rewards.internal.reward.JdbcRewardRepository;
import rewards.internal.reward.RewardRepository;
#Configuration
public class RewardsConfig {
#Autowired
DataSource dataSource;
#Bean
public RewardNetwork rewardNetwork(){
return new RewardNetworkImpl(accountRepository(), restaurantRepository(), rewardRepository());
}
#Bean
public AccountRepository accountRepository(){
JdbcAccountRepository repository = new JdbcAccountRepository();
repository.setDataSource(dataSource);
return repository;
}
#Bean
public RestaurantRepository restaurantRepository(){
JdbcRestaurantRepository repository = new JdbcRestaurantRepository();
repository.setDataSource(dataSource);
return repository;
}
#Bean
public RewardRepository rewardRepository(){
JdbcRewardRepository repository = new JdbcRewardRepository();
repository.setDataSource(dataSource);
return repository;
}
}
As you can see I declare 4 methods that are used to create 4 beans and that specify the dependency that occurs among these beans.
So I have a RewardNetwork bean that is implemented by RewardNetworkImpl class that depends from the following 3 beans: AccountRepository, RestaurantRepository and RewardRepository.
Is it the correct interpretation of the Java configuration is Spring?
Can I say for example that RewardNetwork is the declared bean and that RewardNetworkImpl its the current implementation of this bean?
All the 3beans (AccountRepository, RestaurantRepository and RewardRepository) depends by another bean dataSource that, as you can see in the previous code snippet, is declared as #Autowired:
#Autowired
DataSource dataSource;
This bean is not declared in this configuration class because it changes according to the environment (test, developt, production).
So, in my case it is declared into the unit test folder src/test/java:
package rewards;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
#Configuration
public class TestInfrastructureConfig {
/**
* Creates an in-memory "rewards" database populated
* with test data for fast testing
*/
#Bean
public DataSource dataSource(){
return
(new EmbeddedDatabaseBuilder())
.addScript("classpath:rewards/testdb/schema.sql")
.addScript("classpath:rewards/testdb/test-data.sql")
.build();
}
}
So the dataSource bean define a datasource that is valid only for the test environment (used when I perform a unit test).
Now my doubt is: I have 2 different configuration classes and the dataSource bean is not definied into the RewardsConfig configuration class that contains the 3 beans that use it. Why I can't not use the #Import annotation to use it into RewardsConfig?
Something like it:
#Import(TestInfrastructureConfig.class)
How it work exactly?
Tnx
You don't have to import beans to make them available for autowiring. #Import is used to add extra configuration classes.
You really don't want to hard-import a test configuration class, because then your production code is referring to test-only code (and, in this case, always activating it). Instead, think of your configuration class more like an abstract class: declare autowired beans, but don't worry about how they get there. The downstream (runtime) configuration will supply them, and you don't need to know how. Maybe you're supplying an in-memory H2 for testing and using Spring Cloud Connectors for actual runs, doesn't matter.