In my MVP applications I use code such as the following to wire my Presenter and View:
View view = new View();
Presenter presenter = new Presenter(view);
view.setPresenter(presenter);
The View class is constructed in a temporarily invalid state, which the call to setPresenter rectifies. I have some code in the View class that throws an IllegalStateException if the View is used without the Presenter being configured.
I was hoping Spring could wire this relationship together with a configuration such as:
<bean id="presenter" class="com.foo.Presenter">
<constructor-arg ref="view" />
</bean>
<bean id="view" class="com.foo.View">
<property name="presenter" ref="presenter" />
</bean>
This failed with a lengthy circular-dependency exception.
Is there a way I can tell Spring to construct the view bean, then construct the presenter bean before finally calling the setter on view?
A related question is Spring setter dependency injection after all beans have been created. However, one of the suggested solutions is to resolve the circular dependencies by using setter-based wiring, which is exactly what I'm failing to do here. The latest manual also seems to agree - see the box entitled "Circular dependencies":
One possible solution is to edit the source code of some classes to be configured by setters rather than constructors. Alternatively, avoid constructor injection and use setter injection only. In other words, although it is not recommended, you can configure circular dependencies with setter injection.
I'm sure that there is a better solution, but if all else fails you can do it "manually":
Configuration:
<bean id="presenter" class="com.foo.Presenter">
</bean>
<bean id="view" class="com.foo.View" init-method="init">
</bean>
View class:
public class View implements ApplicationContextAware {
private ApplicationContext applicationContext;
private Presenter presenter;
public void init(){
presenter = (Presenter)applicationContext.getBean("presenter");
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
As an extra note, if you have annotation-driven on your configuration you can just do #Autowired private ApplicationContext applicationContext; instead of implementing the ApplicationContextAware interface.
Some further research has unearthed a solution. Initially, I tried reversing the order of the bean definitions in the XML config file and it worked:
<bean id="view" class="com.foo.View">
<property name="presenter" ref="presenter" />
</bean>
<bean id="presenter" class="com.foo.Presenter">
<constructor-arg ref="view" />
</bean>
However, this felt wrong as I'm confident I shouldn't be relying on file ordering to ensure things aren't breaking. This then led to the realisation that the depends-on can solve the problem:
<bean id="presenter" class="com.foo.Presenter" depends-on="view">
<constructor-arg ref="view" />
</bean>
<bean id="view" class="com.foo.View">
<property name="presenter" ref="presenter" />
</bean>
I welcome comments on whether this is a good approach. It's quite plausible I'm bending Spring to my will in a way that's not intended.
Related
I'm trying to add BouncyCastle to my Spring application but I am not sure how to add the provider to the java.security.Security provider list using JavaConfig.
Using XML configuration, I can use the MethodInvokingFactoryBean similar the following:
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="java.security.Security.addProvider"/>
<property name="arguments">
<list>
<bean class="org.bouncycastle.jce.provider.BouncyCastleProvider"/>
</list>
</property>
</bean>
However, I'm not sure of the right way to do this using JavaConfig. Should I still be using the MethodInvokingFactoryBean? I presumed since it is pure java, there would be a more direct approach. At the moment, I've added the directive to a #PostConstruct method in the JavaConfig object, but not too thrilled about it - it seems a little "hacky" to me:
#Configuration
public class AppConfig {
// other #Bean definitions
#PostConstruct
public void init(){
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
}
MethodInvokingBean will be the de facto choice for add BouncyCastleProvider to java.security.Security since you won't need any exposure to your application context.
I have the following construct Spring XML (Spring 3.1):
<bean id="taskRunner" abstract="true" init-method="startThreads"
class="my.class.TaskRunner" />
...
<bean id="taskRunnerA" parent="taskRunner">
<constructor-arg name="foo">...</constructor-arg>
<property name="bar">...</property>
</bean>
And I am trying to separate out the init method into a higher level abstract bean:
<bean id="taskRunnerLauncher" abstract="true" init-method="startThreads" />
<bean id="taskRunner" abstract="true" depends-on="taskRunnerLauncher"
class="my.class.TaskRunner" />
...
<bean id="taskRunnerA" parent="taskRunner">
<constructor-arg name="foo">...</constructor-arg>
<property name="bar">...</property>
</bean>
Somehow this does not work, i.e. startThreads() is never invoked in the second case. Does anybody know why? Does Spring support nested abstract beans?
My idea for doing this is so I can override "taskRunnerLauncher" in unit tests and set it to "mock" or "java.lang.Object" and suppress startThreads() call (which starts new thread and making it a pain to test).
Does anybody know why?
The taskRunnerLauncher bean is set to be abstract. This means it will only act as a template for other beans. Spring will not actually create a bean for it. Therefore there won't be any invocation of startThreads because there is nothing to invoke it on.
Found the problem. I mistakenly used depends-on instead of parent attribute on taskRunner bean.
I've got a MyAppConversionServiceFactoryBean which I'm registering like:
<bean id="conversionService" class="com.MyProject.MyAppConversionServiceFactoryBean">
<property name="messageSource" ref="messageSource"/>
<property name="converters">
<set>
<bean class="com.MyProject.XRepresentationConverter" />
<bean class="com.MyProject.YRepresentationConverter" />
<bean class="com.MyProject.ZRepresentationConverter" />
</set>
</property>
</bean>
I can continue to list every converter we write into this list, but I'd love to be able to configure it such that this isn't necessary and that converters will automatically register themselves somehow with my factory.
Sidebar 1: If that's not possible with a custom factory, is it possible with the default spring one?
Sidebar 2: If neither the first part nor Sidebar 1 is possible, is it possible to #Autowired the conversionService into the converters (so they can easily call one another)? Attempting to #Autowired ConversionService conversionService has previously given me issues due to not being able to wire the conversionService into an object while it's still busy creating the service.
Note: We're using Spring, but not Spring MVC. I have no control over that, so any solutions on that route will be unfortunately unusable. I can change pretty much anything else about the configuration and Java classes, just not the overarching tools.
#Vikdor's comment on the question pointed me in the right direction.
Spring is apparently capable (and no one I asked in person knew this) of gathering collections of beans through the scanning process with #Autowired annotations. Here's what I needed to achieve the same effect I got from the configuration in the post:
applicationContent.xml must have:
<context:component-scan base-package="com.MyProject"/>
<bean id="conversionService" class="com.MyProject.MyAppConversionServiceFactoryBean" />
MyAppConversionServiceFactoryBean.java:
public class MyAppConversionServiceFactoryBean implements
FactoryBean<ConversionService>, InitializingBean {
#Autowired
private Set<BaseConverter> converters;
}
And then all of my converters now have the #Component annotation.
Relevant Docs on #Autowired do briefly mention that it can be used to collect all beans of a type, but I wouldn't have known that it could be done into any collection type without this thread by Grzegorz Oledzki which addresses the generic form of my question, but takes it down a philosophical route.
I have two xml files defining beans for the springframework (version 2.5.x):
containerBase.xml:
<beans>
<bean id="codebase" class="com.example.CodeBase">
<property name="sourceCodeLocations">
<list>
<value>src/handmade/productive</value>
</list>
</property>
</bean>
</beans>
... and
containerSpecial.xml:
<beans>
<import resource="containerBase.xml" />
</beans>
Now I want to adjust the property sourceCodeLocations of bean codebase within containerSpecial.xml. I need to add a second value src/generated/productive.
A simple approach is to override the definition of codebase in containerSpecial.xml and add both values, the one from containerBase.xml and the new one:
containerSpecial.xml:
<beans>
<import resource="containerBase.xml" />
<bean id="codebase" class="com.example.CodeBase">
<property name="sourceCodeLocations">
<list>
<value>src/handmade/productive</value>
<value>src/generated/productive</value>
</list>
</property>
</bean>
</beans>
Is there a way to extend the list without redefining the bean?
EDIT 2009-10-06:
The purpose of this is to have a shared standard container containerBase that is used by a lot of different projects. Each project can override/extend some properties that are special for that project in its own containerSpecial. If the project doesn't override, it's using the defaults defined in containerBase.
You could use a BeanFactoryPostProcessor to change the bean's metadata before the Spring container instantiates the CodeBase bean. For example:
public class CodebaseOverrider implements BeanFactoryPostProcessor {
private List<String> sourceCodeLocations;
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
CodeBase codebase = (CodeBase)beanFactory.getBean("codebase");
if (sourceCodeLocations != null)
{
codebase.setSourceCodeLocations(sourceCodeLocations);
}
}
public void setSourceCodeLocations(List<String> sourceCodeLocations) {
this.sourceCodeLocations = sourceCodeLocations;
}
}
Then in contextSpecial.xml:
<beans>
<import resource="context1.xml" />
<bean class="com.example.CodebaseOverrider">
<property name="sourceCodeLocations">
<list>
<value>src/handmade/productive</value>
<value>src/generated/productive</value>
</list>
</property>
</bean>
</beans>
Yes. A bean definition can have a "parent" attribute that references a parent bean definition. The new "child" definition inherits most of the properties of the parent and any of those properties can be overridden.
See Bean Definition Inheritance
Also you can use Collection Merging to merge the list property definition from the parent and child bean definitions. This way you can specify some list items in the parent bean definition and add more items to it in the child bean definition.
Is there a way to define the list in a properties or other configuration before hand?
It seems like the app configuration and wiring are tightly coupled. From my experience, if it is hard to do something in Spring, likely there is a different easier way to do it.
3 approaches:
Simple: have two lists defaultSourceCodeLocations and additionalSourceCodeLocations and have your accessor methods check both of these (or combine them). I've seen this done in some frameworks - a default list of handlers is populated then additional user created ones are added...
More complicated but keeps the original class clean: You could then create a CodeBaseModifier class. This would have a init-method to alter an injected instance of the bean.
<bean id="codebaseModifier" class="com.example.CodeBase" init-method="populateCodeBase">
<property name="sourceCodeLocations" ref="codebase"/>
<property name="additionalSourceCodeLocations">
<list>
<value>src/handmade/productive</value>
</list>
</property>
</bean>
If you wanted to make this really generic you could make a bean modifier that would do this by reflection. Be careful of the ordering if use this approach. Dependent beans of CodeBase would have to make sure this class was instantiated first (with depends on)
3 A variation on 2... Instead of directly creating a CodeBase class instead create a factory that returns a populated bean. This factory could then be configured with Spring in a similar fashion to 2. Have a defaultSourceCodeLocations and additionalSourceCodeLocations
Unless you need a lot of extensible properties I would go with option 1.
In Spring 3.0, you can specify merge="true" on the 'list' tag. See http://forum.springsource.org/archive/index.php/t-97501.html for details.
I have two Spring proxies set up:
<bean id="simpleBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="simpleBeanTarget"/>
</property>
<property name="interceptorNames">
<list>
<value>cacheInterceptor</value>
</list>
</property>
</bean>
<bean id="springDao" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="springDaoTarget"/>
<property name="interceptorNames">
<list>
<value>daoInterceptor</value>
</list>
</property>
</bean>
simpleBean works just fine -- springDao does not.
The SpringDao class looks like:
public class SpringDao extends JdbcDaoSupport {
private SimpleJdbcTemplate simpleJdbcTemplate;
public SimpleJdbcTemplate getSimpleJdbcTemplate() {
if (simpleJdbcTemplate==null) {
simpleJdbcTemplate= new SimpleJdbcTemplate(getDataSource());
}
return simpleJdbcTemplate;
}
...
And I have my unit test autowired like this:
#Autowired
#Qualifier("springDao")
protected SpringDao springDao;
And the first indication something is wrong is I get this error:
Could not autowire field: . . . nested
exception is
java.lang.IllegalArgumentException
If I comment out the #Qualifier annotation and run my unit test again, I get this:
No unique bean of type ... expected
single matching bean but found 2:
[springDaoTarget, springDao]
That is what I expected.
So I changed my autowiring to
#Autowired
#Qualifier("springDaoTarget")
protected SpringCustomerCapacityDao springDao;
And added the following to my unit test:
Object proxy = applicationContext.getBean("springDao");
Assert.assertNotNull(proxy);
Assert.assertTrue(proxy instanceof SpringDao);
And the instanceof test failed, which (to me) means that my proxy is not really my proxy.
So I'm confused. What's going on? How can I fix this?
Edit Here is the requested springDaoTarget definition, which will disappoint many people:
<bean id="springDaoTarget" class="com.company.SpringDao">
If the target of your proxy implements at least one interface then Spring's default behavior is to create a JDK Proxy that implements all the interfaces of the target. This means it will not be a subclass of the target class. You can override this by forcing the creation of CGLIB proxies instead which are dynamic subclasses of the target.
As a general rule, if you are going to use AOP but only use interfaces in a limited fashion you'll want to force CGLIB. Otherwise you will have lots of JDK Proxies in your container which are not of the same type as the bean implementations you loaded.
See Cliff Meyers blog: Spring AOP: CGLIB or JDK Dynamic Proxies?
It was easy to fix, once I figured it out. SpringDao no longer inherits from JdbcDaoSupport and now it works.