2017-03-23 18 views
1

我有以下情形:多级继承泛型和春季刊 - Java的

的POJO:

abstract class A 

abstract class B1 extends A 
class C1 extends B1 

abstract class B2 extends A 
class C2 extends B2 

引擎:

抽象类EngineA {

private EngineA a; 

    public EngineA(A a){ 
      this.a =a; 
} 
} 

抽象类EngineB1扩展EngineA私有引擎B1b1;

 public EngineB1(B1 b1){ 
        super(b1); 
        this.b1 =b1; 
} 
class EngineC1 extends EngineB1<C1> // similar constructor 

abstract class EngineB2<B2> extends EngineA<B2> // similar constructor 
class EngineC2 extends EngineB2<C2> // similar constructor 

所有POJO和发动机是组件与范围原型

我所做的这一切才能实现:

EngineA engineA = context.getBean(EngineA.class, /*either C1 or C2 object */) 
在主

()。

如果对象是C1我希望它被EngineC1和C2用于EngineC2 这样,如果在将来添加任何类,我不必更改主要方法。我也不想检查instanceof或使用Qualifier,因为最终它会导致主类的代码更改(我猜)。 但我得到这个错误:

没有可用的'EngineA'类型的可用bean:期望的单个匹配的bean,但找到2:c1,c2。

首先是否有可能实现我想要做的事情?

仿制药是否正确书写?

可能的解决方案之一是使用反射来构建自己的EngineFactory。但是还有其他解决方案吗?

回答

0

为此我找不到内置的Spring方法(选中3.0.6.RELEASE)。 这是可以实现的方式,希望这将有助于

package pt; 

public class Tc { 

    // Type Classes 
    public static abstract class A{} 

    public static abstract class B1 extends A{} 
    public static abstract class B2 extends A{} 

    public static abstract class C1 extends B1{} 
    public static abstract class C2 extends B2{} 

    // Engine Classes 
    public static abstract class EngineA<T extends A>{} 

    public static abstract class EngineB1<T extends B1> extends EngineA<B1>{} 
    public static abstract class EngineB2<T extends B2> extends EngineA<B2>{} 

    public static class EngineC1 extends EngineB1<C1>{} 
    public static class EngineC2 extends EngineB2<C2>{} 

} 

Spring配置文件:paramType.xml

<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> 

    <bean id="c1" class="pt.Tc$EngineC1"/> 
    <bean id="c2" class="pt.Tc$EngineC2"/> 

    <bean id="beanUtil" class="pt.BeanUtil"/> 

</beans> 

BeanUtil类处理的目的:

package pt; 

import org.springframework.beans.BeansException; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.ApplicationContextAware; 

import java.lang.reflect.ParameterizedType; 
import java.lang.reflect.Type; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Map; 

public class BeanUtil implements ApplicationContextAware { 

    private ApplicationContext context; 

    @Override 
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
     context = applicationContext; 
    } 

    public <T> T getBean(Class<T> beanClass, Class... paramClasses) { 

     List<String> expectedSet = convertToClassNameList(paramClasses); 

     Map<String, T> beansOfType = context.getBeansOfType(beanClass); 

     for (T value : beansOfType.values()) { 

      Type type = value.getClass().getGenericSuperclass(); 
      if (!(type instanceof ParameterizedType)) { 
       continue; 
      } 

      ParameterizedType parameterizedType = (ParameterizedType) type; 
      List<String> currentParamList = convertToClassNameList(parameterizedType.getActualTypeArguments()); 
      if (isSameListContent(currentParamList, expectedSet)) { 
       return value; 
      } 
     } 

     return null; 
    } 

    protected boolean isSameListContent(List<String> list1, List<String> list2) { 
     if (list1.size() != list2.size()) { 
      return false; 
     } 
     for (int i = 0; i < list1.size(); i++) { 
      if (!list1.get(i).equals(list2.get(i))) { 
       return false; 
      } 
     } 
     return true; 
    } 

    protected List<String> convertToClassNameList(Type... paramTypes) { 
     List<String> retval = new ArrayList<String>(paramTypes.length); 
     for (Type type : paramTypes) { 
      // class java.lang.String 
      retval.add(type.toString().substring(6)); 
     } 
     return retval; 
    } 

    protected List<String> convertToClassNameList(Class... paramClasses) { 
     List<String> retval = new ArrayList<String>(paramClasses.length); 
     for (Class clazz : paramClasses) { 
      retval.add(clazz.getName()); 
     } 
     return retval; 
    } 
} 

测试类

package pt; 

import org.junit.Assert; 
import org.junit.runner.RunWith; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.test.context.ContextConfiguration; 
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = {"classpath:paramType.xml"}) 
public class Test { 

    @Autowired 
    BeanUtil beanUtil; 

    @org.junit.Test 
    public void test1() { 

     Tc.EngineA bean = beanUtil.getBean(Tc.EngineA.class, Tc.C1.class); 
     System.out.println("Found Instance for param (pt.Tc$EngineC1) --> " + bean.getClass().getName()); 
     Assert.assertEquals(bean.getClass(), Tc.EngineC1.class); 

     bean = beanUtil.getBean(Tc.EngineA.class, Tc.C2.class); 
     System.out.println("Found Instance for param (pt.Tc$EngineC2) --> " + bean.getClass().getName()); 
     Assert.assertEquals(bean.getClass(), Tc.EngineC2.class); 

     bean = beanUtil.getBean(Tc.EngineA.class, Tc.B2.class); 
     System.out.println("Not existing param type --> " + (bean == null ? "Success" : "Fail")); 
     Assert.assertNull(bean); 
    } 
} 

结果是:

Found Instance for param (pt.Tc$EngineC1) --> pt.Tc$EngineC1 
Found Instance for param (pt.Tc$EngineC2) --> pt.Tc$EngineC2 
Not existing param type --> Success 
+0

在这种情况下该类锝将有当新的POJO和引擎被加入其中,我不想被更新。无论如何感谢您的努力:) –

+0

使用Tc类只是为了分组。没有什么与逻辑有关。尝试将每个文件分成不同的文件,你会发现它也会起作用。所以以后可以自由添加任何类。 – hsnkhrmn