views:

336

answers:

2

I want to be able to create a Tuple2 from spring config where I explicitly declare the types of my parameters:

<bean class="scala.Tuple2">
      <constructor-arg index="0" value="Europe/London" type="java.util.TimeZone" />
      <constructor-arg index="1" value="America/New_York" type="java.util.TimeZone" />
</bean>

This does not work (I have the relevant property editors specified in my config file). At runtime I get the error:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'scala.Tuple2#6504bc' defined in file [C:\Work\myproj\config\test\myproj.xml]: Unsatisfied dependency expressed through constructor argument with index 0 of type [java.lang.Object]:
Ambiguous constructor argument types - did you specify the correct bean references as constructor arguments?

The error goes away if I do not declare the explicit type - but then of course the Tuple2 in my program is just a (String, String) which is not what I want.


EDIT for those of you who did not know this, Spring uses PropertyEditors to create instances from Strings as follows:

public class TimeZoneEditor extends java.beans.PropertyEditorSupport {
    public void setAsText(String text) { setValue(TimeZone.getTimeZone(text)); }
    public String getAsText() { return ((TimeZone)getValue()).getID(); }
}

Now I simply declare in my config:

<bean id="customEditorConfigurer" 
       class="org.springframework.beans.factory.config.CustomEditorConfigurer">   
    <property name="customEditors"> 
        <map>
            <entry key="java.util.TimeZone">
                <bean class="my.cleve.rutil.TimeZoneEditor"/> 
            </entry>
        </map>
    </property> 
</bean>

And hey presto I can do things like:

<map key-type="java.util.TimeZone" value-type="java.lang.Integer">
    <entry key="Europe/London" value="4" />
</map>

Or alternatively Spring can figure out the generic type parameters from your setter methods. Except it doesn't seem to work in the case of my Tuple2!

+1  A: 

You will need to create the TimeZone parameters explicitly using the static method getTimeZone() of class TimeZone:

<bean class="scala.Tuple2">
  <constructor-arg index="0">
    <bean class="java.util.TimeZone" factory-method="getTimeZone">
      <constructor-arg value="Europe/London"/>
    </bean>
  </constructor-arg>
  <constructor-arg index="1">
    <bean class="java.util.TimeZone" factory-method="getTimeZone">
      <constructor-arg value="America/New_York"/>
    </bean>
  </constructor-arg>
</bean>
Walter Chang
I shouldn't have to do this, Walter. For example I can create a `Map` whose value-types are `TimeZone`s in the way I have described above.
oxbow_lakes
A: 

It may be working for Map because spring has special support for it through the syntax you specified:

<map key-type="java.util.TimeZone" value-type="java.lang.Integer">

In this case, spring probably determines it should invoked the property editors based on the mismatch between the provided values of type String and the requested types TimeZone and Integer.

huynhjl