0

(JVM の GC を支援するために) アプリ全体で「静的」宣言を削除するために、以下の Converter クラスの定義から「静的」を削除しました。そのため、以下の悪名高いエラーが発生しました。

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)

アプリケーションごとにクラスのコピーが 1 つだけ作成されるため、「静的」が必要だと思います。正しい?それで、問題を解決するためにクラスを @Singleton @Lock(READ) として定義できますか?

NetBeans によって生成された JSF コントローラー/Bean コードごとに、コンバーターは通常、コントローラーまたは @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 で誰かが私の質問に回答したときにメール通知を受け取る方法を教えてください。

ありがとう!

4

1 に答える 1

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 は、次の方法では参照またはインスタンス化できませんでした。

@Inject、@EJB、BeanManager

参考文献:

オラクルのブログ

  1. Ken Saks のブログ: アプリケーション固有のポータブル JNDI 名
  2. Ken Saks のブログ: 移植可能なグローバル JNDI 名

TomEE JavaEE の例 - EJB の参照

  1. EJB の注入
  2. 記述子による EJB のルックアップ
  3. EJB のルックアップ

最終的には、Glassfish の server.log ファイル (参照実装 (RI)) を参照して、@Stateless EJB の JNDI ルックアップ パスのサンプルを確認する必要がありました。過去に Glassfish を使用していたためです。:)

アップデート:

移植可能なグローバル JNDI 名は、TomEE/catalina ログでも確認できます。以下のようになります。

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)

グローバル JNDI 名の「webApp」は、WAR ファイル名または EJB JAR ファイル名などの名前である可能性があります...

これが他の人に役立つことを願っています!

于 2013-04-13T14:36:53.150 に答える