Say I need to rely on several implementations of a Spring bean. I have one AccountService interface and two implementations: DefaultAccountServiceImpl and SpecializedAccountServiceImpl.
How is this possible (injecting one or the other implementation) in Spring?
Which implementation will the following injection use?
#Autowired
private AccountService accountService;
Ad. 1: you can use #Qualifier annotation or autowire using #Resource as opposed to #Autowired which defaults to field name rather than type.
Ad. 2: It will fail at runtime saying that two beans are implementing this interface. If one of your beans is additionally annotated with #Primary, it will be preferred when autowiring by type.
#Autowired
#Qualifier("impl1")
BaseInterface impl1;
#Autowired
#Qualifier("impl2")
BaseInterface impl2;
#Component(value="impl1")
public class Implementation1 implements BaseInterface {
}
#Component(value = "impl2")
public class Implementation2 implements BaseInterface {
}
For full code: https://github.com/rsingla/springautowire/
Related
I have a classA which implements an interfaceA, with a methodA, then I have a classB in which I call classA with an #Autowired to be able to use methodA, but it gives me a warning that I must create a method for classA. Why is this happening? Doesn't #Autowired work like this in this case? Should I just instantiate classA? Thank you very much for your answers.
ClassA
#RequiredArgsConstructor
public class RepositoryImpl implements IRepository {
#Autowired
private final TransactionDataMapper transactionDataMapper;
#Autowired
private SpringDataColminvoice springDataColminvoice;
#Override
public <S extends TransactionDto> S save(S s) {
Colm colm = transactionDataMapper.toEntity(s);
//methodA
springDataColminvoice.save(colm);
return null;
}
}
InterfaceA
public interface IRepository extends IRepository<TransactionDto, Integer> {}
ClassB
#Service
#RequiredArgsConstructor
public class ServiceImpl implements IInvoiceService {
#Autowired
private RepositoryImpl repositoryImpl;
#Override
public void save(CMessage cMessage) throws HandlerException {
try {
TransactionDto transactionDto = cMessage.getTransaction();
// methodA
repositoryImpl.save(transactionDto);
} catch (Exception e) {
throw new HandlerException(e.getMessage());
}
}
}
Exception
Action:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field RepositoryImpl in com.st.ms.yyu.d.binvoce.infraestructure.rest.spring.services.impl.InvoiceServiceImpl required a bean of type 'com.st.ms.yyu.d.binvoce.infraestructure.db.springdata.repository.impl.ServiceImpl' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.st.ms.yyu.d.binvoce.infraestructure.db.springdata.repository.impl.RepositoryImpl' in your configuration.
(posting this as an answer since I do not have enough reputation to comment)
As others have pointed out already, a code sample would help tremendously.
That being said, though, it sounds like you're missing implementation for "ClassA".
If you have an interface that "ClassA" implements, you have to implement the interface's methods in "ClassA" before you can use them.
I assume your code currently looks somewhat like this?
public interface InterfaceA {
void methodA();
}
public class ClassA implements InterfaceA {
}
public class ClassB {
#Autowired
ClassA classA; // Cannot use {#link InterfaceA#methodA} because the class does not implement the function
}
If this is your code, make sure you add an implementation for your "methodA()" function in "ClassA". Somewhat like so:
public class ClassA implements InterfaceA {
#Override
public void methodA() {
}
}
Additionally, in order to autowire in Spring (Boot), you need to ensure that the class you'd like to autowire is marked as such. You can autowire beans.
To make "ClassA" in the example eligible for autowiring, make sure to instantiate it either as:
A bean (using the #Bean annotation).
A component (using the #Component annotation).
A service (using the #Service annotation).
Any of the other annotations that may match your use case the best.
In our example, this would look somewhat like this:
#Component // Or #Service / whatever you may need
public class ClassA implements InterfaceA {
#Override
public void methodA() {
}
}
Hope you've found any of this helpful. All the best!
-T
As what I have understood, #Autowire means injecting the value/instance of the specific property where you put the annotation #Autowire. In this case, #Autowire only happens when there is defined/created Bean within your basePackage of your Spring Boot project that can match it, i.e. where your #Autowire referred to (meaning there is no conflict issue like ambiguity, etc. and the DataType(Class) can be implicitly casted). In your example, first you treat the IRepository and/or RepositoryImpl as Repository without using the #Repository annotation to inform the Spring Boot default configuration that this is a Repository bean. As you didn't put the POM.xml or posted the related code, I presumed you are creating your own repository class. I think it's much better to post your dependencies here.
But as what others pointed out. You need to create a bean that can match the #Autowired you've put on TransactDataManager & SpringDataColminvoice. You need also to inform the Spring Boot or register it that your class A is a Bean by annotating
#Bean - defining a regular bean,
#Component - a Component in the Project,
#Service - a Service in the Project,
#Repository - a Repository (if you're using Spring JPA), etc.
#<Other Annotations depending of what other Spring Project/Dependencies your using>
Since newer versions of Spring is moving to annotation based from XML mapping, we need to put proper annotation for each class/object that we want to be auto injected/instantiated from #Autowired using the above sample annotations depending on the role/purpose of your class/object is.
I suggest if you're not sure. Then create a typical bean using common annotation #Bean. So your class A might be
#Component //Insert proper Annotation for your class if necessary. This is just a sample
#RequiredArgsConstructor
public class RepositoryImpl implements IRepository {
#Autowired
private final TransactionDataMapper transactionDataMapper;
#Autowired
private SpringDataColminvoice
springDataColminvoice;//segunda
#Override
public <S extends TransactionDto> S save(S s) {
//Some implementation
}
#Bean
private TransactionDataMapper getTransactionDataMapper(<Some parameters if needed>){
return <an instance for TransactionDataManager>;
}
#Bean
private SpringDataColminvoice getSpringDataColmInvoice(<Some parameters if needed>){
return <an instance for SpringDataColminvoice>;
}
}
Note that 2 beans definition are optional if there are already a Beans define on outside class or if it was marked by other annotation like #Service, #Component or other proper annotations and the other one bean is just a reference parameter for the other bean in order to properly instantiated.
In your class B is the following:
public class ClassB {
#Autowired
ClassA classA;
/*Note: ignore this Bean definition if Class A is annotated with #Component,
#Service, or other proper #Annotation for Class A.
*/
#Bean
private ClassA getClassA(<Some Parameters if Needed>){
return <Instance of Class A>
}
}
Take note that, you don't need to put a Bean definition inside the Class B if you put a proper annotation for your Class A like #Component, #Service, etc.
Suppose I have several components that depend on one service:
public interface MyService { ... }
// in package1
#Component
public class Package1Component1 {
#Autowired
private final MyService myService;
}
public class Package1Component2 {
#Autowired
private final MyService myService;
}
// in package 2
public class Package2Component1 {
#Autowired
private final MyService myService;
}
public class Package2Component2 {
#Autowired
private final MyService myService;
}
And I have two implementations of MyService:
#Service
public class MyServiceImpl1 implements MyService { ... }
#Service
public class MyServiceImpl2 implements MyService { ... }
And I want MyServiceImpl2 to be injected into all components in package2 and MyServiceImpl1 everywhere else
I don't want to use #Qualifier to resolve ambiguity as it will require to always specify it when you need to inject MyService and to change a lot of files when I need to switch to single implementation everywhere (MyServiceImpl2 is temporary implementation that should be used only in specific scope).
Is there any way to specify bean for scope (java package?), like in Angular I can override module providers (AuthService in this case):
#NgModule({
declarations: [LoginComponent, UserInfoComponent],
providers: [
{
provide: AuthService,
useClass: FacebookAuthService,
},
],
})
export class AuthModule {}
You can introduce your meta-annotation annotated with #Qualifier and use it.
Once you are ready to change, just change Qualifier on your meta annotation.
I think it's not really correct to co-relate Angular specificities with Spring, as they are simply two radically different infrastructures, in all aspects.
Why don't you want to use #Qualifier? for what reason? because, the problem you describe is exactly why people came up with #Qualifier implementation.
I don't want to use #Qualifier to resolve ambiguity as it will require to always specify it when you need to inject MyService and to change a lot of files when I need to switch to single implementation everywhere.
Not really. You can provide ID for your bean definition, and disregarding of what implementation you'll use later, same bean, with that same ID, will be injected wherever you'll qualify it to be injected. You will only swap the implementation class.
Also, package in Java, is not a scope for Beans. Package is facility for grouping a logically similar classes, and it can be considered as a scope, but for class and its members' accessibility/visibility, not for the beans.
Bean scopes have a different semantics, and you can read about them here.
The is another way to specify, that the bean should qualify as a candidate, if there are more than one implementations of a type you're injecting. It's #Primary; however, this #Primary will always override any other candidates, while with #Qualifier you can leverage more fine-grained control on what to inject where.
I'm not so familiar with Spring and I have the following situation:
A repository class:
#Repository
public class MyRepository {
// ...
}
A class that uses the repository class:
public class MyClass extends AbstractClass {
#Autowired
private MyRepository myRepository;
//...
}
I know that if I annotate my MyClass with #Component and use it with an #Autowired, then the #Autowired MyRepository is resolved just fine.
Problem is I am in a situation that I need to create new instances of MyClass with reflection. So MyRepository is never resolved and is null all the time.
Is there a way to use #Autowired in this situation?
Explaining better my situation:
I have some implementations of AbstractClass.
In a setup phase of my application I create a HashMap of these implementations. Basically:
{"MyClass", MyClass.class}
//...
Then I have a generic Controller that maps to the url /{class}?options=...
Using the {class} #PathVariable, the HashMap above and reflection I am able to create a instance of a class based on the given options (this part is important). Do you guys think there's a better way of doing this?
Thanks in advance
Spring itself offers some functionality for doing auto-wiring in your objects
which you created by new or newInstance() or whatever.
To use it you need an AutowireCapableBeanFactory
which you get by Spring's normal dependency injection with #Autowired.
#Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
Then you use its autowireBean(Object) method
to inject the #Autowired properties into your bean.
Object myBean = map.get(className).newInstance();
autowireCapableBeanFactory.autowireBean(myBean);
Design note:
Think well if you really need the approach above.
The javadoc of AutowireCapableBeanFactory advises against using this interface for most use-cases:
This subinterface of BeanFactory is not meant to be used in normal application code: stick to BeanFactory or ListableBeanFactory for typical use cases.
Integration code for other frameworks can leverage this interface to wire and populate existing bean instances that Spring does not control the lifecycle of. This is particularly useful for WebWork Actions and Tapestry Page objects, for example.
You can use Factory Design Pattern over here.
This might seem a little complicated in start but I am sure you will love it after you have implemented it.
Steps:
Add #Component on all implementations of AbstractClass.
Create a factory class as:
#Component
public class MyFactory {
private final Map<String, AbstractClass> impletationMap = new HashMap<>();
#Autowired
ApplicationContext context;
#PostConstruct
public void initialize() {
populateDataMapperMap(context.getBeansOfType(AbstractClass.class).values().iterator());
}
private void populateDataMapperMap(final Iterator<AbstractClass> classIterator) {
while (classIterator.hasNext()) {
AbstractClass abstractClassImpl = (AbstractClass) classIterator.next();
impletationMap.put(abstractClassImpl.getClass().getName(), abstractClassImpl);
}
}
}
When the Bean of this MyFactory class is initialized, then it will lookup for all beans of type AbstractClass and put them in the HashMap(implementationMap).
Now from this factory you can get the HashMap and then get the implementations as and when you require. It will be very easy when you add new implementation of AbstractClass as factory will take care of it.
One work around is instead of binding the MyClass to the Hashmap to bind a Factory class. MyClassFactory. This way you will delegate the construction to a concrete factory that will do the job to instantiate the correct class and initialize the correct repository.
Here is an example:
{"MyClass", MyClassFactory.class}
The factory can be Component as well, then you need to bind the hashmap to the factory instance instead of the factory class. But lets say it is not a component:
//#Component this is optional
public MyClassFactory {
//#Autowired optional
ApplicationContext ctx;
public MyClass createInstance() {
MyRepository repo = ctx.getBean("")
MyClass myclass = new MyClass(repo)
return myclass;
}
}
If you mark it as component you can well also use ApplicationContextAware interface if you are going to autowire the ApplicationContext.
One approach is to declare #Component on top of MyClass.
Then, in the setup phase, you can pass the instance of MyClass instead of MyClass.class itself, in the HashMap. There won't be any need to create instances via reflection.
Note: You can fetch the instance of MyClass from your ApplicationContext in the setup phase.
Try this
#Component
public class SomeClass extends AbstractClass {
private static ApplicationContext applicationContext;
public MyClass getMyClass(){
// Now #Autowired MyRepository will work
return applicationContext.getBean(MyClass.class);
}
}
Yes, you can annotate all your AbstractClass implementation beans with #Component and use the next declaration
#Autowired
private List<AbstractClass> beans;
You can then convert that to a Map in a #PostConstruct method.
Spring won't complain about duplicate definitions if you autowire Lists.
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.
My controller contains the following annotation :
#Resource(name="userService")
private UserDetailsServiceImpl userService;
and the service itself has the following :
#Service("userService")
#Transactional
public class UserDetailsServiceImpl implements UserDetailsService {
#Resource(name = "sessionFactory")
private SessionFactory sessionFactory;
However I receive the following error on startup :
Injection of resource dependencies
failed; nested exception is
org.springframework.beans.factory.BeanNotOfRequiredTypeException:
Bean named 'userDetailsServiceImpl'
must be of type
[myapp.service.UserDetailsServiceImpl], but was actually of
type [$Proxy19]
It should be
#Resource(name="userService")
private UserDetailsService userService;
Spring uses the interface type to make dependency injection, not the implementation type
Change to (interface instead of concrete class):
#Resource(name="userService")
private UserDetailsService userService;
And live happily ever after.
Long version: at runtime, by default, Spring replaces your class with something that implements all the interfaces of your class. If you inject interface rather than a concrete type, you don't care what is the exact type implementing this interface.
In your case adding #Transactional annotation causes your bean to be replaced by AOP proxy with transaction capabilities. If you remove this annotation, your code will run fine. However, it is a good idea to depend on interfaces, not on concrete implementations.