0

I am having issues with the retrieval of beans using JNDI.

I have 2 ears: clientear and workerear. Clientear contains clientejb and libejb Workerear contains workerejb and libejb

The lib contains MyInterface The workerejb contains the bean and the abstract class and the clientejb contains the client code that performs the lookup.

My bean which implements a remote interface

public class MyBean implements MyInterface

Its JNDI binding is

java:global/jndinaming/MyBean!learning.jndinaming.MyInterface

That is OK.

Now I want it to extend an Abstract class:

public abstract  class MyAbstractClass implements MyInterface
public class MyBean extends MyAbstractClass

So the JNDI binding becomes

java:global/jndinaming/MyBean!learning.jndinaming.MyBean

That is ok, I adjusted the string and my code which was this:

(MyInterface) ctx.lookup("java:global/jndinaming/MyBean!learning.jndinaming.MyInterface");

Becomes this:

(MyInterface) ctx.lookup("java:global/jndinaming/MyBean!learning.jndinaming.MyBean");

And I get a Class Cast exception:

ClassCastException: Cannot cast MyBean$$$view68 (id=938) to MyInterface

The interface file is in a project which is accessible by both the client and worker project.

The client project contains the code that calls the lookup method.

The worker project has the bean implementation and abstract class.

The projects are in separate ear files but in the same wildfly container.

Why does adding the new "layer" with the abstract class causes this class cast exception? What can I do to solve it?

btw: trying to access using

 (MyInterface) ctx.lookup("java:global/jndinaming/MyBean!learning.jndinaming.MyInterface");

Results in a nameNotFound exception being thrown

Edit: this is the current status of the bean, Abstract class and interface:

interface:

import javax.ejb.Remote;

@Remote
public interface MyInterface {
    public void print();

}

Abstract Class:

public abstract  class MyAbstractClass implements MyInterface{

}

MyBean

@Stateless
public class MyBean extends MyAbstractClass{

    @Override
    public void print() {
        System.out.println("MyAbstractClassExtender.PRINT");

    }

}

Client code:

@Stateless
public class TimedBean {
    @Resource
    private SessionContext              ctx;

    @Schedule(second="*/10", minute="*", hour="*")
    public void run() throws NamingException{
            MyInterface c2 = (MyInterface) ctx.lookup("java:global/workerear/workerejb-0.0.1-SNAPSHOT/MyAbstractClassExtender!learning.lib.MyInterface");
        c2.print();
    }

}
JSBach
  • 4,679
  • 8
  • 51
  • 98

2 Answers2

1

Removing the @Remote from the interface and adding it to the bean solves the problem:

public interface MyInterface {
    public void print();

}

@Stateless
@Remote(MyInterface.class)
public class MyBean extends MyAbstractClass{

    @Override
    public void print() {
        System.out.println("MyAbstractClassExtender.PRINT");

    }

}

Then the JNDI binding will be this one:

java:global/workerear/workerejb-0.0.1-SNAPSHOT/MyBean!learning.lib.MyInterface

And the cast works.

JSBach
  • 4,679
  • 8
  • 51
  • 98
  • 1
    Took a while to get back, glad you got it working. Am guessing possibly the annotation processor looks at the "implements" to determine the remote/local interfaces (i.e If @Remote is on the interface and not the session bean). Its an interesting issue you raised. – Phuthib Jul 21 '15 at 11:39
0

The annotations processor checks the interfaces in the implements clause to determine the remote/local interfaces. Because the interface in this case is inherited and not explicitly defined in the implements clause, the annotations processor will assume the default behavior for your container.

One solution would be to add an implements to your Bean:

@Stateless
public class MyBean extends MyAbstractClass implements MyInterface{
    @Override
    public void print() {
        System.out.println("MyAbstractClassExtender.PRINT");

    }
}

Another as stated in your answer would be to declare the remote interface in your bean instead with:

@Stateless
@Remote(MyInterface.class)
public class MyBean extends MyAbstractClass{

    @Override
    public void print() {
        System.out.println("MyAbstractClassExtender.PRINT");

    }
}

There will be advantages and disadvantages for one method over the other. I found this blog very interesting http://piotrnowicki.com/2013/03/defining-ejb-3-1-views-local-remote-no-interface/

Phuthib
  • 1,326
  • 2
  • 13
  • 20