CDI生成方法InjectionPoint是空的

时间:2017-08-08 18:17:51

标签: java junit cdi

我倾向于CDI Annotation有关于Produces Annotation的问题:

我有一个银行

public interface Bank {
    public void withdrawal();
    public void deposit();
}

两种实施风格

public class BankOfAmerica implements Bank {
    public void withdrawal() {
        System.out.println("You are withdrawing from Bank Of America");
    }

    public void deposit() {
        System.out.println("You are depositing in Bank Of America");
    }
}

public class Chase implements Bank {
    public void withdrawal() {
        System.out.println("You are withdrawing from Chase");
    }

    public void deposit() {
        System.out.println("You are depositing in Chase");
    }
}

限定符

@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, PARAMETER, FIELD})
public @interface BankProducer {
}

Enum

public enum BankName {
    DCU(DCU.class), Chase(Chase.class), BankOfAmerica(BankOfAmerica.class);

    private Class<? extends Bank> bankType;

    private BankName(Class<? extends Bank> bankType) {
        this.bankType = bankType;
    }

    public Class<? extends Bank> getBankType() {
        return bankType;
    }
}

绑定BankName的注释

@Retention(RUNTIME)
@Target({TYPE, METHOD, PARAMETER, FIELD})
public @interface BankType {
    @Nonbinding
    BankName value();
}

工厂

public class BankFactory {
    @Produces
    @BankProducer
    public Bank createBank(@Any Instance<Bank> instance, InjectionPoint injectionPoint) {
        Annotated annotated = injectionPoint.getAnnotated();
        BankType bankTypeAnnotation = annotated.getAnnotation(BankType.class);
        Class<? extends Bank> bankType = bankTypeAnnotation.value().getBankType();
        return instance.select(bankType).get();
    }
}

和JUnit

@RunWith(Arquillian.class)
public class ProducesTest {
    @Inject
    @BankProducer
    @BankType(BankName.BankOfAmerica)
    private Bank bankOfAmerica;

    @Deployment
    public static JavaArchive createDeployment() {
        return ShrinkWrap.create(JavaArchive.class).addPackages(true, "com.tutorial.produces")
            .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml").merge(getDependecies());
    }

    private static JavaArchive getDependecies() {
        JavaArchive[] javaArchives = Maven.configureResolver().loadPomFromFile("pom.xml")
            .resolve("org.projectlombok:lombok").withTransitivity().as(JavaArchive.class);
        JavaArchive mergedLibraries = ShrinkWrap.create(JavaArchive.class);
        for (JavaArchive javaArchive : javaArchives) {
            mergedLibraries.merge(javaArchive);
        }
        return mergedLibraries;
    }

    @Test
    public void create() {
        assertEquals(banks.getBankOfAmerica().getClass(), BankOfAmerica.class);
    }
}

POM - 使用tomee

<dependency>
    <groupId>org.apache.tomee</groupId>
    <artifactId>javaee-api</artifactId>
    <version>7.0-1</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.apache.tomee</groupId>
    <artifactId>arquillian-tomee-embedded</artifactId>
    <version>7.0.3</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.jboss.shrinkwrap.resolver</groupId>
    <artifactId>shrinkwrap-resolver-depchain</artifactId>
    <version>2.2.2</version>
    <scope>test</scope>
    <type>pom</type>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.10</version>
    <scope>test</scope>
</dependency>

我在工厂的createBank方法中遇到了NullPointer异常。 InjectionPoint是空的。问题是什么,如何解决?

替代解决方案:尝试焊接

<dependency>
    <groupId>org.jboss.weld.se</groupId>
    <artifactId>weld-se</artifactId>
    <version>2.2.8.Final</version>
</dependency>

JUnit的

@RunWith(WeldJUnit4Runner.class)
public class ProducesWeldTest {
    @Inject
    @BankProducer
    @BankType(BankName.BankOfAmerica)
    private Bank bankOfAmerica;

    @Test
    public void create() {
         assertEquals(bankOfAmerica.getClass(), BankOfAmerica.class);
    }
}

WeldContext和WeldJUnit4Runner来自这里 - http://memorynotfound.com/java-se-unit-testing-cdi-junit-jboss-weld-se/

1 个答案:

答案 0 :(得分:0)

正如我在帖子评论中已经提到的,CDI实施似乎有效。我认为问题在于测试。最初,我刚用main()方法编写了一个简单的测试,一切正常。现在我将相同的代码移动到JUnit测试,它仍然有效。为了测试您的实现,我刚刚为您的工厂和测试类添加了以下客户端,如下所示:

public class BankClient {

    @Inject
    @BankProducer
    @BankType(BankName.BankOfAmerica)
    private Bank bankOfAmerica;

    public void deposit() {
        bankOfAmerica.deposit();
    }

    public void withdrawal() {
        bankOfAmerica.withdrawal();
    }
}

// JUnit test

public class BankServiceTest {
    private static Weld weld = new Weld();

    private static BankClient sut;

    @BeforeClass
    public static void initWeld() {
        WeldContainer container = weld.initialize();;
        sut = container.instance().select(BankClient.class).get();
    }


    @Test
    public void deposit_should_be_invoked() {
        sut.deposit();
    }

    @Test
    public void withdrawal_should_be_called() {
        sut.withdrawal();
    }

    @AfterClass
    public static void shutDown() {
        weld.shutdown();
    }
}

执行测试后,您应该在控制台和JUnit绿色栏上看到以下输出:

  

您存入美国银行

     

您正在退出美国银行