I've a problem with spring. I'm replacing the xml file based configuration of spring with annotation based configuration. Because of that I runned into the following problem. Theres is a class, where one field is configured by class based autowiring. Since yet, there has been only one candidate. But now there is more then one candidate, because I've added the #Named tag to mutliple classes of the same interface.
Here is a code example:
The class with the autowiring field:
public class AutowiringClass<X, Y> {
// This is the field which is autowired
private Autowired<X, Y> bean;
.....
}
Then there is a second class, which extends AutoWiringClass with specific generic arguments:
public class TestClass extends AutoWiringClass<ObjectX, ObjectY> {
.....
}
The Problem is, that spring doesn't know which class it should use, since there are more than once class of the type Autowiring but with different generic types (ObjectX, ObjectY). I thought, that the different generic types will do the thing.. but they doesn't :(
It would be awesome if anybody has an solution for that.
Qualifiers are what you are looking for. When you register a class as a Spring bean (using #Component or the like) you can pass a name as an argument. Then when you are autowiring a property, add a #Qualifier annotation with that bean's name. So:
#Component("Test1")
public class Test { }
#Component("Test2")
public class BetterTest extends Test {}
public class TestUser {
#Autowired
#Qualifier("Test1")
private Test test;
}
Generics won't help you due to type erasure, Spring can't do nothing about it. But you can either use #Primary annotation to denote the default implementation that should be always used or switch to autowiring by name rather than by type. Then Spring will use field name when in doubt.
Related
I am trying to instantiate a class passing a parameter by constructor drMessage, I am using the #RequiredArgsConstructor annotation, and some dependency injections using #Autowired as I show below, the problem is that when using the #RequiredArgsConstructor annotation it implements the default constructors internally, and I tried to build the constructors manually but the IDE tells me that the variable of those constructors has not been initialized, how could I solve it? Thanks
#RequiredArgsConstructor
#Service
public class ServiceImpl implements IService {
#Autowired
private final DtoMapper dtoMapper;
#Autowired
private final CDtoMapper cDtoMapper;
private DrMessage drMessage;
**other sentences**
}
Constructor Injection With Lombok
With Lombok, it's possible to generate a constructor for either all class's fields (with #AllArgsConstructor) or all final class's fields (with #RequiredArgsConstructor). Moreover, if you still need an empty constructor, you can append an additional #NoArgsConstructor annotation.
Let's create a third component, analogous to the previous two:
1.Example
#Component
#RequiredArgsConstructor
public class ThankingService {
private final Translator translator;
public String produce() {
return translator.translate("thank you");
}
}
The above annotation will cause Lombok to generate a constructor for us:
2.Example
#Component
public class ThankingService {
private final Translator translator;
public String thank() {
return translator.translate("thank you");
}
/* Generated by Lombok */
public ThankingService(Translator translator) {
this.translator = translator;
}
}
#Service annotated classes are Spring managed beans. You don't manually instantiate these classes. Spring does it for you.
These #Service annotated beans have default singleton scope. Which means this bean is only initialize once. So they are called stateless beans, or says they have a shared state. You do not crate a state or change the state of these kind of beans.
Note: Read this document about bean scopes.
In your ServiceImpl you only have two final state variables. Which means are the only required filed when ServiceImpl initialize, so only they will be included in #RequiredArgsConstructor.
Lombok works at compile time while Spring works at runtime.
So when you place a Lombok annotation of the constructor (#AllArgsConstructor, #RequiredArgsConstructor, etc) on your class (it can be a regular java class, spring bean, whatever), Lombok creates a constructor for you.
In this case, it will create a constructor for all final fields (see the documentation
As you see lombok doesn't take into consideration the #Autowired annotation,
Since you haven't placed #NonNull annotation on drMessage (check the documentation) it won't generate a constructor parameter for it, so your class will look like:
#RequiredArgsConstructor
#Service
public class ServiceImpl implements IService {
#Autowired
private final DtoMapper dtoMapper;
#Autowired
private final CDtoMapper cDtoMapper;
private DrMessage drMessage;
public ServiceImpl(DtoMapper dtoMapper, cDtoMapper cDtoMapper) {
this.dtoMapper = dtoMapper;
this.cDtoMapper = cDtoMapper;
}
**other sentences**
}
So if you want the lombok to generate a parameter for DrMessage make it final, or put a #NonNull annotation on it.
At this point the job of Lombok is done, in fact, you can exclude it from being available at runtime at all. Now regarding the spring part:
First of all, you say that you by yourself are trying to create the instance of ServiceImpl class, why? It's a spring bean (you've put a #Service annotation on it), so let Spring manage this class.
With this definition, placing #Autowired on the final field won't work in spring.
See this thread, so you should not place #Autowired on these fields.
Luckily Spring in its recent versions is smart enough to understand that if the class has a single constructor (in your case the one that you've generated with Lombok) spring will call it to create the instance of your class, so instead of field injection, you'll use constructor injection.
I have a postgres database which stores (as a String) the relevant class to use dependent on the information coming in from the user.
e.g. user has input Name, the database has the value NameFinder() stored against this and the code needs to create an instance of NameFinder().
I was wondering if there was a way of using reflection to instantiate this class as an #Autowired component, and then call the relevant function.
I can't seem to find a guide that uses #Autowired classes so any help would be appreciated.
For autowiring to work you need the class which uses #Autowired to be a #Component (or a child like #Service ...). https://www.baeldung.com/spring-autowire
For Spring to know what to inject, you need to define a #Bean in your Configuration
https://www.baeldung.com/spring-bean
As for the reflective instantiation in the bean:
#Bean
public Name getName(Database db) {
String nameFqn = db.getConfigTable().getNameFQN();
return (Name) Class.forName(nameFqn).getConstructor().newInstance();
}
Note this uses a no-arg public constructor. FQN means fully-qualified name, i.e. com.some.pkg.NameFinder
assuming:
package com.some.pkg;
class NameFinder implements Name {
public NameFinder(){}
}
I feel like a Spring Bean should be configurable also directly from a FQN without using reflection but I don't know how. Try reading up on a BeanFactory or something similar. Usually reflection is to be avoided.
I am trying to achieve the following Spring code using Android Annotations:
#Autowired
public initHandlerList(List<Handler> handlerList) {
// Do stuff with the list ...
}
I tried using both an interface and a class.
Bean definition:
#EBean
public AbstractHandler implements Handler {}
Trying to inject:
#Bean
public initHandlersList(List<AbstractHandler> handlersList) {
// Do stuff with the list ...
}
But always got the following error:
Error:(20, 5) error: org.androidannotations.annotations.Bean can only be used on an element annotated with #org.androidannotations.annotations.EBean
So I guess since the list itself is not annotated with #EBean it can't be used as a Bean... any way to implement this using Android Annotations?
Thanks !
Sorry I can't comment but my reputation is too low.
I read the wiki and under method based injection I saw how you inject the beans. What I can see in your code is that you are indeed creating a EBean with an AbstractHandler object however you are trying to inject a List object which has not been annotated with #EBean you can either delete the List<> and just use the AbstractHandler or you can extend a List implementation (Like ArrayList) and annotate it with #EBean.
#EBean
public class InjectableArrayList<T> extends ArrayList<T>{}
Hope this helps.
I am trying to inject specific Generic bean to Generic subtype, but Spring is unable to resolve dependency. By removing type from the bean, everything works as expected. Here is an example:
public class AbstractFrom{
// ...
}
public class EmployyForm extends AbstractFrom{
// ...
}
public class CompanyForm extends AbstractFrom{
// ...
}
abstract class AbstractBean<T extends AbstractFrom>{
public abstract void calculate(T form);
}
#Component
public CompanyBean extends AbstractBean<CompanyForm>{
public void calculate(CompanyForm form){
// specific impl
}
}
#Component
public EmployeeBean extends AbstractBean<EmployyForm>{
public void calculate(EmployyForm form){
// specific impl
}
}
Here is a target class:
#Service
public BaseService{
#Autowire
public AbstractBean<AbstractFrom> baseBean; // <- NoSuchBeanDefinitionException
// #Autowire
// public AbstractBean baseBean; <- Injection works as is expected
}
Depends of active profile is initialized only CompanyBean or EmployeeBean, never both. I've also tried set the same name given beans and us #Qualifier annotation.
Does exist any way how inject this bean using diamond syntax? Does Spring is able to resolve given dependency? Using Spring 4.2.x.
Edit:
With Spring 4.3 is should be possible. See Juergen Hoeller's talk
I know you are probably not going to like this, but why not separate out the EmployeeForm and the CompanyForm to 2 separate base forms, and then in the BaseService make TWO entires, for the Autowire.
This is not a Spring answer per se, but that is what I would do, as a quick work around to see if it would work.
Separating them is not a terrible design compromise.
I'm just learning spring, and something struck me as very odd about the annotation configurations using the name attribute as a string.
#Bean(name = "com.my.injected.Service")
public InjectedService injectedService() {
return injectedService;
}
Is this name similar to the Spring Bean XML configuration id and class attributes?
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
Why isn't this simply
#Bean(clazz = com.my.injected.Service.class)
public InjectedService injectedService() {
return injectedService;
}
instead?
You're fully qualifying the path in both cases and actually using the class makes it way easier for your IDE to tell you when you've screwed it up. I understand that the XML configuration came first, and naturally it was always looking up things by string, so is this just a holdover? Is there some advantage to using strings or major disadvantage to using .class?
Question was originally based on a false premise. I edited it to spell out what this premise was and make it less confusing for new people who come along. Hopefully I did this such that the given answers are still exactly applicable; apologies if not.
#Bean annotation is meant to provide a spring bean. The type of the bean to provide will be the same type of the class/interface you define in the return method. So, instead of declaring to return a concrete class in the method, return the top (abstract) class/interface instead.
Imagine this case:
public interface MyEntityDao {
MyEntity get(String id);
}
#Repository
public class MyEntityDaoDatabaseImpl implements MyEntityDao {
#Override
public MyEntity get(String id) {
/* implementation that goes to database every time */
}
}
#Repository
public class MyEntityDaoCacheImpl implements MyEntityDao {
#Override
public MyEntity get(String id) {
/* implementation that looks the data
up in cache, never in database */
}
}
#Configuration
public class MyAppConfiguration {
#Bean
public MyEntityDaoDatabaseImpl method1() {
return new MyEntityDaoDatabaseImpl();
}
#Bean
public MyEntityDaoCacheImpl method2() {
return new MyEntityDaoCacheImpl();
}
}
#Service
public class MyEntityService {
#Autowired //what to inject here?
MyEntityDao dao;
}
In case above, there are two implementations of the proposed interface. How the framework may be able to understand which implementation to use except for the name?
#Service
public class MyEntityService {
#Autowired
#Qualifier("properBeanNameToInject")
MyEntityDao dao;
}
Bean name is not necessarily related to its class or even any of interfaces it implements. It is a name and nothing more. When you use the annotation configuration, Spring figures out what the exact class or interface the #Bean provides like the rest of java code would: either through the fully qualified name in the code or through the imports specified in the file. In your case, you presumably have an import com.my.injected.Service; statement at the top of the java file.
Your example is using the fully qualified class name as the bean name. It is your choice. You could use any other identifier. Using the fully qualified name could be useful if your code is providing an object that is named exactly like another 3rd party #Bean object that your code must include or consume. However, you could just as easily use name = "myService".
The bean name helps Spring (and application programmer) to distinguish between multiple instances of of the same bean class because you can deploy the same class as bean several times. If only one instance of bean type appear you event do not have to give it name manually: spring does this by default.
If you have several beans that have the same type or implement the same interface and you want to refer specific bean use #Qualifier annotation.