What works
Suppose I have a spring bean definition of an ArrayList:
<bean id="availableLanguages" class="java.util.ArrayList">
<constructor-arg>
<bean class="java.util.Arrays" factory-method="asList">
<constructor-arg>
<list>
<value>de</value>
<value>en</value>
</list>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
Now I can inject this into all kinds of beans, e.g. like this:
#Controller
class Controller {
#Autowired
public Controller(ArrayList<String> availableLanguages) {
// ...
}
}
This works great.
How it breaks
However if I change my controller a tiny bit and use the type List instead of ArrayList like this:
#Controller
class Controller {
#Autowired
public Controller(List<String> availableLanguages) {
// ...
}
}
Then instead I get a list of all beans of type String rather then the bean I defined. However I actually want to wrap my List into an unmodifiable List, but this will only be possible if I downgrade my dependency to a list.
So far discovered workaround
The following XML file:
<bean id="availableLanguages" class="java.util.Collections" factory-method="unmodifiableList">
<constructor-arg>
<bean class="java.util.Arrays" factory-method="asList">
<constructor-arg>
<list>
<value>de</value>
<value>en</value>
</list>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
works together with this controller:
#Controller
class Controller {
#Autowired
public Controller(Object availableLanguages) {
List<String> theList = (List<String>)availableLanguages;
}
}
While this works the extra type cast is ugly.
Findings so far
I figured that there is a special handling for collections in Spring 4.2.5 (the currently most recent version) which seems to cause all the trouble. It creates special behaviour when a parameter is an interface that extends Collection. Thus I can workaround by using Object or a concrete implementation as parameter type.
Question
Is there any way to directly inject a list into a bean? How?
Using #Qualifier will inject the bean with the given qualifier. You can name the list which you want to be a bean and that will work fine.
Related
Java
public class MyObject{}
public class MyFactory{
private Optional<MyObject> myproperty;
public Optional<MyObject> getMyproperty{...}
public void setMyproperty{...}
}
Spring config xml (doesn't work)
<bean id="myproperty" class="java.util.Optional">
<constructor-arg>
<value>com.MyObject</value>
</constructor-arg>
</bean>
<bean id="myfactory" class="com.Myfactory">
<property name="myproperty" ref="myproperty" />
</bean>
Does spring support generics beans?
The reason for using Optional is it provide some useful features such as checking value if null. You can complete checking and further action in one line of code.
getMyproperty().ifPresent(id -> call.setId(id));
Seems the problem have nothing to do with generics.
You simply need to properly tell Spring to create the bean using a factory method, as Optional can only be created though factory methods. Something like:
<bean id="myproperty" class="java.util.Optional" factory-method="of">
<constructor-arg type="java.lang.Object" value="com.MyObject" />
</bean>
for which it is supposed to mean creating the myproperty bean by Optional.of(com.MyObject.class) (Change the factory-method to ofNullable if that's the one you want to use)
Another option is to use SpEL (Spring Expression Language):
<bean id="mybean" ...>
<property name="optProp" value="#{ T(java.util.Optional).of( #wrapme) }"/>
</bean>
Where "wrapme" is the name of a bean defined elsewhere that you want to wrap in java.util.Optional.
I've got this:
#Named
#Singleton
public class MyDefaultDef {
#Inject
public MyDefaultDef(SomeRef someRef, List<AnotherRef> anotherRefs) {
//...
}
//...
}
Question1: [main] How does work autowiring of List<AnotherRef> anotherRefs as a constructor arg?
I mean if I'd like to replace that bean definition with xml, I had to specify each element of the list. I.e.
<constructor-arg>
<list>
<ref bean="..."/>
<ref bean="..."/>
</list>
</constructor-arg>
But from where Spring takes those elements in case of annotations?
Question2: How to replace MyDefaultDef bean definition to xml?
When Spring needs to autowire a List<SomeBean>, it looks up all beans in its BeanFactory and retrieves all those that are of type SomeBean. It thens creates a List and adds them to it. It then autowires it.
There is no way in Spring XML to do this listing by type. You'll need to compromise. You leave your class as such
public class MyDefaultDef {
#Inject
public MyDefaultDef(SomeRef someRef, List<AnotherRef> anotherRefs) {
//...
}
//...
}
and simply declare
<bean class="com.example.MyDefaultDef" autowire="constructor"/>
Spring will end up using your constructor above.
I was wondering if it is possible to specify x amount of the same bean in a list in Spring. For example, instead of having beans with ids: stage1, stage2,... stageN, as here:
<bean id="stage1" class="Stageclass"/>
<bean id="stage2" class="Stageclass"/>
<bean id="stages" class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="stage1" />
<ref bean="stage2" />
</list>
</constructor-arg>
</bean>
Would it be possible to do something like the following?:
<bean id="stage1" class="Stageclass"/>
<bean id="stages" class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="stage1" duplicate="20 times"/>
</list>
</constructor-arg>
</bean>
Thanks in advance.
If you use annotation based configuration and you specified list of objects with same interface as dependency for some class then spring will auto-wire aut-wire then for free. Example:
interface StageInterface {
//...
}
class StageImpl1 implements StageInterface {
//...
}
class StageImpl2 implements StageInterface {
//...
}
#Component
class StageContainer {
private final List<StageInterface> stages;
#Autowired
public StageContainer(List<StageInterface> stages) {
this.stages = stages;
}
public List<StageInterface> getStages() {
return stages;
}
}
This is a spring version 3+ feature.
I believe the same is possible with xml configuration as well. In your case that's probably will be the same class(StageClass), but with different configuration parameters.
Lookup method injection from http://static.springsource.org/spring/docs/2.5.x/reference/beans.html solved the problem. Just needed to make sure the bean I wanted multiple instances of had scope="prototype"
You can't do that using standard Spring's default namespace. However you can implement your own custom namespace where you could support such syntax.
Alternatively, you can implement a static method that would create an ArrayList instance with duplicated elements.
I have a class "Box" with add method accepting all the fruits:
public class Box {
List <IFruit> fruits;
public void add (IFruit fruit) {
fruits.add(fruit);
}
}
I would like to define with Spring's applicationContext.xml a singleton instance of this class, which would have all the IFruits implementations added (those appear in a package x.y.fruits, for inst. x.y.fruits.Apple).
The first part is easy:
<bean id="box" class="x.y.Box"/>
But how to wire all the IFruit instances?
Thanks!
If you #Autowire the field, you do not need to define anything, Spring will find all instances of the IFruit interface in the application context and load them in.
public class Box {
#Autowired
List <IFruit> fruits; //This should contain all IFruit's in the ApplicationContext
public void add (IFruit fruit) {
fruits.add(fruit);
}
}
Of course, you need to add the element <context:annotation-config/> to your xml configuration for #Autowired to work...
If you create a setter for the list, say setFruits, you can wire it like this:
<bean id="box" class="x.y.Box">
<property name="fruits">
<list>
<ref bean="fruit1" />
<ref bean="fruit2" />
...
</list>
</property>
</bean>
<bean id="fruit1" class="x.y.fruits.Apple" />
...
You can also do this similarly using constructor injection.
I have a spring beans configuration file where I define the following jackson classes as spring beans.
For some reason on run-time the filterProvider bean is instantiated without the map argument.
You can see from the docs that the SimpleFilterProvider does have such a constructor and that SimpleBeanPropertyFilter implements BeanPropertyFilter.
<bean id="productAttributesAndAdvertiserNameFilter" class="org.codehaus.jackson.map.ser.impl.SimpleBeanPropertyFilter" factory-method="filterOutAllExcept">
<constructor-arg value="name"/>
</bean>
<bean id="offerIdFilter" class="org.codehaus.jackson.map.ser.impl.SimpleBeanPropertyFilter" factory-method="filterOutAllExcept">
<constructor-arg value="id"/>
</bean>
<bean id="filterProvider" class="org.codehaus.jackson.map.ser.impl.SimpleFilterProvider">
<constructor-arg>
<util:map value-type="org.codehaus.jackson.map.ser.BeanPropertyFilter">
<entry key="onlyNameFilter" value-ref="productAttributesAndAdvertiserNameFilter" />
<entry key="onlyIdFilter" value-ref="offerIdFilter" />
</util:map>
</constructor-arg>
</bean>
Update:
As of Jackson 1.9.5 this issue is fixed (thanks Tatu)
Any help would be appreciated.
Looks like you've found a bug in SimpleFilterProvider.
I just downloaded the latest sources (1.9.4) and the constructors are defined as such:
public SimpleFilterProvider() {
_filtersById = new HashMap<String,BeanPropertyFilter>();
}
/**
* #param mapping Mapping from id to filter; used as is, no copy is made.
*/
public SimpleFilterProvider(Map<String,BeanPropertyFilter> mapping) {
_filtersById = new HashMap<String,BeanPropertyFilter>();
}
The constructor which takes the mapping ignores it... (i.e. javadoc is incorrect)
I think <util:map> is misplaced here. I'd make it a separate bean, outside of the filter provider declaration, and refer to it. OR I'd change that to a <map> without the util namespace.
I don't see why it is not working.
At worst, you can create your own class by extending the SimpleFilterProvider and declare this bean in your Spring context...