Search code examples
javajakarta-eeannotationsejbjndi

EJB not "visible" to EJB manager. Cannot use CDI or JNDI to reference it


I have a weird problem that suddenly sprung up when I was trying to create a new EJB and inject it into another EJB so I could call its resources. I'm using Glassfish 3.1, and Java EE 6.

I've done this a couple of times before without problems in the same project, but for some reason this EJB causes deployment errors. As soon as I add the annotation

@EJB EJBname ejbname;

To the bean I want to reference it in and save I get a deployment server error.

server logs reveals:

Caused by: javax.naming.NameNotFoundException: com.bob.thrift.ThriftClient#com.bob.thrift.ThriftClient not found

javax.naming.NamingException: Exception resolving Ejb for 'Remote ejb-ref name=com.bob.logic.RSSbean/tclient,Remote 3.x interface =com.bob.thrift.ThriftClient,ejb-link=null,lookup=,mappedName=,jndi-name=com.bob.thrift.ThriftClient,refType=Session' . Actual (possibly internal) Remote JNDI name used for lookup is 'com.bob.thrift.ThriftClient#com.bob.thrift.ThriftClient' [Root exception is javax.naming.NamingException: Lookup failed for...

I don't know what that hash symbol # means or if I can confirm that that is the correct syntax. It looks like that is the correct package where my class exists, however.

I'm doing exactly what I did for the other EJBs they're all simple @stateless session beans. This seems to be analogous to a referenced library file not being listed in the buildpath. As if it has the name but it can't find the actual location. I'm not sure how to resolve this in the case of EJB injection.

Edit: The EJB with the stuff I need: package com.bob.thrift;

import com.bob.thrift.sendEventMessage2;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransportException;

import javax.annotation.ManagedBean;
import javax.ejb.Remote;
import javax.ejb.Local;
import javax.ejb.LocalBean;
import javax.ejb.Singleton;
import javax.ejb.Stateless;

@Stateless
@LocalBean

public class ThriftClient {

public ThriftClient(){} 

public String sendToServer(String say){
    System.out.println("Entering ThriftClient's main method starting server connection...");
    String msg;
    //**Make Socket**
    TSocket socket = new TSocket("137.222.23.23",1111);

    //**Make Buffer**
    //TSocket bufferedSocket = (socket); skipping this step because the jvm already handles
    //the buffering on this end. 

    //**put in protocol**
    TBinaryProtocol protocol = new TBinaryProtocol(socket);
    //**create client to use protocol encoder**
    sendEventMessage2.Client client = new sendEventMessage2.Client(protocol);

The EJB with the injection that causes deployment errors: package com.bob.logic;

import java.util.List;

import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.jws.WebService;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.bob.eao.XRSSeao;
import com.bob.thrift.ThriftClient;


 @Stateless
 @LocalBean
 //@WebService
public class RSSbean {

private String inputString;
private List Statuses;

@EJB private ThriftClient tclient;

As soon as I add the above line "@EJB ThriftClient tclient" it will not deploy and I get NameException, JNDI lookup, mapping null type of exceptions. It refuses to be found this way.


Solution

  • I'm not sure if you did it correctly with your ejbName. Suppose you have the following bean:

    @Stateless
    public class MrBean implements MrBeanInterface {}
    

    Then you need to inject the bean with @EJB annotation as following:

    @EJB
    private MrBeanInterface mrBean;
    

    Notice that the class is MrBeanInterface, not MrBean directly. Alternatively, if you use CDI and you have 2 implementation for the same interface, you can also inject a bean like this:

    @Stateless
    public class MrBean  implements BeanInterface {}
    
    @Stateless
    public class MrsBean implements BeanInterface {}
    
    @Inject
    @Exact(MrBean.class)
    private BeanInterface mrBean;
    

    UPDATE 1:

    This is from Oracle's tutorial:

    • Java EE application clients refer to enterprise bean instances by annotating static fields with the @EJB annotation. The annotated static field represents the enterprise bean’s business interface, which will resolve to the session bean instance when the application client container injects the resource references at runtime.

    Regarding What is EJB?, When to use EJB? and Benefits of EJB?, you can refer to this article.

    UPDATE 2:

    According to your update, your @LocalBean does not have any interfaces. This might have violated EJB 3.0's specs. In this Oracle's documentation, they mentioned:

    • When using the EJB 3.0 programming model to program a bean, you are required to specify a business interface.

    Besides, in this tutorial from IBM, they defined a No-Interface Local SessionBean as following:

    • The bean does not expose any other client views (Local, Remote, 2.x Remote Home, 2.x Local Home, Web Service) and its implements clause is empty.
    • The bean exposes at least one other client view. The bean designates that it exposes a no-interface view with the @LocalBean annotation on the bean class or in the deployment descriptor.

    In brief, I think you should still specify an interface for your ThriefClient even if you don't need to use it.

    @Stateless
    @LocalBean
    public class ThriefClient implements ThriefInterface {
       // Your  functions
    }
    
    @Local
    public interface ThriefInterface {
       // Empty interface
    }
    

    Alternatively, in EJB 3.1, you can try this:

    @Stateless
    public class ThriefClient {
       // Your  functions
    }
    
    @Stateless
    public class RSSbean {
        @EJB
        private ThriefClient thriefClient;
    }