2013-04-13 65 views
0

爲了消除整個應用程序中的'靜態'聲明(以幫助JVM的GC),我從下面的Converter類定義中刪除了'static'。因此,導致下面臭名昭着的錯誤:Can Converter @FacesConverter(forClass = [someClass.class])被實現爲@Singleton @Lock(READ)?

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) 

我假設'靜態'是必要的,因爲只有一個副本的類創建每個應用程序。正確?那麼,我可以將類定義爲@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

答案是肯定的,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()); 
     } 
    } 
} 

教訓:

@注入, @EJB, BeanManager

參考:ejbFacade無法通過以下引用或實例化

甲骨文博客

  1. Ken Saks's Blog: Application-specified Portable JNDI Names
  2. Ken Saks's Blog: Portable Global JNDI Names

TomEE JavaEE的例子 - 引用的EJB

  1. Injection Of Ejbs
  2. Lookup Of Ejbs with Descriptor
  3. Lookup Of Ejbs

最終,我不得不提及的server.log文件Glassfis h,參考實現(RI),以查看我的@Stateless EJB的JNDI查找路徑樣本,因爲我過去使用過Glassfish。 :)

UPDATE:

您還可以找到在TomEE /卡塔利娜日誌便攜式全局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) 

其中「Web應用程序」在全局JNDI名稱可能是您的WAR文件名的名稱或可能EJB JAR文件名,等等

希望這會幫助別人!