简体   繁体   中英

@EJB returns null

I'm new to JBoss and to J2EE. I'm attempting to contact a Singleton Bean with a Session bean. Long term, I want to cache some information in the Singleton bean, and if its not available, lookup the relevant information in a database. But first, I'm creating the simplest use case possible.

However, when I run this simple use-case (get an application counter) in Eclipse, I'm getting a null reference to the EJB, and I'm not sure where to turn next.

I'm running Eclipse Keplar, JDK1.7, JBoss AS 7.1, EJB 3.1

Here is the jsp file.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<jsp:useBean id="counter" class="com.bender.counter.Counter" scope="session"/>
<%-- <jsp:useBean id="counterBean" class="com.bender.counterbean.CounterBean" scope="application"/> --%>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Test Counter</title>
</head>

<body>
Hit Counter( <%=counter.getHitCount() %> )<br/>
<%-- Hit CounterBean( <%=counterBean.getHits() %> )<br/> --%>
</body>
</html>

Here is the first session bean

package com.bender.counter;

import com.bender.counterbean.CounterBean;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;

@SessionScoped
public class Counter {
    @EJB 
    CounterBean counterBean;

    private int hitCount;

    public Counter() {
        this.hitCount = 0;
    }

    public int getHitCount() {
        if (counterBean == null) {
            System.out.println("Failure");
            hitCount = -1;
        } else {
            hitCount = counterBean.getHits();
        }
        return hitCount;
    }

    public void setHitCount(int newHits) {
        this.hitCount = newHits;
    }
}

Here is the Singleton Bean

package com.bender.counterbean;

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;

@Startup
@Singleton
public class CounterBean {
    private int hits = 1;

    public CounterBean() {
        super();
        System.out.println("In constructor of CounterBean.");
    }

    @PostConstruct
    public void init(){
        System.out.format("In post Construct of CounterBean, hits( %d )%n", this.hits);
    }

    // Increment and return the number of hits
    public int getHits() {
        return hits++;
    }
}

Here is the output from the server.log. Note that the counterbean appears to register with jndi. Note also the commented out in the jsp. This was an attempt to contact the CounterBean from the jsp. That attempt was successful, so I think the CounterBean is successfully running in the server.

17:07:50,427 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-12) JBAS015876: Starting deployment of "Counter.war"
17:07:50,443 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-15) JNDI bindings for session bean named CounterBean in deployment unit deployment "Counter.war" are as follows:

    java:global/Counter/CounterBean!com.bender.counterbean.CounterBean
    java:app/Counter/CounterBean!com.bender.counterbean.CounterBean
    java:module/CounterBean!com.bender.counterbean.CounterBean
    java:global/Counter/CounterBean
    java:app/Counter/CounterBean
    java:module/CounterBean

17:07:50,458 INFO  [stdout] (MSC service thread 1-8) In constructor of CounterBean.

17:07:50,458 INFO  [stdout] (MSC service thread 1-8) In post Construct of CounterBean, hits( 1 )

17:07:50,474 INFO  [org.jboss.web] (MSC service thread 1-4) JBAS018210: Registering web context: /Counter
17:07:50,489 INFO  [org.jboss.as.server] (management-handler-threads - 83) JBAS018559: Deployed "Counter.war"
17:07:55,185 INFO  [stdout] (http-localhost-127.0.0.1-8080-1) Failure

Thanks for your help!

Injection only works, if the DI container (in JBoss it is weld) knows about the object. This normally happens because the container itself creates the instance. You may also pass an existing object to the container an let it inject all dependencies.

It looks like CDI injection into JSP pages does not work in JBoss AS 7:

Maybe you take a look at alternatives to JSP:

If you cannot switch to another technology, then you might have to do the injection yourself. Use the following method to let the CDI container performa all injections for the given object:

public static <T> void programmaticInjection(Class<T> clazz, T injectionObject) throws NamingException {
    InitialContext initialContext = new InitialContext();
    Object lookup = initialContext.lookup("java:comp/BeanManager");
    BeanManager beanManager = (BeanManager) lookup;
    AnnotatedType<T> annotatedType = beanManager.createAnnotatedType(clazz);
    InjectionTarget<T> injectionTarget = beanManager.createInjectionTarget(annotatedType);
    CreationalContext<T> creationalContext = beanManager.createCreationalContext(null);
    injectionTarget.inject(injectionObject, creationalContext);
    creationalContext.release();
}

