Is it possible to use Spring 3 #Autowired annotation inside #Service? - java

I'm using class that is not called by my #Controller directly and when I try to use #Autowired propeprty in that class what is defined as #Service, property is null. But #Autowired with same markup will work inside #Controller.
Example code:
#Service
public class UsernameValidator implements Validator {
#Autowired private UserDao userDao;
// code here when used, userDao is always null
}

This should work perfectly fine, if you have the following in your applicationContext.xml:
<context:component-scan base-package="com.yourproject" />

Related

Spring #Autowired not working in some classes

So i am using Spring to access my DB and fetch Users based on different Properties. With a #Restcontroller I get the Data. I created a UserRepository which extends the CrudRepository.
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Integer> {
Iterable<User> findByNachname(String nachname);
Iterable<User> findByRolle(Rolle rolle);
Optional<User> findByBenutzername(String benutzername);
#Transactional
String deleteByBenutzername(String benutzername);
}
I use #Autowire to get an Instance of the UserRepo in my Controller-class
#RestController
public class LoginController {
#Autowired
private UserRepository userRepository;
}
This works perfectly fine in all Controllers i have.
But now when i try the same in another class the userRepository Instance is null.
public class Authentificator {
#Autowired
private UserRepository userRepository;
}
The Authentificator and the LoginController are not in the same package. But both of them are not in the same package as the UserRepo.
project
UserRepo-package
Controller-Package
Authentificator-Package
you must make sure Authentificator is also a spring bean - I mean you must annotate it with something like #Component or #Service. After this step you’ll also have to “get” the Authentificator instance from spring instead of instantiating it with the new keyword.
#Autowired does work only with the spring context. This means that it will work only with class instances which are managed by Spring. Your Authentificator class is managed by you and Spring does not have to take care or know about it, it's not important for the Java Framework.
This is more of a configuration issue rather than an annotation issue.
If you want Spring to inject a field in Authenticator object the dependent object must be also created by Spring. You can do it by marking this class as a #Component or by creating a method with Authenticator return type marked with #Beanannotation. Then it must be injected somewhere.

ConflictingBeanDefinitionException : Same class name, different package

I have a dao in one package:
package com.mypackage.dao;
#Repository
public class MyDao {
// some code here
}
I have another dao with same class name in a sub package:
package com.mypackage.one.dao;
#Repository
public class MyDao {
// some other code here
}
I have third class where I am trying to inject the bean using autowiring:
import com.mypackage.one.dao;
public class TestClass{
#Autowired
private MyDao myDao;
}
On deployment, I get the following error:
Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'myDao' for bean class [com.mypackage.dao.MyDao] conflicts with existing, non-compatible bean definition of same name and class [com.mypackage.one.dao.MyDao]
My applicationContext.xml has:
<context:component-scan base-package="com.mypackage.dao"/>
<context:component-scan base-package="com.mypackage.one.dao"/>
I can not rename the classes as its a legacy application.
What is the solution for this ?
I tried using qualifier, but that is not working.
Added below line:
<bean id="oneMyDao" class="com.mypackage.one.dao.MyDao" />
And changed autowiring to:
#Autowired
#Qualifier("oneMyDao")
private MyDao myDao;
But it still throws the same error.
i think your mixing XML and Java bean configuration for same bean.
your code should be something like this
package com.mypackage.dao;
#Repository
#Qualifier("myDAOBasePackage")
public class MyDao
{
// some code here
}
package com.mypackage.one.dao;
#Repository
#Qualifier("myDAOSubPackage")
public class MyDao {
// some other code here
}
Ues this to inject
#Autowired
#Qualifier("myDAOBasePackage")
private MyDao myDao;
I think that the problem is in definition of beans. You have to give your beans different names.
Please, try to change annotations to #Repository("dao1") for the first dao and to #Repository("dao2") for the second dao. And then try to #Autowire bean using #Qualifier("dao1") or #Qualifier("dao2").
Also you should remove this line
<bean id="oneMyDao" class="com.mypackage.one.dao.MyDao" />
if you use #Repository annotation

How to Autowire a Spring-annotated service class in a #Configuration class?

I'm trying to inject a service-annotated class into a configuration class in a Spring Boot application, but it doesn't get injected (is set to null), which I assume is due to the Spring lifeycle.
Also, this service has an overloaded constructor that uses constructor injection, and I guess this is also a problem, as autowiring acts upon a default constructor. However, the service needs to be Spring-configured, so I don't think one can create a new instance in a Bean annotated method.
How can one solve this?
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private SessionService sessionService;
#Bean
public SessionService sessionService() {
return sessionService;
}
}
public interface SessionService extends BaseCacheService<Session> {
void extendExpiration(String key);
String getSessionId(String key);
}
#Service
public class SessionServiceImpl implements SessionService {
private Environment environment;
private UserService userService;
#Autowired
public SessionServiceImpl(Environment environment, UserService userService) {
this.environment = environment;
this.userService = userService;
}
}
If I exclude the #Bean method, then I get a compilation error:
Your error is the following (you are returning a null value):
#Bean
public SessionService sessionService() {
return sessionService;
}
Solution
Since your SessionServiceImpl is annotated with #Service, you can just remove the #Bean method and let spring create it. Spring already makes it available for you.
Or, If your SessionServiceImpl wasn't annotated with #Service, you would need the following :
#Bean
public SessionService sessionService() {
return new SessionService();
}
If this doesn't work, it may just be that your SessionServiceImpl is in a package not being scanned by spring (as suggested by #Miloš Milivojević)
You may add #ComponentScan to your Configuration class
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#ComponentScan("com.package.to.sessionServiceImpl-or-higher")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
Expanding on #Alex's answer, when you annotate a method with #Bean, it tells Spring that this method will produce that type. So, you essentially told Spring to give you the null reference you already had for all Beans of type SessionService.
If you are using Annotation-based context configuration, you can Autowire any #Component Bean (not just #Service) that can be constructed without runtime parameters (e.g. has a default constructor or an Autowired Constructor). If you need to do something to create the bean (e.g. runtime configuration required), you would either create a method as #Alex suggested, or you can use getBean and pass in the Type and Constructor arguments. The former is generally preferred.
I was facing similar issue while writing an integration test class for a spring boot application. RestTemplate class and CounterService of metrics API are autowired in my service class. I could use #ContextConfiguration(Classes={RestTemplate.class}) for injecting RestTemplate to my service, but adding CounterService.class to above annotation does not help, maybe because CounterService is an interface not a concrete class, Hence I was getting "No bean of type CounterService found" issue.
Thanks to answer by Milos, I included #EnableAutoConfiguration to my integration test class, issue was resolved!
If Alex's answer does not work (removing the #Bean method), you're probably not using #EnableAutoConfiguration or your Application is not in the root-hierarchy package so it's not scanning the whole classpath. Try adding #ComponentScan("service.class.package") to your configuration (in addition to removing the sessionService method) and see if it helps.

