为了在整个app中删除'static'声明(以帮助JVM的GC),我从下面的Converter类的定义中删除了'static'。所以这导致了下面的臭名昭着的错误:
Apr 13, 2013 4:10:38 AM org.apache.myfaces.application.ApplicationImpl internalCreateConverter
SEVERE: Could not instantiate converter jsf.CustomerController$CustomerControllerConverter
java.lang.InstantiationException: jsf.CustomerController$CustomerControllerConverter
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at org.apache.myfaces.application.ApplicationImpl.internalCreateConverter(ApplicationImpl.java:1626)
at org.apache.myfaces.application.ApplicationImpl.createConverter(ApplicationImpl.java:1545)
at javax.faces.application.ApplicationWrapper.createConverter(ApplicationWrapper.java:158)
我认为'static'是必要的,因为每个应用程序只创建一个类的副本。正确?那么,我可以将类定义为@Singleton @Lock(READ)来解决问题吗?
根据NetBeans生成的JSF控制器/ bean代码,Converter通常在与控制器或@ManagedBean相同的.java文件中定义。老实说,我不想在xhtml中使用addConverter()或converterId =“...”。我更喜欢使用@FacesConverter,因为这在整个应用程序中都适用于我。
package jsf;
import jpa.entities.Customer;
import jpa.session.CustomerFacade;
import java.io.Serializable;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
@ManagedBean(name = "customerController")
@RequestScoped
public class CustomerController implements Serializable {
@EJB
private jpa.session.CustomerFacade ejbFacade;
public CustomerController() {
}
@FacesConverter(forClass = Customer.class)
public class CustomerControllerConverter implements Converter {
public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
if (value == null || value.length() == 0) {
return null;
}
/*
* 2012-07-10 when user enters invalid/incomplete value (e.g. "irene", see below) in AutoComplete
*
WARNING: For input string: "irene"
java.lang.NumberFormatException: For input string: "irene"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.valueOf(Integer.java:582)
at jsf.pointOfContact.pf_PointOfContactController$PointOfContactControllerConverter.getKey(pf_PointOfContactController.java:1625)
at jsf.pointOfContact.pf_PointOfContactController$PointOfContactControllerConverter.getAsObject(pf_PointOfContactController.java:1620)
at org.primefaces.component.autocomplete.AutoCompleteRenderer.getConvertedValue(AutoCompleteRenderer.java:529)
at javax.faces.component.UIInput.getConvertedValue(UIInput.java:1030)
at javax.faces.component.UIInput.validate(UIInput.java:960)
*
*/
try {
Integer test = getKey(value);
} catch (java.lang.NumberFormatException e) {
return null;
}
CustomerController controller = (CustomerController) facesContext.getApplication().getELResolver().
getValue(facesContext.getELContext(), null, "customerController");
return controller.ejbFacade.find(getKey(value));
}
java.lang.Integer getKey(String value) {
java.lang.Integer key;
key = Integer.valueOf(value);
return key;
}
String getStringKey(java.lang.Integer value) {
StringBuffer sb = new StringBuffer();
sb.append(value);
return sb.toString();
}
public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
if (object == null) {
return null;
}
if (object instanceof Customer) {
Customer o = (Customer) object;
return getStringKey(o.getCustomerId());
} else {
throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + Customer.class.getName());
}
}
}
}
请告知。
另外,如果有人在stackoverflow.com上回复我的问题,请告诉我如何收到电子邮件通知。
谢谢!
答案 0 :(得分:0)
答案是肯定的,在JNDI查找的帮助下。
我刚刚从JSF @RequestScoped CustomerController中删除了CustomerControllerConverter,创建了转换器类,用@Singleton @Lock(READ)标记它,并通过JNDI查找引用了@Stateless EJB。见下文。
package converter;
import java.util.concurrent.TimeUnit;
import javax.ejb.AccessTimeout;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Singleton;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.naming.InitialContext;
import jpa.entities.Customer;
import jpa.session.CustomerFacade;
/**
*
* @author Administrator
*/
@Singleton
@Lock(LockType.READ)
@AccessTimeout(value = 1, unit = TimeUnit.MINUTES)
@FacesConverter(forClass = Customer.class)
public class CustomerConverter implements Converter {
public CustomerConverter() {
}
public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
if (value == null || value.length() == 0) {
return null;
}
/*
* 2012-07-10 when user enters invalid/incomplete value (e.g. "irene", see below) in AutoComplete
*
WARNING: For input string: "irene"
java.lang.NumberFormatException: For input string: "irene"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.valueOf(Integer.java:582)
...
...
at org.primefaces.component.autocomplete.AutoCompleteRenderer.getConvertedValue(AutoCompleteRenderer.java:529)
at javax.faces.component.UIInput.getConvertedValue(UIInput.java:1030)
at javax.faces.component.UIInput.validate(UIInput.java:960)
*
*/
try {
Integer test = getKey(value);
} catch (java.lang.NumberFormatException e) {
return null;
}
Object object = null;
CustomerFacade ejbFacade;
try {
InitialContext ic = new InitialContext();
ejbFacade = (CustomerFacade) ic.lookup("java:global/appWARFileNameOrAppContextName/CustomerFacade");
if (ejbFacade == null) {
System.err.println("CustomerConverter.getAsObject(): ejbFacade = null)");
return null;
}
} catch (Exception e) {
System.err.println("CustomerConverter.getAsObject(): error on JNDI lookup of CustomerFacade");
e.printStackTrace();
return null;
}
try {
object = ejbFacade.find(getKey(value));
} catch (Exception e) {
System.err.println("CustomerConverter.getAsObject(): error on ejbFacade.find(getKey(value))");
e.printStackTrace();
return null;
}
return object;
}
java.lang.Integer getKey(String value) {
java.lang.Integer key;
key = Integer.valueOf(value);
return key;
}
String getStringKey(java.lang.Integer value) {
StringBuffer sb = new StringBuffer();
sb.append(value);
return sb.toString();
}
public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
if (object == null) {
return null;
}
if (object instanceof Customer) {
Customer o = (Customer) object;
return getStringKey(o.getCustomerId());
} else {
throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + Customer.class.getName());
}
}
}
经验教训:无法通过以下方式引用或实例化ejbFacade:
@注入, @EJB, BeanManager
参考文献:
Oracle博客
TomEE JavaEE示例 - 引用EJB
最终,我不得不引用Glassfish的server.log文件(参考实现(RI))来查看我的@Stateless EJB的JNDI查找路径示例,因为我使用的是Glassfish,过去。 :)
<强>更新强>
您还可以在TomEE / catalina日志中找到可移植的全局JNDI名称。它将如下所示。
Apr 13, 2013 10:00:58 AM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=CustomerFacadeLocalBean) --> Ejb(deployment-id=CustomerFacade)
Apr 13, 2013 10:00:58 AM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=global/webApp/CustomerFacade!jpa.session.CustomerFacade) --> Ejb(deployment-id=CustomerFacade)
Apr 13, 2013 10:00:58 AM org.apache.openejb.assembler.classic.JndiBuilder bind
INFO: Jndi(name=global/webApp/CustomerFacade) --> Ejb(deployment-id=CustomerFacade)
其中&#39; webApp&#39;在全局JNDI名称中可能是您的WAR文件名或可能是EJB JAR文件名等...
希望这有助于其他人!