class cast exception in narrow a jndi reffrence in ejb

sara picture sara · Jul 25, 2011 · Viewed 14.9k times · Source

I am trying to write a simple stateless sesssion bean but I have problem with narrow reference I give in lookup time. I got

class cast exeption

I use

eclipse IDE

my bean class

package codes;
import java.rmi.RemoteException;

import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;


public class SinaBean implements SessionBean {


    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    public String getHello()
    {
        return "hello";
    }
    public void ejbCreate(){

    }
    @Override
    public void ejbActivate() throws EJBException, RemoteException {
        // TODO Auto-generated method stub

    }

    @Override
    public void ejbPassivate() throws EJBException, RemoteException {
        // TODO Auto-generated method stub

    }

    @Override
    public void ejbRemove() throws EJBException, RemoteException {
        // TODO Auto-generated method stub

    }

    @Override
    public void setSessionContext(SessionContext arg0) throws EJBException,
            RemoteException {
        // TODO Auto-generated method stub

    }

}

my home interface

package codes;

import java.rmi.RemoteException;

import javax.ejb.CreateException;
import javax.ejb.EJBHome;

public interface SinaHome extends EJBHome {

    public SinaObject create() throws RemoteException,CreateException;
}

my component

package codes;

import java.rmi.RemoteException;

import javax.ejb.EJBObject;

public interface SinaObject extends EJBObject {

    String getHello() throws RemoteException;
}

my client

package codes;

import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;

public class Client {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Context con=null;
        try {   
            Properties p=new Properties();
            p.setProperty(Context.INITIAL_CONTEXT_FACTORY,
            "org.jnp.interfaces.NamingContextFactory");
            p.setProperty(Context.PROVIDER_URL, "localhost:1099");
            p.setProperty(Context.URL_PKG_PREFIXES,
            "org.jboss.namingrg.jnp.interfaces");
            con = new InitialContext(p);
            Object o=con.lookup("SinaBean");
                       System.out.println(o);/***/untill know it works.it sysout : 
                       //org.jnp.interfaces.NamingContext@e83912*** 

            @SuppressWarnings("unused")
            SinaHome sh=(SinaHome)PortableRemoteObject.narrow(o, SinaHome.class);//***exeption is here!!***
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }

}

my xml file

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd">
  <display-name>Ejb </display-name> 
  <enterprise-beans>

  <session>

  <display-name>SinaBean</display-name>
  <ejb-name>SinaBean</ejb-name>
  <home>codes.SinaHome</home>
  <remote>codes.SinaObject</remote>
  <ejb-class>codes.SinaBean</ejb-class> 
  <session-type>Stateless</session-type>
  <transaction-type>Bean</transaction-type> 

  <security-identity>
  <description></description>
  <use-caller-identity></use-caller-identity>
  </security-identity> 

  </session>

  </enterprise-beans>

 </ejb-jar>

the exception I receive

java.lang.ClassCastException
    at com.sun.corba.se.impl.javax.rmi.PortableRemoteObject.narrow(PortableRemoteObject.java:229)
    at javax.rmi.PortableRemoteObject.narrow(PortableRemoteObject.java:137)
    at codes.Client.main(Client.java:27)
Caused by: java.lang.ClassCastException: org.jnp.interfaces.NamingContext cannot be cast to org.omg.CORBA.Object
    at com.sun.corba.se.impl.javax.rmi.PortableRemoteObject.narrow(PortableRemoteObject.java:212)
    ... 2 more

I will be extremely grateful for your advices.

Answer

Arjan Tijms picture Arjan Tijms · Jul 25, 2011

First of all, your xml file indicates you are using EJB3 (which is actually the only version even worth considering), but your bean is an EJB2 bean.

If your server indeed runs EJB3, remove the XML file and remove the needless EJB home and component implementations. Add the @Stateless annotation and a remote interface. Make sure it looks something like this:

@Remote
public interface SinaRemote {
    String getHello();
}

@Stateless
public class SinaBean implements SinaRemote {

    public String getHello() {
        return "hello";
    }
}

Then correct your JNDI properties. The following is wrong:

p.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.namingrg.jnp.interfaces");

it should be:

p.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");

(the variants people use here are almost endless and it basically always works anyway, but just to be sure use the correct variant)

Furthermore, and most likely the main culprit, you're using the ejb-name as-if it was a global JNDI name but this is not the case. The ejb-name is a somewhat confusing logical name that's used as an extra kind of qualifier when referring to a specific bean when injecting or creating an ejb-ref.

In your case you're setting it to the same as the unqualified bean name, which is already the default. Since SinaBean exists, I'm guessing you're not deploying via an EAR, but deploy a standalone EJB jar, right?

If you are using JBoss AS 6 (EJB3.1) you can use the global portable JNDI names, otherwise the old JBoss specific JNDI naming can be used: [ear name]/[simple bean name]/remote. Note that [simple bean name] is not the ejb-name, but again in your case they happened to be the same. Since [ear name]/ is removed when you're deploying only an EJB jar, this explains the exception you're getting: SinaBean is a directory (context in JNDI terms), which can contain the actual entries local, remote and no-interface. What you're doing is trying to cast this intermediate directory node to the proxy to your bean, which of course doesn't work.

Anyway, finally, remove the usage of PortableRemoteObject, this is no longer needed. The client code will then look like this:

Properties properties = new Properties();
properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
properties.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
properties.setProperty(Context.PROVIDER_URL, "localhost:1099");
context = new InitialContext(properties);
SinaRemote sina = (SinaRemote) context.lookup("SinaBean/remote");