Spring injected resource is always null

ISSUE:
I am trying to inject a service into a bean but the service instance is always null.
BACKGROUND:
I have two beans one called from the other. This is how they are defined in XML config:
<context:annotation-config />
<bean class="com.test.MyBeanImpl" name="myBean"/>
<bean id="myService" class="com.test.MyServiceImpl" />
and the beans are implemented like so:
MyServiceImpl.java
class MyServiceImpl implements MyService {
public void getString() {
return "Hello World";
}
}
MyBeanImpl.java
#Component
class MyBeanImpl implements MyBean, SomeOtherBean1, SomeOtherBean2 {
#Resource(name="myBean")
private MyService myService;
public MyBeanImpl() {}
}
QUESTIONS:
Is there some reason related to the fact that my bean implements 3 interfaces that is preventing the Service being injected? If not what other factors could be effecting it?
as you are using annotations Just mark your service class with #Service annotation and use #Autowired annotation to get the instance of your service class
MyServiceImpl.java
package com.mypackage.service;
#Service
class MyServiceImpl implements MyService {
public void getString() {
return "Hello World";
}
}
MyBeanImpl.java
#Component
class MyBeanImpl implements MyBean, SomeOtherBean1, SomeOtherBean2 {
#Autowired
private MyService myService;
public MyBeanImpl() {}
}
also make sure you mention your package name in <context:component-scan /> element in your dispatcher file as
<context:annotation-config />
<context:component-scan base-package="com.mypackage" />
hope this will solve your problem
Make sure the bean you are injecting MyService into is a bean.
/* This must be a bean, either use #Component or place in configuration file */
#Component
public class SomeClass{
#Resource
private MyService myService;
}
Also make sure that within your configuration you have specified that the application uses annotation-based configuration using:
<context:annotation-config/>
Since your using multiple interfaces it may be best to qualify the bean with a name:
<bean class="com.test.MyBeanImpl" name="myBean" />
Then specify the name element on the #Resource annotation
#Resource(name="myBean")
private MyService myService;
Here is a Github Gist that explains these concepts.

Spring bean autowire for testing

I have many spring services with this autowire:
#Autowired
private SmartCardService smartCardService;
I need a dummy class for testing and I defined this class extending the original:
#Service
public class DummySmartCardService extends SmartCardService{
...
}
How can I be sure that all autowire will take the dummy instead of original service without changing all Autowired annotation?
Thanks.
Consider using the #Primary annotation. See here
Load your DummySmartCardService bean from a test version of your application context file instead so that no changes to the code under test are necessary
#ContextConfiguration(locations = {"classpath:test-services.xml"})
Use the #Resource annotation or a #Qualifier, With #Qualifier which discriminates bean types:
#Autowired
#Qualifier("testing")
private SmartCardService smartCardService;
#Service
#Qualifier("testing")
public class DummySmartCardService extends SmartCardService{
...
}
Or with #Resource which uses by-name semantics:
#Resource("dummySmartCardService")
private SmartCardService smartCardService;
#Service("dummySmartCardService")
public class DummySmartCardService extends SmartCardService{
...
}
Theoretically you could use #Qualifier("beanName") but it is discouraged.
But it think would be better if you had a Spring profile to load only test related stubs in your tests:
#Service
#Profile("test")
public class DummySmartCardService extends SmartCardService{
...
}
#ContextConfiguration(locations = {"classpath:services.xml"})
#ActiveProfiles("test")
public class TestSuite{
#Autowired
private SmartCardService smartCardService;
}
IMHO you should take a look at Springockio for proper and rather easy mocking of Spring beans.
You can replace your bean with a mock or wrap with a Spy this way:
#ContextConfiguration(loader = SpringockitoContextLoader.class,
locations = "classpath:/context.xml")
public class SpringockitoAnnotationsMocksIntegrationTest extends
AbstractJUnit4SpringContextTests {
#ReplaceWithMock
#Autowired
private InnerBean innerBean;
#WrapWithSpy
#Autowired
private AnotherInnerBean anotherInnerBean;
....
}
This not only is a clean way (you do not need to change the code being tested by adding qualifiers or profiles) but also allows you to use the capabilities of Mockito for mocking, verifying and spying which is great.

Categories