Autowired Environment is null in #Configuration-annotated classes - spring

In this #Configuration-annotated class, the #Autowired Environment class is always null.
The code-sample below is taken directly from:
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/PropertySource.html
#Configuration
#PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {
#Autowired
Environment env;
#Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
// some futher contitional stuff/checks etc. on the properties
String someProp = env.getProperty(...);
if(someProp.equals(...)) {
...
}
return testBean;
}
}
If I make the class implement EnvironmentAware the Environment is set correctly (and my code works).
#Configuration
#PropertySource("classpath:/com/myco/app.properties")
public class AppConfig implements EnvironmentAware {
Environment env;
#Bean
public TestBean testBean() {
// ...
}
#Override
public void setEnvironment(final Environment environment) {
this.environment = environment;
}
}
Any thoughts why the #Autowired approach does not work in #Configuration-annotated classes as expected, since autowiring the Environment in other beans works.

I think you must add #Bean annotation to Environment class, because if You want #Autowired class who is not signed as #Bean then it is impossible

Try injecting values directly:
#Configuration
#PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {
#Value("${testbean.name}")
private String testbeanName;
#Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(testbeanName);
return testBean;
}
}

Related

How to use #TestConfiguration

How to override #Configuation which is present under src/main/java with #TestConfiguration during unit tests?
#Configuration
public class AppConfig {
#Bean
public EmployeeService employeeService(){
return new EmployeeService();
}
}
#Component
public class ServerStartSetup implements CommandLineRunner {
#Autowired
private EmployeeService employeeService;
public void run(String... args) {
// do something with employee service
}
}
I would like to override the above bean with some below custom bean for testing purposes.
#TestConfiguration
public class TestAppConfig {
#Bean
public EmployeeService employeeService(){
return new FakeEmployeeService();
}
}
#SpringBootTest
#Import(TestAppConfig.class)
public class UnitTest {
}
However AppConfig does not seem to be skipped. That is , it throws an error saying that there is a bean with same name employeeService. If I rename bean method name in the TestAppConfig, it injects the bean created via AppConfig.
How to fix this.?
Note: One possible solution is using #Profile. I am looking for anything other than using Profiles.
I tested locally and found that changing the method name or #Bean to #Bean("fakeEmployeeService") and adding the #Primary annotation works.
#SpringBootTest
class DemoApplicationTests {
#Autowired
private EmployeeService employeeService;
#TestConfiguration
static class TestConfig {
//#Bean("fakeEmployeeService")
#Bean
#Primary
public EmployeeService employeeServiceTest() {
return new EmployeeService() {
#Override
public void doSomething() {
System.out.println("Do something from test...");
}
};
}
}
...
}
If we want to override a bean definition in #TestConfiguration, we need:
To use the same name as the overridden bean. (Otherwise it would be an "additional" bean and we could get conflict/'d have to qualify/primary)
Since spring-boot:2.1: spring.main.allow-bean-definition-overriding=true (set this in tests ONLY!plz!)
#ref
Then, with:
#TestConfiguration
public class TestAppConfig {
#Bean // when same name, no #Primary needed
public EmployeeService employeeService(){ // same name as main bean!
return new FakeEmployeeService();
}
}
We can do that:
#Import(TestAppConfig.class)
#SpringBootTest(properties = "spring.main.allow-bean-definition-overriding=true")
public class UnitTest {
... // EmployeeService will be "fake", the rest is from "main config"
You can mock the AppConfig bean in your test like this:
#MockBean
private AppConfig config;
Or, like you said, just use profiles.

#Autowired Environment is always null

I am having a simple RestController:
#RestController
#PropertySource("classpath:application.properties")
public class Word2VecRestController {
private final static Logger LOGGER = Logger.getLogger(Word2VecRestController.class);
// #Resource is not working as well
#Autowired
Environment env;
// This is working for some reason
// but it's null inside the constructor
#Value("${test}")
String test;
public Word2VecRestController() {
LOGGER.info(env.getProperty("test"));
System.out.println("");
}
#GetMapping("/dl4j/getWordVector")
public ResponseEntity<List<Double[]>> getWordVector(String word) {
return null;
}
}
The problem is, that env is always null. I've seen somewhere that I could try to use #Resource instead of #Autowired but that didn't help.
application.properties:
test=helloworld
I've tried to use
#Value("${test}")
String test;
but the problem here is that these are null during construction of the object where I need it.
Field injection is done by Spring after the constructor is called. This is why Environment is null in the Word2VecRestController constructor. You can try constructor injection if you need it in the constructor:
#RestController
#PropertySource("classpath:application.properties")
public class Word2VecRestController {
private final static Logger LOGGER = Logger.getLogger(Word2VecRestController.class);
#Autowired
public Word2VecRestController(Environment env, #Value("${test}") String test) {
LOGGER.info(env.getProperty("test"));
System.out.println("");
}
#GetMapping("/dl4j/getWordVector")
public ResponseEntity<List<Double[]>> getWordVector(String word) {
return null;
}
}
PS: if you use Spring Boot, you do not need the #PropertySource("classpath:application.properties"), this is automatically done for you.
Add
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
to enable the PropertySourcesPlaceholderConfigurer to your configuration. Important this must been a static method!
For example:
#Configuration
#PropertySource("classpath:application.properties")
public class SpringConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}

MethodValidationPostProcessor breaks #Transactional

I have a Controller which calls a Service which has #Transactional annotation.
But when I declare a bean MethodValidationPostProcessor, no transaction is created (could not initialize proxy - no Session).
#EnableWebMvc
#ComponentScan(basePackages = {"my"})
public class Application extends WebMvcConfigurerAdapter {
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
Controller bean:
#RestController
#RequestMapping(path = "/my", produces = APPLICATION_JSON_VALUE)
public class MyController {
#Autowired
private TransactionalService transactionalService;
#RequestMapping(method = POST)
public void post(#SafeHtml #RequestBody String hey) {
transactionalService.doStuff(hey);
}
}
Service bean:
#Service
public class TransactionalService {
#PersistenceContext
private EntityManager entityManager;
#Transactional
public void doStuff(String hey) {
Item h = entityManager.find(Item.class, hey);
h.getParent(); // could not initialize proxy - no Session
}
}
I'd like to understand why #Transactional doesn't work when I declare MethodValidationPostProcessor. Thanks !
Note: If I add #Transactional on my Controller, it works. But it's not what I want to do.
Thanks to #Kakawait, I got a work-around: declaring my bean MethodValidationPostProcessor. Needs to be static so that #Transactional still work properly.
/**
* This bean must be static, to be instantiated before the other MethodValidationPostProcessors.
* Otherwise, some are not instantiated.
*/
#Bean
public static MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}

How to use annotation and avoid xml configuration in spring framework

I have designed a packing structure.
Controller
Delegates (which is helper class) - this class do all the business and return the value to Controllers.
Service
Service Implementation
DAO
DAO Implementation.
I want to implement autowired (Annotation) concept and would like to avoid xml configuration such as service and DAO configuration on spring-bean.xml.
This code is not working if I want to avoid xml configuration.
I have done those changes
bean id :loginDelegate, userService, userDao
added the #Service & #Repository annotation to the corresponding service & DAO implementation.
#Controller("loginController")
public class LoginController {
#Autowired
private LoginDelegate loginDelegate;
public LoginDelegate getLoginDelegate() {
return this.loginDelegate;
}
public void setLoginDelegate(LoginDelegate tLoginDelegate) {
this.loginDelegate = tLoginDelegate;
}
#RequestMapping(value="/login.do",method=RequestMethod.GET)
public ModelAndView displayLogin(HttpServletRequest request, HttpServletResponse response) {
log.info("<---displayLogin()--->");
ModelAndView model = new ModelAndView("login");
LoginBean loginBean = new LoginBean();
model.addObject("loginBean", loginBean);
return model;
}
}
public class LoginDelegate {
#Autowired
private IUserService userService;
public IUserService getUserService() {
return this.userService;
}
public void setUserService(IUserService userService) {
this.userService = userService;
}
public boolean isValidUser(String username, String password) throws Exception {
return userService.isValidUser(username, password);
}
}
public interface IUserService {
public boolean isValidUser(UserBean userObj);
public int addUsers(UserBean userObj);
}
public class UserServiceImpl implements IUserService {
#Autowired
private IUserDao userDao;
public IUserDao getUserDao() {
return this.userDao;
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
public boolean isValidUser(UserBean userObj) {
return userDao.isExistUser(userObj);
}
#Override
public int addUser(final UserBean userObj) {
return userDao.saveUserDetails(userObj);
}
}
public interface IUserDao {
public boolean isExistUser(UserBean userObj);
public int saveUserDetails(UserBean userObj);
}
public class UserDaoImpl implements IUserDao {
#Autowired
UserBean userObj;
#Autowired
DataSource dataSource ;
public DataSource getDataSource(){
return this.dataSource;
}
public void setDataSource(DataSource dataSource){
this.dataSource = dataSource;
}
Use Java-based configuration if you want to completely get rid of XML-based configuration
#Configuration
#ComponentScan(basePackages = "com.acme")
public class AppConfig {
...
}
The above normal Java class when annotated with #Configuration, makes it a 'Spring Configuration class' (analogous to XML-based configuration).
#ComponentScan annotation scans for classes annotated with #Component, #Controller, #Service, #Repository classes from the package defined during start-up time to get them registered as Spring beans. This can be done in XML also with <context:component-scan base-package="com.acme" />
Refer:http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/beans.html#beans-java-instantiating-container-scan

Spring Java Configuration: overridden #Bean method invoked before autowiring

I have RepositoryConfig extending Neo4jConfiguration. The latter sets up a number of beans with #Bean annotated methods. RepositoryConfigoverrides getGraphDatabaseService which is invoked before any fields in RepositoryConfig are autowired. That is a problem since I want to use the autowired stuff inside the getGraphDatabaseServicemethod.
#ConfigurationProperties(prefix = "neo4j")
public class RepositoryProperties {
[...]
}
#Configuration
#EnableNeo4jRepositories("com.foo.bar")
#EnableConfigurationProperties(RepositoryProperties.class)
public class RepositoryConfig extends Neo4jConfiguration {
#Autowired
private RepositoryProperties properties;
#Override
#Bean(name = "graphDatabaseService", destroyMethod = "shutdown")
public GraphDatabaseService getGraphDatabaseService() {
[...] // properties is 'null' at this point
}
#PostContstruct
public void foo() {
[...] // properties is initiated OK here
}
}
Why is getGraphDatabaseServicebeing called before autowiring is complete? I guess it has to do with the inheritance... If I remove the inheritance then autowiring is complete at the time getGraphDatabaseServiceis called. I've also tried annotating the method with #DependsOn, with no luck.
Any ideas is much appreciated!
Yes, I have seen this too occasionally. I think there are two workarounds.
Option 1. Autowire the bean definition
#Override
#Bean(name = "graphDatabaseService", destroyMethod = "shutdown")
#Autowired
public GraphDatabaseService getGraphDatabaseService() {
[...] // properties is 'null' at this point
}
Option 2. Inject the bean
#Override
#Bean(name = "graphDatabaseService", destroyMethod = "shutdown")
public GraphDatabaseService getGraphDatabaseService(#Autowired RepositoryProperties properties) {
// can probably delete the Config member with this approach
[...] // properties is 'null' at this point
}

Resources