Discussions

EJB programming & troubleshooting: error when using java.lang.Method.invoke in an EJB

  1. Hi,

    I have the following error when using java.lang.Method.invoke in an EJB when using WSAD 5 ou WAS 5, I haven't tried on another app server) :
    java.lang.IllegalArgumentException: argument type mismatch

    Here's the design of my application :
    I have 2 EARS :
    - client EAR
         - 1 Web module
    - server EAR
         - 1 EJB module

    I've deployed a utility JAR in the client EAR with the EJB module classes.

    These 2 EAR are deployed on the same WAS (or same WTE).
    (NB. : If those ears where deployed in different WAS, it works !)

    The client EAR instantiates a Bean and invokes a method of the EJB :
    /**
     * This methods instantiates the class aClassName, invokes the method aMethodName of this bean using parameters aParams.</p>
     */
    public Object execute (String aClassName, String aMethodName, String[] aParamClasses, Object[] aParams) {

    The value object transmitted (aParams) is developped included in the EJB module (and in the utility JAR of client EAR).

    So, this EJB has to :
    1. instanciate a class aClassName.
    2. Retrieve object java.lang.reflect.Method corresponding to method aMethodName with signature aParamClasses.
    3. invoke this method using aParams as arguments.

    The 3. part doesn't work. I think the class of the arguments aParams isn't the same after the 'RMI / IIOP marshalling' between the two EARs.

    Is it a bug ?

    Here's the stack trace :
    [30/07/03 20:33:04:828 CEST] 43e3af4f SystemErr R java.lang.IllegalArgumentException: argument type mismatch
    [30/07/03 20:33:04:828 CEST] 43e3af4f SystemErr R at java.lang.reflect.Method.invoke(Native Method)
    [30/07/03 20:33:04:828 CEST] 43e3af4f SystemErr R at nbp.test.ejbbean.EJBBeanBean.execute(EJBBeanBean.java:82)
    [30/07/03 20:33:04:828 CEST] 43e3af4f SystemErr R at nbp.test.ejbbean.EJSRemoteStatelessEJBBean_16fa0a36.execute(EJSRemoteStatelessEJBBean_16fa0a36.java:39)

    and here's a sample of the code :

    ------------------- EJB -------------------------
    /**
     * Bean implementation class for Enterprise Bean: EJBBean
     */
    public class EJBBeanBean implements javax.ejb.SessionBean {
    private javax.ejb.SessionContext mySessionCtx;

    public Object execute (String aClassName, String aMethodName, String[] aParamClasses, Object[] aParams) {
    try {
    ClassLoader lClassLoader = this.getClass().getClassLoader();
    //Thread.currentThread().getContextClassLoader();
    Class lClass = lClassLoader.loadClass(aClassName);
    int lParamSize = 0;
    if (aParamClasses != null) {
    lParamSize = aParamClasses.length;
    }
    Class[] lParamClasses = new Class[lParamSize];

    for (int i= 0; i<lParamSize; i++) {

    lParamClasses [i] = lClassLoader.loadClass (aParamClasses[i]);
    }

    Method lMethod = lClass.getMethod(aMethodName, lParamClasses);
    Object lInstance = lClass.newInstance();
    System.out.println ("1rst call... ");
    lMethod.invoke(lInstance, new Object[] {new Bean ("titi")});
    System.out.println ("1rst call OK ");
    System.out.println ("2nd call... ");
    Object lRet= lMethod.invoke(lInstance, aParams);
    System.out.println ("2nd call... ");
    return lRet;
    } catch (Throwable err) {
    err.printStackTrace ();
    throw new RuntimeException (err.toString());
    }
    }
    }

    ----------------- JSP (EAR Client) --------------

    <%
    try {
    InitialContext lContext = new InitialContext();
    EJBBeanHome lBeanHome = (EJBBeanHome) javax.rmi.PortableRemoteObject.narrow(lContext.lookup("ejb/nbp/test/ejbbean/EJBBeanHome"), EJBBeanHome.class);
    EJBBean lEJBBean = lBeanHome.create();
    lEJBBean.execute (BeanService.class.getName(), "execute", new String[] {Bean.class.getName()}, new Object[] {new Bean ("toto")});
    System.out.println (">>> invoke bean ok...");


    /*EJBControllerHome lHome = (EJBControllerHome) javax.rmi.PortableRemoteObject.narrow(lContext.lookup("ejb/nbp/test/service/controller"), nbp.fwk.service.provider.ejbcontroller.EJBControllerHome.class);
    EJBController lController = lHome.create();
    ServiceCommand lCommand = new ServiceCommand ("bean", "execute", new String[] {Bean.class.getName()}, new Serializable [] {new Bean("titi")}, new nbp.tec.environment.v1.DefaultRequest());
    lController.execute(lCommand);
    System.out.println (">>> invoke bean ok...");*/
    /*InterlocuteurPKTO lPk = new InterlocuteurPKTO ("1", "1", "1");
    lCommand = new ServiceCommand ("interlocuteur", "getInterlocuteur", new String[] {Integer.TYPE.getName()}, new Serializable [] {new Integer(4)}, new nbp.tec.environment.v1.DefaultRequest());
    lController.execute(lCommand);
    System.out.println (">>> invoke int ok...");
    lCommand = new ServiceCommand ("interlocuteur", "getInterlocuteur", new String[] {"nbp.srv.sample.service.interlocuteur.InterlocuteurPKTO"}, new Serializable [] {lPk}, new nbp.tec.environment.v1.DefaultRequest());
    lController.execute(lCommand);
    System.out.println (">>> invoke Pk ok...");
    lCommand = new ServiceCommand ("interlocuteur", "getListeInterlocuteur", new String[] {"nbp.srv.sample.service.interlocuteur.InterlocuteurPKTO", Integer.TYPE.getName()}, new Serializable [] {lPk, new Integer(4)}, new nbp.tec.environment.v1.DefaultRequest());
    lController.execute(lCommand);*/
    %><%
    } catch (Throwable err) {
    System.err.println (err.toString());
    err.printStackTrace();
    %>Erreur : <%=err.toString()%><%
    }%>


    thanks for your help.

    Threaded Messages (3)

  2. Against EJB Specs.[ Go to top ]

    Hi,
      If you go through the EJB Specifications, it is clearly stated over there that do not try to use ClassLoader in a bean class as well as do not use Reflection APIs in a bean class.
      This is discouraged by the specifications itself and hence all the application servers will give you errors for such type of code.
      Even if you try to deploy this code on Weblogic or any other application server, u will get such types of errors.
  3. EJB specs[ Go to top ]

    Thanks for your answer.

    I should'nt have used Ejbs in my app since the EJB specs are so strict (Classloader as you said, file access), and the advantages granted are so small (I don't really see them for the moment).

    I will try to do the same thing in another way (I was building a kind of EJB controller, so I used reflection in the EJB container).
  4. Hi again Jaitirth,

    I've read the EJbs specs in more detail and, as you said the specs mentions :
    The entreprise bean must not attempt to create a class loader ; obtain the current class loader ; set the current class loader ; set security manager ; create a new security manager ; stop the JVM ; or change input, output or error stream.

    So I've changed the code in order to avoid getting the current class loader :
    Previous code :
    ClassLoader lClassLoader = this.getClass().getClassLoader();
    Class lClass = lClassLoader.loadClass(aClassName);
    Changed code :
    Class lClass = Class.forName (aClassName);

    But it doesn't work and I have the same error.

    Do you think I'm ok now with EJBs specs by doing only Class.forName and Method.invoke ?
    I didn't see in the specs that this two actions where forbidden.


    I think the origin of the problem is that the implementation of the method java.lang.reflect.Method.invoke checks the parameters classes with the signature.
    So if the parameters are instantiated in ClassLoader 1 (client EAR) and the Method is instantiated ClassLoader 2 (Server EAR), the invoke implementation check results in :

    void invoke (Object aInstance, Object[] aParams) {
        for i in aParams
            if (!mParamSignature[i].isAssignable (aParams[i].getClass()) {
                throw new IllegalArgumentException ("...")
            }
        }
    etc ....
    }
    I've no means to coroborate this supposition since all the methods are native (Class.equals and Method.invoke).

    So if you think I'm okay with the specs, I'll ask IBM support for a bug report.

    I'm waiting for your answer, thanks.