Let's say we have two beans, defined in Spring
<bean class="foo.A"/>
<bean class="foo.B"/>
public class A {
#Autowired
private B b;
}
public class B {
public void foo() {
...
}
}
What I want to achieve is the interception of all calls to B.foo(). Looking at documentation, I wrote interceptor C and changed the definition of bean B as follows:
public class C implements org.springframework.aop.MethodBeforeAdvice {
public void before(final Method method, final Object[] args, final Object target) {
// interception logic goes here
}
}
<bean class="foo.C"/>
<bean class="org.springframework.aop.framework.ProxyFactoryBean" scope="prototype">
<property name="proxyTargetClass" value="true"/>
<property name="singleton" value="false"/>
<property name="target">
<bean class="foo.B" scope="prototype"/>
</property>
<property name="interceptorNames">
<list>
<value>foo.C</value>
</list>
</property>
</bean>
Problem: when starting up, Spring container complains: No matching bean of type [foo.B] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. In other words, it can't inject B into A because B is hidden behind org.springframework.aop.framework.ProxyFactoryBean and no longer "automagically" recognized. If I replace the definition into a simple class=foo.B, container starts fine. What's the best way to solve this?
Bonus question: is it possible to implement interception of B.foo() without involvement of ProxyFactoryBean and only using annotations (preferably without involvement of <aop:...)?
Define an interface for foo.B (e.g. foo.BInterface) and use foo.BInterface in the class A.
Also pay attention that Autowired injections are done only once. So if foo.A is singleton, it will receive only the first created instance of foo.B, while you want it to be a prototype.
Answer to bonus: Yes, but it may be more complicated. As a possible solution you can implement BeanPostProcessor. In the implementation you can replace the foo.B with dynamic proxy. So basically you do the same, but instead of using <aop: you do it yourself using basic Spring functionality. And again: you don't solve the "prototype is not autowired" problem and you still need an interface.
Perhaps you want to have the Bean 'foo.B' defined outside of the ProxyFactoryBean, and refer to it from the target property.
<bean class="foo.C"/>
<bean id="fooB" class="foo.B" scope="prototype"/>
<bean class="org.springframework.aop.framework.ProxyFactoryBean" scope="prototype">
<property name="proxyTargetClass" value="true"/>
<property name="singleton" value="false"/>
<property name="target" ref="fooB"/>
<property name="interceptorNames">
<list>
<value>foo.C</value>
</list>
</property>
</bean>
Tarlog's answer is correct, but to make it more clear:
you should wire objects by their interface, not by their class:
public class A {
#Autowired
private C b;
}
public class B implements C{
public void foo() {
...
}
}
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 have a list of Class types that I need to iterate over and for every type in that list, Spring needs to automatically find the correct sort of object to initialize.
For example : I have a ClassA and ClassB. When for example there is a type User, a ClassA needs to be initialized with certain parameters (which are defined in the context.xml). When for example there is a type of Message, it should also make an object from type ClassA but with different parameters, which are again defined in the context.xml.
How would I go about doing this? I have looked at the inversion of control feature of spring but cannot seem to find the correct implementation for my specific purpose
One idea was that I make a bean for every kind of possible type such as
<bean id="classAconfig" class="ClassA">
<property name="type" value="User.class"/>
<property name="fields">
<list>
<value>id</value><value>email</value>
</list>
</property>
<property name="map">
<map>
<entry key="id" value="1"/><entry key="login" value="1"/><entry key="email" value="1"/>
</map>
</property>
</bean>
Kind regards,
Merlijn
Well, I found it. Just had to define some beans in the context xml like described above. But in ClassA I extended InitializingBean and overrided the afterPropertiesSet methode. In that methode I registered the ClassA in my service.
public class ClassA extends InitializingBean
#Override
public void afterPropertiesSet() throws Exception {
service.registerClass(this);
}
And then in my service :
public void registerClass(#Nonnull Class clazz) {
classes.put(clazz.getType(), clazz);
}
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've got following java class.
package com.org.data.dbresource;
import org.springframework.orm.ibatis.SqlMapClientTemplate;
public class DBConnectionManager {
private SqlMapClientTemplate sqlMapClientTemplate;
public void setSqlMapClientTemplate (SqlMapClientTemplate sq)
{
this.sqlMapClientTemplate = sq;
}
public SqlMapClientTemplate getSqlMapClientTemplate ()
{
return this.sqlMapClientTemplate;
}
}
My Spring xml looks like following:
<bean id="IbatisDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/RSRC/app/oltp"/>
</bean>
<bean id="MySqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation" value="classpath:sql-map.xml"/>
<property name="dataSource" ref="IbatisDataSource"/>
</bean>
<bean id="myObject" class="com.org.data.dbresource.DBConnectionManager">
<property name="sqlMapClientTemplate" ref="MySqlMapClient"/>
</bean>
Error I get is:
Failed to convert property value of
type
[com.ibatis.sqlmap.engine.impl.SqlMapClientImpl]
to required type
[org.springframework.orm.ibatis.SqlMapClientTemplate]
for property 'sqlMapClientTemplate';
Everything works fine if, instead of SqlMapClientTemplate I pass SqlMapClient but then I have to explicitly catch SQLExceptions
What should I change?
The error says it all - you're trying to inject an object of type SqlMapClient (as created by SqlMapClientFactoryBean) into a property of type SqlMapClientTemplate.
You need to manually instantiate the SqlMapClientTemplate yourself, either inside DBConnectionManager, e.g.
private SqlMapClientTemplate sqlMapClientTemplate;
public void setSqlMapClient(SqlMapClient sqlMapClient)
{
this.sqlMapClientTemplate = new SqlMapClientTemplate(sqlMapClient);
}
and then
<bean id="myObject" class="com.org.data.dbresource.DBConnectionManager">
<property name="sqlMapClient" ref="MySqlMapClient"/>
</bean>
Remember, SqlMapClientTemplate isw nothing more than a helper class. Neither Spring nor iBatis mandates its use, and if you want to use it, you need to instantiate it yourself.
Is there a way to set a property in spring to, not an instance of a class, but the class object itself? i.e.
Rather than
<bean>
<property name="prototype" class="a.b.c.Foo">...
giving you an instance of "Foo", something like:
<bean>
<property name="prototype" class="java.lang.Class" value="a.b.c.Foo.class"...
edit:
best (working) solution so far - use the normal instantiation and derive the class in the setter. In terms of solutions I think this we'd describe this as "cheating":
<bean class="Bar">
<property name="prototype" class="a.b.c.Foo">...
public class Bar{
public void setPrototype(Object o){
this.prototypeClass=o.getClass();
edit:
dtsazza's method works as well.
edit:
pedromarce's method works as well.
<bean>
<property name="x">
<value type="java.lang.Class">a.b.c.Foo</value>
</property>
</bean>
That should work.
You could certainly use the static factory method Class.forName(), if there's no more elegant syntax (and I don't believe there is):
<property name="x">
<bean class="java.lang.Class" factory-method="forName">
<constructor-arg value="a.b.c.Foo"/>
</bean>
</property>
No. With a bean tag you instruct Spring on how to instantiate a class.
Would <property name="x" class="a.b.c.Foo.class"> work? That should be an instance of a Class object...