2012-04-02 19 views
2

......至少,如果「優雅的解決方法」的概念實際上有優點!Weld(CDI)和Datanucleus(JPA)不好玩,有沒有優雅的解決方法?

這裏還有一些細節:

當使用CDI和JPA,你經常要訪問您的JPA管理豆的一個在EL表達式在JSF頁面中的一個,像這樣:

<html xmlns="http://www.w3.org/1999/xhtml" 
     xmlns:h="http://java.sun.com/jsf/html" 
     xmlns:f="http://java.sun.com/jsf/core"> 
    <h:head> 
    <title>An Everyday Facelet</title> 
    </h:head> 
    <h:body> 
    <h1>Behold, a jpa-managed bean property!</h1> 
    <h:outputText value="#{exampleEntity.name}" /> 
    </h:body> 
</html> 

爲了簡單起見,我們假設這個頁面是HTTP Post的結果,並且客戶端爲前一頁的name屬性輸入了一個值。豆本身可以是一個簡單的jpa實體從生產者方法中檢索,如下所示:

@Entity 
public class ExampleEntity implements Serializable { 
    @Id 
    @Column 
    private Long entityId; 
    @Column 
    private String name; 

    public ExampleEntity() { 
    } 

    public void setEntityId(Long entityId) { 
     this.entityId = entityId; 
    } 
    public Long getEntityId() { 
     return entityId; 
    } 
    public void setName(String name) { 
     this.name = name; 
    } 
    public String getName() { 
     return name; 
    } 
} 

// Some method in another class 
public class AnotherClass { 
    @Produces 
    @RequestScoped 
    @Named("exampleEntity") 
    public ExampleEntity getExampleEntity() { 
     return new ExampleEntity(); 
    } 
} 

好吧,讓我們來編譯。數據中心JPA實現的一個重要方面是有一個後編譯步驟。你需要在編譯好的jpa類上運行一個字節碼增強器,所以我們假設我們這樣做了。當試圖啓動你的servlet容器(例如,Tomcat,Jetty)時,你會在啓動Weld時出現異常(如果你真的嘗試在某處注入這個bean,那麼你會得到一個異常)。假設我的類在 'testapp' 包,例外情況是這樣的:

org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001437 Normal scoped bean class testapp.ExampleEntity is not proxyable because the type is final or it contains a final method public final java.lang.Object testapp.ExampleEntity.jdoGetObjectId() - Managed Bean [class testapp.ExampleEntity] with qualifiers [@Any @Default @Named]. 

公衆最終java.lang.Object繼承jdoGetObjectId()?我既沒有定義也沒有宣佈其中的一個,好的網絡服務器。你一定錯了!

原來datanucleus增強器必須將此最終方法添加到我編譯的類。如果我不運行它,Web服務器啓動正常,但我認爲我的數據不會實際存在。通過一點研究,我可以在Weld文檔中找到對問題的解釋:http://docs.jboss.org/weld/reference/1.1.5.Final/en-US/html/injection.html#d0e1429

簡而言之,它看起來像命名的bean不能有最終的方法。遵循一些建議,我找到了一個可行的解決方案。我爲我的jpa bean聲明瞭一個接口,並創建一個生成器方法來獲得一個具體的類(實際上它是數據核增強類,但Weld不知道)。這裏的額外代碼:

public interface ExampleEntity { 
    public Long getEntityId(); 
    public void setEntityId(Long entityId); 
    public String getName(); 
    public void setName(String name); 
} 

現在ExampleEntity純粹的接口,我創建沒有CDI註解

@Entity 
public class ExampleEntityImpl implements ExampleEntity, Serializable { 
    // Same as the ExampleEntity class above 
} 

最後,也許在控制器的地方,我定義了一個生產JPA管理實施獲取示例實體的方法

@Named("exampleEntityController") 
@RequestScoped 
public class ExampleEntityController { 

    private ExampleEntity newExampleEntity; 

    public ExampleEntityController() { 
     newExampleEntity = new ExampleEntityImpl(); 
    } 

    // The producer method 
    @Produces 
    @RequestScoped 
    @Named("exampleEntity") 
    public ExampleEntity getExampleEntity() { 
     return newExampleEntity; 
    } 

    // Other stuff, because surely a controller does more than just this, right? 
} 

而且這個工作。 Web服務器啓動,沒有例外。名稱屬性在該示例facelet中正確檢索(假定數據已經輸入到前一頁)。然而,爲每個jpa管理的bean製作一次性的接口和生產者方法是相當多餘又醜陋的。有更好的解決方案嗎?大核是這個項目的要求,所以我不能簡單地使用別的東西。如果還有更多「優雅的解決方法」,我想它會讓Weld更好地讓我擁有一種我永遠不會在我的一個命名bean中使用的最終方法。

編輯:感謝您的回覆/更正,但我正在尋找一種方法來避免必須爲每個jpa bean創建一個接口。我已經從示例中刪除了混合JPA/CDI註釋,但Web服務器仍會拋出相同的異常。不過,我可以看到我需要製作者方法。

+0

對不起,你是怎麼來'@Named ''@ RequestScoped'' @ Entity'? – Osw 2012-04-02 23:20:17

+0

好吧,範例在這個例子中是隨意的,但它只是一個命名的bean,我也可以使用JPA API持久化。無論如何,這就是目標。它適用於完整的應用程序服務器。 – Shaun 2012-04-02 23:32:33

+1

按照http://db.apache.org/jdo/enhancement.html – DataNucleus 2012-04-03 08:16:13

回答

1

你不應該爲你的實體使用CDI。

  • 實體由您創建,使用new操作
  • CDI豆是由容器創建的,所以它可以處理注射和初始化
1

不要將CDI註釋與JPA混合使用。你真正需要做的是爲任何你想使用CDI的實體創建一個生產者。 JPA需要創建該實例,然後生產者將允許它在CDI環境中使用或命名爲EL使用。

相關問題