Spring IoC and Generic Interface Type

27,890

Solution 1

I do not believe this is possible due to erasure. We generally switched to strongly typed sub-interfaces when going for full-autowiring:

public interface LongService extends ISimpleService<Long> {}
public interface StringService extends ISimpleService<String> {}

Upon doing this switch we found we actually liked this pretty well, because it allows us to do "find usage" tracking much better, something you loose with the generics interfaces.

Solution 2

i don't think thats possible without Qualifier

ill try to show my Solutions with a genericDAO, sorry if it's a bit detailed

the Interface and Implementation Class Definition

public interface GenericDAO<T, ID extends Serializable> (...)

public class GenericDAOImpl<T, ID extends Serializable>
    implements GenericDAO<T, ID> 
    (...) important is this constructor
    public GenericDAOImpl(Class<T> persistentClass) {
       this.persistentClass = persistentClass;
    }

the spring bean definition, notice the abstract="true"

<bean id="genericHibernateDAO" class="de.optimum24.av.pers.ext.hibernate.dao.GenericDAOImpl"
      abstract="true">
    <description>
        <![CDATA[
            Definition des GenericDAO.
        ]]>
    </description>
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

Using this genericDAO without special implementation Class

 <bean id="testHibernateChildDao" class="de.optimum24.av.pers.ext.hibernate.dao.GenericDAOImpl">
    <property name="sessionFactory" ref="sessionFactory" />
    <constructor-arg>
        <value>de.optimum24.av.pers.test.hibernate.domain.TOChild</value>
    </constructor-arg>
</bean>

notice the constructor-arg with an concrete Class, if you work with Spring Annotation you need to do:

@Autowired
@Qualifier(value = "testHibernateChildDao")
private GenericDAO<TOChild, Integer> ToChildDAO;

to distinguish the various versions of genericDao Beans (notice the Qualifier with direct Reference to the Beanname)

Using this genericDAO with special implementation Class

the Interface and Class

public interface TestHibernateParentDAO extends GenericDAO<TOParent, Integer>{
  void foo();
}
public class TestHibernateParentDAOImpl extends GenericDAOImpl<TOParent, Integer>
                              implements TestHibernateParentDAO {
  @Override
  public void foo() {
      //* no-op */
  }
}

the Bean Definition, notice the "parent" Reference to the abstract genericDAO above

<bean id="testHibernateParentDao" class="de.optimum24.av.pers.test.hibernate.dao.TestHibernateParentDAOImpl"
      parent="genericHibernateDAO" />

and usage with Spring Annotation

@Autowired
private TestHibernateParentDAO ToParentDAO;

Solution 3

It is possible to do this with erasure, if the generic type is fully reified at compile-time. In this case the type information is available via either of:

Class#getGenericInterfaces()
Class#getGenericSuperclass()

This is the major feature of Guice which is missing from Spring.

Solution 4

Don't make your interface generic. Make your methods, instead:

public interface ISimpleService {
    public <T> T doSomething(T param);
}

Hope it helps.

Share:
27,890
Miguel Ping
Author by

Miguel Ping

Nuthin' special :)

Updated on November 27, 2020

Comments

  • Miguel Ping
    Miguel Ping over 3 years

    I'm trying to use Spring IoC with an interface like this:

    public interface ISimpleService<T> {
        void someOp(T t);
        T otherOp();
    }
    

    Can Spring provide IoC based on the generic type argument T? I mean, something like this:

    public class SpringIocTest {
        @Autowired
        ISimpleService<Long> longSvc;
    
        @Autowired
        ISimpleService<String> strSvc;
        //...
    }
    

    Of course, my example above does not work:

    expected single matching bean but found 2: [serviceLong, serviceString]
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessAfterInstantiation(AutowiredAnnotationBeanPostProcessor.java:243)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:957)
    

    My Question: is it possible to provide a similar functionality with minimum modifications to either the Interface or the implementing classes? I know for instance I can use @Qualifiers, but I want to keep things as simple as possible.

  • Miguel Ping
    Miguel Ping over 15 years
    And how do you deal with code duplication? Probably have a middle class that is also generic, no? Tks
  • krosenvold
    krosenvold over 15 years
    The only duplication necessary is the marker interface. But you're not showing your implementation classes so I can't tell if you're doing anything I'm not seeing!
  • Miguel Ping
    Miguel Ping over 15 years
    The implementation would suit another SO question :)
  • HipsterZipster
    HipsterZipster over 12 years
    Great answer hitting on both the Annotation and XML usages. Did this solution work out for you in the long term? Where there any drawbacks to using this methodology like being able to trace through code easier (mentioned by Krosenvold in 1st post)?
  • Michael Pralow
    Michael Pralow over 12 years
    it is more of a organizational/knowledge problem, if the developers know the process it does work, this generic method is certainly harder to handle than the use of (marker) interfaces