2017-08-08 47 views
1

我扶着CDI標註有一個問題關於可生產譯註:CDI主要生產方法InjectionPoint是空

我有一個銀行

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 { 
} 

枚舉

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異常。注入點是空的。什麼是問題,我該如何解決?

替代的解決方案:嘗試焊接

<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/

+0

注入點和生產者點的限定符必須匹配。而且你犯了兩個限定詞的錯誤,一個是生產者和一個是注射。它應該是一個。 – maress

+0

我剛剛使用Weld測試了您的實現,並且一切正常。我想你的問題在於你的單元測試。我沒有Arquillian的經驗來判斷它是否能夠初始化和注入bean。 – ujulu

+0

我用POM更新了這篇文章。我正在使用TOMEE – Dingo

回答

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測試

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綠條:

您在沉積銀行美國

你是withdr來自美國銀行

+0

謝謝大家幫助我。 – Dingo

+0

不客氣。 – ujulu