Platform: JBoss AS 7.1.1.
I have a stateless bean method that needs to call another method of the same bean but has to go through the EJB container.
#Stateless
public class OrderManager {
#Resource
SessionContext ctx;
#Inject
MailUtil mm;
Logger logger = Logger.getLogger("Test");
public void method1() {
if (mm == null) {
logger.info("MailUtil is null");
}
ctx.getBusinessObject(OrderManager.class).method2();
}
#Asynchronous
public void method2() {
if (mm == null) {
logger.info("MailUtil is null");
}
}
}
Unfortunately, the injected variable mm is null within method2(). While, within method1(), a properly injected mm variable exists.
Is this a defect in JBOss, or am I doing something wrong? Thanks.
The same thing happened for me using WebSphere 8.5.5.5. The self injected bean had null in its injected beans.
The solution was to change the second method from private to public.
According to Pete Muir this is a bug, however, we're not sure if it's fixed or not. Trying a newer version of JBoss (build it from source) will work. If it's still an issue, please create a bug report.
Related
In the following case,
public class Base {
#Transactional
public void doSave() {
// ...
}
}
public class Inherited extends Base {
public void someMethod() {
super.doSave();
}
#Override
public void doSave() {
super.doSave();
}
}
If I add the #Transactional annotation to Inherited.someMethod, the interceptor gets called without issue.
However, without the annotation on the inherited class, the interceptor does not get involved in the call to the super class from Inherited.someMethod().
Furthermore, calling Inherited.doSave() does not seem to get the interceptor invoked either. I would have expected the annotation on the superclass to be also valid on the subclass. Is this not the expected behaviour?
I am using Apache DeltaSpike for the #Transactional annotation and this is being deployed as a war in an ear (technically as a jar in a war in an ear). However, this may not be relevant as trying with a custom interceptor shows the same behaviour.
This is JBoss EAP 6.3.0 Alpha in case its relevant.
This is expected. Interceptors are only applied if the object is managed. When you you write it this way with inheritence, it's not applied as it's not part of a call stack that CDI is aware of. You would need to inject Base into your class and call Base.doSave
I'm writing a course on EJBs on JBOSS AS 7 and I have some troubles.
I have a simple local stateless EJB :
#Stateless
public class CitationEJB {
String citation ="Hello Citation";
public String getCitation(){
System.out.println("getting citation from :"+this.toString());
return this.citation;
}
public void setCitation(String citation) {
System.out.println("changing citation to : "+citation);
this.citation = citation;
}
#PostConstruct
public void sayHello(){
System.out.println("Hello, I'm a new EJB");
}
}
Then I invoke a EJB via JNDI in a JSF ManagedBean :
#ManagedBean
#SessionScoped
public class CitationBean {
//#EJB trying this time with JNDI
CitationEJB ejb;
public String getCitation() throws NamingException{
ejb = lookupCitationEJB();
return ejb.getCitation();
}
public String getCitation2() throws NamingException{
ejb.setCitation("hello Toto");
CitationEJB ejb = lookupCitationEJB();
return ejb.getCitation();
}
private static CitationEJB lookupCitationEJB() throws NamingException {
Hashtable jndiProperties = new Hashtable();
jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
Context context = new InitialContext(jndiProperties);
String jndiName = "java:global/CitationsDyn/CitationEJB!com.citations.ejb.CitationEJB";
//jndiName = "java:app/CitationsDyn/CitationEJB"; // Works also
return (CitationEJB) context.lookup(jndiName);
}
}
Then I show up the CitationEJB.getCitation() with JSF. Everything works fine except that when I make F5, and so a new request, I always have the same object : when I use CitationEJB.setCitation("Hello toto"), then F5, I do have "Hello Toto" and not a brand new Object.
When I use the #EJB annotation to get the EJB, I have the expected behaviour with a new object for every request.
So what I learned is that the EJB is picked in a pool, but when is it destroyed ? I guess that the JNDI lookup is not bound to a Scope as is a JSF page. But how is it exactly specified ?
The lifecycle of a Stateless Session Bean is managed by the container. A number of instances will be created and placed in an instance pool when the EJB is deployed (for example JBoss 6 creates 10 instances by default). The number can scale up or down based on the demand. The EJBs are generally not destoryed after use, but rather put back in to the pool to be used again and again.
For your application where you want to keep state, a Stateful Session Bean would be the properly choice (or Single Session Bean if you wanted to share state between the instances). With a Stateful Session Bean, the application can cause the EJB to be destoryed by annotating a method with #Remove.
I'm struggling with CDI and class inheritence.
I've a JAX-RS controller declared as :
#Path("/share")
public class ControllerShare extends BaseController {
#Inject
private ServiceShare serviceShare;
#PostConstruct
private void verifInit() throws ExceptionTechnique {
log.warn("Checking CDI injection");
if (serviceShare == null) {
log.error("serviceAccount not initialized. Check your EJB configuration");
throw new ExceptionTechnique("serviceShare not initialized. Check your EJB configuration.");
}
}
...
}
This controller extends a base controller declared as :
public abstract class BaseController {
private Logger log = LoggerFactory.getLogger(ControllerShare.class);
#Context protected HttpServletRequest request;
#Inject private ControlerSession ctrlSession;
public BaseController() {}
#PostConstruct
private void verifInit() throws ExceptionTechnique {
log.warn("Checking CDI injection");
if (ctrlSession == null) {
log.error("controllerSession not initialized. Check your CDI configuration");
throw new ExceptionTechnique("serviceAccount not initialized. Check your CDI configuration.");
}
}
...
}
The problem is that injection is correctly done in ControllerShare (I correctly see "Checking CDI injection"), but is not done in the BaseController class (ctrlSession is null).
I try #Named and others combination without success. Injection is just done in ControllerShare and not in BaseController.
EDIT:
One more thing : curiously the #Context is working fine. My request is set and the value is correct.
Thank's for any explanation and solution.
Actually, this should work according to
http://docs.jboss.org/cdi/spec/1.0/html/inheritance.html
4.2. Inheritance of member-level metadata
Suppose a class X is extended directly or indirectly by the bean class of a managed bean or session bean Y.
If X declares an injected field x then Y inherits x.
On a side note: #PostConstruct however is not inherited if you specify it anew. Therefore, in your sub-class your method must be named differently to have both initializers executed.
If X declares an initializer, non-static observer, #PostConstruct or #PreDestroy method x() then Y inherits x() if and only if neither Y nor any intermediate class that is a subclass of X and a superclass of Y overrides the method x().
I've started playing with Wicket and I've chosen Guice as dependency injection framework. Now I'm trying to learn how to write a unit test for a WebPage object.
I googled a bit and I've found this post but it mentioned AtUnit so I decided to give it a try.
My WebPage class looks like this
public class MyWebPage extends WebPage
{
#Inject MyService service;
public MyWebPage()
{
//here I build my components and use injected object.
service.get(id);
....
}
}
I created mock to replace any production MyServiceImpl with it and I guess that Guice in hand with AtUnit should inject it.
Now the problems are:
AtUnit expects that I mark target object with #Unit - that is all right as I can pass already created object to WicketTester
#Unit MyWebPage page = new MyWebPage();
wicketTester.startPage(page);
but usually I would call startPage with class name.
I think AtUnit expects as well that a target object is market with #Inject so AtUnit can create and manage it - but I get an org.apache.wicket.WicketRuntimeException: There is no application attached to current thread main. Can I instruct AtUnit to use application from wicketTester?
Because I don't use #Inject at MyWebPage (I think) all object that should be injected by Guice are null (in my example the service reference is null)
I really can't find anything about AtUnit inside Wicket environment. Am I doing something wrong, am I missing something?
I don't know AtUnit but I use wicket with guice and TestNG. I imagine that AtUnit should work the same way. The important point is the creation of the web application with the use of guice.
Here how I bind all this stuff together for my tests.
I have an abstract base class for all my tests:
public abstract class TesterWicket<T extends Component> {
#BeforeClass
public void buildMockedTester() {
System.out.println("TesterWww.buildMockedTester");
injector = Guice.createInjector(buildModules());
CoachWebApplicationFactory instance =
injector.getInstance(CoachWebApplicationFactory.class);
WebApplication application = instance.buildWebApplication();
tester = new WicketTester(application);
}
protected abstract List<Module> buildModules();
The initialization is done for every test class. The subclass defines the necessary modules for the test in the buildModules method.
In my IWebApplicationFactory I add the GuiceComponentInjector. That way, after all component instantiation, the fields annotated with #Inject are filled by Guice:
public class CoachWebApplicationFactory implements IWebApplicationFactory {
private static Logger LOG = LoggerFactory.getLogger(CoachWebApplicationFactory.class);
private final Injector injector;
#Inject
public CoachWebApplicationFactory(Injector injector) {
this.injector = injector;
}
public WebApplication createApplication(WicketFilter filter) {
WebApplication app = injector.getInstance(WebApplication.class);
Application.set(app);
app.addComponentInstantiationListener(new GuiceComponentInjector(app, injector));
return app;
}
}
[UPDATE: After discussion on the Glassfish forums/ML at http://forums.java.net/jive/thread.jspa?messageID=480532 a bug was filed against Glassfish https://glassfish.dev.java.net/issues/show_bug.cgi?id=13040 for this issue.]
I'm trying to inject a local no-interface view of a #Stateless EJB into a JSF2 #Named #javax.enterprise.context.SessionScoped backing bean. The EJB is one of several that extend an abstract generic base class. Injection of "#Inject TheEJBClass varName" fails with "Unable to convert ejbRef for ejb TheEJBClass to a business object of type class my.package.name.TheAbstractBase". [edit: Actually, it turns out that injection succeeds, but method resolution in the injected proxy for methods inherited from superclasses fails.] If I use "#EJB TheEJBClass varName" then varName remains null, ie nothing is injected.
Details:
I'm running Glassfish 3.0.1 on Linux (Ubuntu 10.04 in case it matters) and having real problems handling injection of my data model EJBs into my JSF2 session scoped models using CDI (Weld). And yes, before you ask, I have beans.xml in place and CDI is activating to perform injection.
If I inject it with an #EJB annotation, eg:
#EJB TheEJBClass memberName;
... the EJB isn't actually injected, leaving memberName null.
If I inject it with a CDI #Inject annotation:
#Inject TheEJBClass memberName;
... then CDI complains when I call a method of "memberName" that's implemented in a superclass of TheEJBClass and not overridden in TheEJBClass its self, reporting:
java.lang.IllegalStateException: Unable to convert ejbRef for ejb TheEJBClass to a business object of type class my.package.name.TheAbstractBase
at
com.sun.ejb.containers.EjbContainerServicesImpl.getBusinessObject(EjbContainerServicesImpl.java:104)
at
org.glassfish.weld.ejb.SessionObjectReferenceImpl.getBusinessObject(SessionObjectReferenceImpl.java:60)
....
I've tried converting the base to concrete class and de-generifying it, but encounter the same problem, so I don't think I'm hitting the Weld bugs with generic bases (https://jira.jboss.org/browse/WELD-305, https://jira.jboss.org/browse/WELD-381, https://jira.jboss.org/browse/WELD-518).
An outline of the code, with full package qualification on annotations added for clarity, is:
// JSF2 managed backing bean.
//
// Called via #{someJSF2Model.value} in a JSF2 page
//
#javax.inject.Named
#javax.enterprise.context.SessionScoped
public class SomeJSF2Model implements Serializable {
#javax.inject.Inject TheEJBClass member;
public Integer getValue() {
return member.getValue();
}
// blah blah
}
// One of several EJB classes that extend TheAbstractBase
#javax.ejb.Stateless
public class TheEJBClass extends TheAbstractBase {
// blah blah
// does **NOT** override "getValue()"
}
public abstract class TheAbstractBase {
// blah blah
public Integer getValue() {
return 1;
}
}
Note that injection does work if I override TheAbstractBase.getValue() in TheEJBClass, or if I call a method defined in TheEJBClass and not any superclass. It seems like the issue is something to do with inheritance.
Very similar code that used JSF2's built-in lifecycle and injection features worked, but given that this is a new project and CDI is where things are heading in the future, I thought it best to try to go for CDI. Here's what I started out with using JSF2/EJB injection, which worked:
// JSF2 managed backing bean. Using #ManagedBean and JSF2's #SessionScoped
// instead of CDI #Named and CDI #SessionScoped this time.
//
#javax.faces.bean.ManagedBean
#javax.faces.bean.SessionScoped
public class SomeJSF2Model implements Serializable {
#javax.ejb.EJB TheEJBClass member;
public Integer getValue() {
return member.getValue();
}
// blah blah
}
// One of several EJB classes that extend TheAbstractBase
// Unchanged from CDI version
#javax.ejb.Stateless
public class TheEJBClass extends TheAbstractBase {
// blah blah
// does **NOT** override "getValue()"
}
// Unchanged from CDI version
public abstract class TheAbstractBase {
// blah blah
public Integer getValue() {
return 1;
}
}
I'm currently working on putting together a self-contained test case, but thought I'd fire off the question now in case this is something where I'm just doing something silly or there's a well known solution my Google-fu isn't up to finding. Why did it work with JSF2/EJB injection, but fail with CDI injection?
( Since re-posted on the Glassfish forums as http://forums.java.net/jive/thread.jspa?threadID=152567 )
As noted above, it's a Weld/glassfish bug.
Fix: Give up on Glassfish and move to JBoss AS 7, which actually works most of the time.