Then call this method from your JSP:

<h3>Inject Test</h3>
          <%
                    MyBean myBean = new MyBean();
                    myBean.programmaticInjection(MyBean.class, myBean);
                    // now call a method on myBean that invokes the injected EJB
          %>
</body>
</html>

MyBean is here a simple JSF bean, similar to yours:

@Named("myBean")
@SessionScoped
public class MyBean implements Serializable {
    private static final Logger logger = LoggerFactory.getLogger(MyBean.class);
    private static final long serialVersionUID = 1L;
    private long taskId;
    @EJB
    private MyEjb myEjb;

After calling programmaticInjection() the @EJB annotated object will be injected.

I was able to resolve this problem by adding a JNDI lookup. I must have something not setup correctly within my JBoss AS 7.1 instance so that one bean can use the (default) JNDI, while the JSP pages have (full) JNDI access. Here is the updated (and cleaned up) code.

JSP

<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<jsp:useBean id="counter" class="com.bender.counter.Counter" scope="session"/>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Test Counter</title>
</head>

<body>
Hit Counter( <%=counter.getHitCount() %> )<br/>
</body>
</html>

Session Bean (note that the @EJB is commented out) package com.bender.counter;

import com.bender.counterbean.CounterBean;

import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.naming.InitialContext;
import javax.naming.NamingException;

@SessionScoped
public class Counter {
//    @EJB
    private CounterBean counterBean;
    {
        try {
            counterBean = (CounterBean) new InitialContext().lookup("java:global/Counter/CounterBean");
        } catch (NamingException e) { 
            e.printStackTrace();
        }
    }

    private int hitCount;

    public Counter() {
        this.hitCount = 0;
    }

    public int getHitCount() {
        if (counterBean == null) {
            System.out.println("Failure");
            hitCount = -1;
        } else {
            hitCount = counterBean.getHits();
        }
        return hitCount;
    }

    public void setHitCount(int newHits) {
        this.hitCount = newHits;
    }
}

And the Singleton Bean

package com.bender.counterbean;

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;


@Startup
@Singleton
public class CounterBean {
    private int hits = 1;

    public CounterBean() {
        super();
        System.out.println("In constructor of CounterBean.");
    }

    @PostConstruct
    public void init(){
        System.out.format("In post Construct of CounterBean, hits( %d )%n", this.hits);
    }

    // Increment and return the number of hits
    public int getHits() {
        return hits++;
    }
}

And here is the JBoss Console Output

16:21:55,740 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-12) JBAS015876: Starting deployment of "Counter.war"
16:21:55,888 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-1) JNDI bindings for session bean named CounterBean in deployment unit deployment "Counter.war" are as follows:

    java:global/Counter/CounterBean!com.bender.counterbean.CounterBean
    java:app/Counter/CounterBean!com.bender.counterbean.CounterBean
    java:module/CounterBean!com.bender.counterbean.CounterBean
    java:global/Counter/CounterBean
    java:app/Counter/CounterBean
    java:module/CounterBean

16:21:56,033 INFO  [stdout] (MSC service thread 1-7) In constructor of CounterBean.

16:21:56,033 INFO  [stdout] (MSC service thread 1-7) In post Construct of CounterBean, hits( 1 )

16:21:56,088 INFO  [org.jboss.web] (MSC service thread 1-15) JBAS018210: Registering web context: /Counter
16:21:56,093 INFO  [org.jboss.as] (MSC service thread 1-15) JBAS015874: JBoss AS 7.1.0.Final "Thunder" started in 2001ms - Started 185 of 258 services (72 services are passive or on-demand)
16:21:56,176 INFO  [org.jboss.as.server] (DeploymentScanner-threads - 2) JBAS018559: Deployed "Counter.war"
16:22:11,455 INFO  [stdout] (http-localhost-127.0.0.1-8080-1) In constructor of CounterBean.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM