Declaring an array of objects in a Spring bean context - java

I'm trying to create an array of objects in a Spring context file so I can inject it to a constructor that's declared like this:
public RandomGeocodingService(GeocodingService... services) { }
I'm trying to use the <array> tag:
<bean id="googleGeocodingService" class="geocoding.GoogleGeocodingService">
<constructor-arg ref="proxy" />
<constructor-arg value="" />
</bean>
<bean id="geocodingService" class="geocoding.RandomGeocodingService">
<constructor-arg>
<array value-type="geocoding.GeocodingService">
<!-- How do I reference the google geocoding service here? -->
</array>
</constructor-arg>
</bean>
I haven't been able to find an example or something in the in the documentation on how to do this. Also, you have any suggestions for a better way of acheiving what I'm trying to do, please let me know :).

That's because there's no such thing as <array>, there's only <list>.
The good news is that Spring will auto-convert between lists and arrays as required, so defined your array as a <list>, and Spring will be coerce it into an array for you.
This should work:
<bean id="googleGeocodingService" class="geocoding.GoogleGeocodingService">
<constructor-arg ref="proxy" />
<constructor-arg value="" />
</bean>
<bean id="geocodingService" class="geocoding.RandomGeocodingService">
<constructor-arg>
<list>
<ref bean="googleGeocodingService"/>
</list>
</constructor-arg>
</bean>
Spring will also coerce a single bean into a list, if required:
<bean id="geocodingService" class="geocoding.RandomGeocodingService">
<constructor-arg>
<ref bean="googleGeocodingService"/>
</constructor-arg>
</bean>

Spring can automatically convert a list into an array[]
check it out http://forum.springsource.org/showthread.php?37767-Injecting-String-Array
<bean name="test" class="Test">
<property name="values" value="hugo,emil"></property>
</bean>

Check out the util schema.

I'm actually using <array> tag to inject an array of objects into a bean and it works.
Take a look at the following code...
<bean id="song1" class="mx.com.company.songs.Song">
<property name="name" value="Have you ever seen the rain?"/>
</bean>
<bean id="song2" class="mx.com.company.songs.Song">
<property name="name" value="La bamba"/>
</bean>
<bean id="guitarPlayer" class="mx.com.company.musician.GuitarPlayer">
<property name="songs">
<array>
<ref bean="song1"/>
<ref bean="song2"/>
</array>
</property>
</bean>

Related

CompositeItemReader in Spring

In Spring Batch, in the job-request.xml file you can have the chunk's writer run a "compositeItemWriter" which looks something like this:
<bean id="compositeItemWriter"
class="org.springframework.batch.item.support.CompositeItemWriter">
<property name="delegates">
<list>
<ref bean="writer1" />
<ref bean="writer2" />
</list>
</property>
</bean>
I was wondering if there's anything similar for readers? I tried using org.springframework.batch.item.support.CompositeItemStream but apparently delegates does not exist as a property. Putting "reader1" or "reader2" in the delegates property list in compositeItemWriter similarly does not work (cannot convert readers to writers)
Any advice would be greatly appreciated
Thanks!
MultiResourceItemReader reads items from multiple resources sequentially:
http://docs.spring.io/spring-batch/apidocs/org/springframework/batch/item/file/MultiResourceItemReader.html
It will look like:
<bean id="itemReader" class="org.springframework.batch.item.file.MultiResourceItemReader">
<property name="resources" value="LIST_OF_FILES" />
<property name="delegate" ref="itemReaderDelegate" />
</bean>

Spring doesn't resolve classpath: in the file declaration in xml

I have the problem with resolve spring's "classpath:" feature. I a have my file in the next path:
src/main/java/resources/FederationMetadata.xml
Also, I have a bean:
<bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager">
<constructor-arg>
<list>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
<constructor-arg>
<bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
<constructor-arg>
<value type="java.io.File">classpath:FederationMetadata.xml</value>
</constructor-arg>
<property name="parserPool" ref="parserPool"/>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
</bean>
</constructor-arg>
</bean>
</list>
</constructor-arg>
</bean>
So my problem is that application fails with the next exception:
D:\myFolder\myProject\classpath:FederationMetadata.xml does not exist
As I understand Spring doesn't resolve file location. I tried with classpath*:, and it didn't help. In another project I have the same settings (with "classpath:") and it works fine. What it can be?
This issue was driving me crazy as well.
At some point I realized that FilesystemMetadataProvider was replaced with ResourceBackedMetadataProvider.
So now if you have your Metadata XML inside of the classpath, do something like this:
<bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager">
<constructor-arg>
<list>
<bean class="org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider">
<constructor-arg>
<bean class="java.util.Timer"/>
</constructor-arg>
<constructor-arg>
<bean class="org.opensaml.util.resource.ClasspathResource">
<constructor-arg value="/FederationMetadata.xml"/>
</bean>
</constructor-arg>
<property name="parserPool" ref="parserPool"/>
</bean>
</list>
</constructor-arg>
</bean>
Try
<value type="java.io.File">file:///FederationMetadata.xml</value>
instead of
<value type="java.io.File">classpath:FederationMetadata.xml</value>
If you want it accessed from class path you need to put it inside
WEB-INF/classes folder.
the path is relative to classes folder ie if the file is inside
WEB-INF/classes/configs/somefile.xml
then
classpath:configs/somefile.xml

