Results 1 to 10 of 10

Thread: Injections and generic types in Spring (2.5)

  1. #1

    Question Injections and generic types in Spring (2.5)

    Hello,

    I just struggled with Spring and understanding why it can't determine a generic type during injection. Please, have a look at this simple code:

    Code:
    public class GenericInjectTest {
    	private Ship< Integer > ship = new Ship< Integer >();
    
    	private void beanInit() {
    		System.out.println( ship.getData() );
    		System.out.println( ship.getData().getClass() );
    	}
    
    	public Ship< Integer > getShip() {
    		return ship;
    	}
    
    	public void setShip( Ship< Integer > ship ) {
    		this.ship = ship;
    	}
    }
    (the beanInit method gets called by Spring, it is defined as the default bean init method).

    And this is the Ship class:

    Code:
    public class Ship< T > {
    	private T data;
    
    	public T getData() {
    		return data;
    	}
    
    	public void setData( T data ) {
    		this.data = data;
    	}
    }
    Here is the (important part of the) Spring context configuration:

    Code:
    <bean class="com.test.spring.GenericInjectTest">
    	<property name="ship.data" value="123" />
    </bean>

    Looking at the bean definition, we can see that I want to set the property "ship.data" to "123". Since ship is parameterized with "Integer" in the GenericInjectTest class, I would think that Spring is able to detect the correct runtime type, which is Integer, and would convert the "123" to a real Integer.

    But this is not the case. When I run the program, the line

    Code:
    System.out.println( ship.getData() );
    prints "123". But the next line

    Code:
    System.out.println( ship.getData().getClass() );
    throws the exception

    Code:
    java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    So Spring has injected a String for the property "ship.data", not an Integer.


    Is it the case, that Spring can't handle those generics, or am I doing anything wrong here?


    Thanks a lot for your help

  2. #2
    Join Date
    May 2007
    Location
    Saint Petersburg, Russian Federation
    Posts
    1,189

    Default

    Minor spring bug. Feel free to register it at the spring jira.

  3. #3

    Default

    Hi,

    thanks for your answer,

    Quote Originally Posted by denis.zhdanov View Post
    Minor spring bug. Feel free to register it at the spring jira.
    well, I did not expect such an answer, I'd rather say it is my own failure

    Is this a known bug? I'm just wondering, because you sounded so confident in saying that.

  4. #4
    Join Date
    May 2007
    Location
    Saint Petersburg, Russian Federation
    Posts
    1,189

    Default

    Quote Originally Posted by patb View Post
    Hi,

    thanks for your answer,

    well, I did not expect such an answer, I'd rather say it is my own failure

    Is this a known bug? I'm just wondering, because you sounded so confident in saying that.


    I'm confident about that just because I debugged the test-case you mentioned and checked the processing (spring 2.5.6). I see that generic type of the bean field is not processed during context initialization, hence, I can be absolutely sure that it's a spring bug. However, I don't have an information whether it's known.

  5. #5

    Default

    Hello,

    ok, I will post it on Spring Jira.


    Thanks a lot

  6. #6

    Default

    What is the reference number in Jira? I would like to comment on the Jira issue.

    I have traced this back to the following method in CachedIntrospectionResults.java:

    Code:
    private CachedIntrospectionResults(Class beanClass) throws BeansException {}
    The problem is that Introspector.getBeanInfo(beanClass), which is part of Java, returns a BeanInfo with a PropertyDescriptor specifying Object as the class for the "data" property. I think Spring will have to specifically check the bean instance to find out what the property instance class really is.

  7. #7

    Default

    Hi,

    great to see that you were able to look into it - my understanding of Spring is not yet sufficient for that

    The JIRA link to this issue is: http://jira.springframework.org/browse/SPR-5561

    Do you know any kind of nice workaround for this?

    Thanks a lot

  8. #8
    Join Date
    May 2007
    Location
    Saint Petersburg, Russian Federation
    Posts
    1,189

    Default

    Quote Originally Posted by patb View Post
    Hi,

    ...

    Do you know any kind of nice workaround for this?

    Thanks a lot
    You can create a separate bean of necessary type (Integer) and inject it to the target property using 'ref' attribute instead of 'value'.

  9. #9
    Join Date
    Aug 2006
    Location
    Now Germany, previously Ukraine
    Posts
    1,546

    Default

    Or even better - use inner bean
    Code:
    <bean class="com.test.spring.GenericInjectTest">
    	<property name="ship.data"> 
                  <bean class="java.lang.Integer">
                         <constructor-arg value="123"/>
                  </bean>
            </property>
    </bean>

  10. #10

    Question

    Thanks to all who offered help, now I'm waiting for the bug fix. Meanwhile, maybe someone is able to do a quick fix for it, if it's not too complicated? I'm just too new to Spring to try it myself

    Quote Originally Posted by denis.zhdanov View Post
    You can create a separate bean of necessary type (Integer) and inject it to the target property using 'ref' attribute instead of 'value'.
    Quote Originally Posted by al0 View Post
    Or even better - use inner bean
    Thanks a lot, this works of course.

    Actually, my original intention was not to inject a bean to a generic property, that has been parameterized with a simple class (like Integer), but to inject a bean to a generic property, that has been parameterized with an enum.

    But since my example above reproduces the same error and is more simple, I decided to use that to describe the potential bug in Spring.

    So, instead of something like

    Code:
    private Ship< Integer > ship = new Ship< Integer >();
    I have such a declaration:

    Code:
    private Ship< MyEnum > ship = new Ship< MyEnum >();
    As we know, Spring has the nice ability to detect the enum type and inject the correct type, for example:

    Code:
    <bean class="com.test.spring.GenericInjectTest">
      <property name="ship.data" value="RADAR" />
    </bean>
    Where "RADAR" is from the enum "MyEnum" ("MyEnum.RADAR") and Spring can detect that.

    There is a workaround, using this kind of bean definition:

    Code:
    <bean class="com.test.spring.GenericInjectTest">
      <property name="ship.data">
        <util:constant static-field="com.test.spring.GenericInjectTest$MyEnum.RADAR" />
      </property>
    </bean>
    But this drives me nuts, it clutters the XML code so heavily when you have to set a lot of Enums, especially when the package names are a lot longer... the direct use of the enum name for the property would be more elegant.

    But I think for that, there is no workaround, since it depends on the type-detection thing for the generic parameterization, which is apparently broken at the moment

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •