......至少,如果「優雅的解決方法」的概念實際上有優點!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服務器仍會拋出相同的異常。不過,我可以看到我需要製作者方法。
對不起,你是怎麼來'@Named ''@ RequestScoped'' @ Entity'? – Osw 2012-04-02 23:20:17
好吧,範例在這個例子中是隨意的,但它只是一個命名的bean,我也可以使用JPA API持久化。無論如何,這就是目標。它適用於完整的應用程序服務器。 – Shaun 2012-04-02 23:32:33
按照http://db.apache.org/jdo/enhancement.html – DataNucleus 2012-04-03 08:16:13