Does java spring config have the ability to resolve variables from custom variable resolvers?

In .net spring land you can declare a custom variable source and do ${variableName} style variables in your spring config. You do it by implementing an interface (IVariableSource) and it looks like this:
<object type="Spring.Objects.Factory.Config.VariablePlaceholderConfigurer, Spring.Core">
<property name="VariableSources">
<list>
<ref object="MyVariableSource" />
</list>
</property>
</object>
<object id="TestObject" type="TestProject.TestObject, TestProject" singleton="false">
<constructor-arg type="string" value="${MyVariableDefinedInMyVariableSource}" />
</object>
What is the equivalent of this in java spring land?
You can also achieve the same in Java too. Below is the example.
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:config/config.properties" />
</bean>
<bean id="myController"
<property name="variableName" value="${variableName}" />
</bean>

Is there a shorthand for creating a String constant in Spring context XML file?

I need to define a string value in Spring context XML file that is shared by multiple beans.
This is how I do it:
<bean id="aSharedProperty" class="java.lang.String">
<constructor-arg type="java.lang.String" value="All beans need me :)"/>
</bean>
Creating a java.lang.String bean by passing a constructor argument of java.lang.String seems kludgy.
Is there a shortcut?
I know this property can be passed using PropertyOverrideConfigurer, but I want to keep this property within the XML file.
You can use PropertyPlaceholderConfigurer and keep values in xml:
<context:property-placeholder properties-ref="myProperties"/>
<bean id="myProperties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="aSharedProperty">All beans need me :)</prop>
</props>
</property>
</bean>
Then you reference it with:
<bean id="myBean" class="my.package.MyClass">
<property name="someField" value="${aSharedProperty}"/>
</bean>
A shorthand to the solution proposed by mrembisz goes like this:
<context:property-placeholder properties-ref="myProperties"/>
<util:properties id="myProperties">
<prop key="aSharedProperty">All beans need me :)</prop>
</util:properties>
You may be able to use the following:
<bean id="abstractParent" abstract="true">
<property name="sharedProperty" value="All child beans need me" />
</bean>
<bean id="bean1" class="MyClass1" parent="abstractParent">
...non-shared properties...
</bean>
<bean id="bean2" class="MyClass2" parent="abstractParent">
...non-shared properties...
</bean>
However, that relies on the property having the same name, so may not be applicable for you.
Something I've used in the past is SpEL to make sure that a bean has the same value as another:
<bean id="myBean" class="xxx.yyy.Foo" >
<property name="myProperty" value="1729" />
</bean>
<bean id="copyCat" class="xxx.yyy.Bar" >
<property name="anotherProperty" value="#{myBean.myProperty}" />
</bean>
I have found this to be particularly useful when setting the value did something other than a simple assignment.

How to reduce duplication in Spring application context

I have some beans which I create which all use a similar pattern for bean instantiation. The top objects are all very similar, but the objects they contain differ by string constructor arguments. Everything in the each top-level bean is the same except for two instances of THIS CHANGES A and one instance of THIS CHANGES B. Below is one of my beans. The others are exactly the same except for the THIS CHANGES values.
<bean id="mover1" class="CustomDataMover">
<constructor-arg ref="session"/>
<constructor-arg>
<bean class="DataCache">
<constructor-arg>
<bean class="AllValuesReader">
<constructor-arg ref="databaseConnector"/>
<constructor-arg value="THIS CHANGES A"/>
<constructor-arg value="v1"/>
<constructor-arg value="v2"/>
</bean>
</constructor-arg>
</bean>
</constructor-arg>
<constructor-arg ref="customUpdate"/>
<constructor-arg value="THIS CHANGES B"/>
<constructor-arg>
<bean class="ValueGenerator">
<constructor-arg>
<bean class="LatestValueRetriever">
<constructor-arg ref="databaseConnector"/>
<constructor-arg value="v3"/>
<constructor-arg value="v4"/>
<constructor-arg value="THIS CHANGES A"/>
</bean>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
How can I reduce the amount of duplication in my beans? I'm looking for some way to make some sort of template. Also, please note that I do have references to other beans.
You can use abstract bean definitions as templates to reduce duplication. For example:
<bean id="parent" abstract="true">
<constructor-arg value="ARG0"/>
<property name="propertyA" value="A"/>
<property name="propertyB" value="B"/>
<property name="propertyC" ref="beanC"/>
</bean>
<bean id="child1" class="SomeClass" parent="parent">
<property name="propertyD" value="D1"/>
</bean>
<bean id="child2" class="SomeOtherClass" parent="parent">
<property name="propertyD" value="D2"/>
</bean>
Beans "child1" and "child2" will share values from "parent" for arg0, "propertyA", "propertyB", and "propertyC", and still be able to configure their own values for "propertyD".
Note that "parent" has no class and therefore cannot be instantiated. Also note that "child1" and "child2" can be children of the same abstract bean definition while being completely different classes - this hierarchy has nothing to do with the class hierarchy.

Categories

Resources