Why is there a WELD-001408 even when the BeanManager knows the EJB
Asked Answered
W

2

9

When trying to deploy an ear we get the infamous WELD-001408 (see below for stacktrace).

Problem: It seems that WELD can't inject an EJB via @Inject into a CDI managed bean (!= @ManagedBean) in a lib/shared.jar. Why is this? Is there a standard that says this is not supposed work?

UPDATE I also had an ejb-jar.xml at the relevant location...

UPDATE2: I created a minimal versin on github

First the setup - my research/findings and more detailed questions at the end:

We are currently using Glassfish 4.1 => Weld 2.2.2.Final, but the error is the same using Payara 4.1.1.154 => Weld 2.2.16.Final, also Java EE 7

Layout of the ear

sample.ear
├── a-ejb.jar (contains AEjb.java + beans.xml + ejb-jar.xml)
├── b-ejb.jar (contains AnotherCdiIManagedBeanPojo.java + DummyEjb.java + beans.xml)
├── lib
|   └── shared.jar (contains ACdiManagedBeanPojo.java, AnotherCdiDependency.java + beans.xml)
└── META-INF
    └── application.xml (...)

In the shared.jar there is

public class ACdiManagedBeanPojo {
    @Inject
    private AEjb aEjb;

    @Inject
    private AnotherCdiDependency anotherCdiDependency;        
}

AEjb is an EJB residing in the a-ejb.jar

@javax.ejb.Singleton
@javax.ejb.LocalBean
@javax.enterprise.context.ApplicationScoped
public class AEjb {}

AnotherCdiDependency is another Pojo in the shared.jar

public class AnotherCdiDependency {}

The following class resides in b-ejb.jar

public class AnotherCdiManagedBeanPojo {
    @Inject
    private AEjb aEjb;
}

beans.xml (CDI 1.1)

<beans bean-discovery-mode="all"
   xmlns="http://xmlns.jcp.org/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd">
</beans>

ejb-jar.xml

<ejb-jar 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_1.xsd"
         version="3.1">
    <enterprise-beans>   
        <session>
            <ejb-name>AEjb</ejb-name>
            <ejb-class>com.xxx.ejb.AEjb</ejb-class>
            <session-type>Singleton</session-type>
        </session>
    </enterprise-beans>
</ejb-jar>

stacktrace

org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type AEjb with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject @Default private com.managed.pojo.ACdiManagedBeanPojo.aEjb
  at com.managed.pojo.ACdiManagedBeanPojo.aEjb(ACdiManagedBeanPojo.java:0)

    at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:370)
    at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:291)
    at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:134)
    at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:165)
    at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:529)
    at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:515)
    at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:490)
    at org.jboss.weld.bootstrap.WeldStartup.validateBeans(WeldStartup.java:419)
    at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:90)
    at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:225)
    at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:131)
    at org.glassfish.internal.data.ApplicationInfo.load(ApplicationInfo.java:328)
    at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:496)
    at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:219)
    at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:491)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:539)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:535)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:360)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2.execute(CommandRunnerImpl.java:534)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:565)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:557)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:360)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:556)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1464)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1300(CommandRunnerImpl.java:109)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1846)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1722)
    at org.glassfish.admin.rest.utils.ResourceUtil.runCommand(ResourceUtil.java:253)
    at org.glassfish.admin.rest.utils.ResourceUtil.runCommand(ResourceUtil.java:231)
    at org.glassfish.admin.rest.utils.ResourceUtil.runCommand(ResourceUtil.java:275)
    at org.glassfish.admin.rest.resources.TemplateListOfResource.createResource(TemplateListOfResource.java:133)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:151)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:171)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:152)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:104)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:387)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:331)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:103)
    at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:297)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:254)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1028)
    at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer.service(GrizzlyHttpContainer.java:365)
    at org.glassfish.admin.rest.adapter.RestAdapter$2.service(RestAdapter.java:316)
    at org.glassfish.admin.rest.adapter.RestAdapter.service(RestAdapter.java:179)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:201)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:175)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:561)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:565)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:545)
    at java.lang.Thread.run(Thread.java:745)
]]

Research and findings

  • Debugging Validator.validateInjectionPointForDeploymentProblems() I saw, that the BeanManager of lib/shared.jar had the instance of AEjb in his enterpriseBeans collection. At no time this collection is used for look ups of dependencies.
  • The injection of none-EJB classes (like AnotherCdiDependency) works fine in the classes of shared.jar
  • Injecting AEjb via @Inject into AnotherCdiManagedBeanPojo that resides in b-ejb.jar (read: toplevel / outside of /lib) works fine as well

My questions

  • My first question: Why can't the BeanManager inject the EJB even if it knows about it? Is there any standard that says shared libs can't be injected with "global" EJBs? If so where to find it?

  • What would be the "easiest" way out of this? Where easy means changing as little code as possible and not creating a big mess we'll have trouble with later on.

  • Bonus question: What is with this comment in BeanManagerImpl.getBeans(InjectionPoint injectionPoint) - where is this FAQ?

    We always cache, we assume that people don't use inline annotation literal declarations, a little risky but FAQd

PS: I have read the following and a lot other stuff concerning classloading, context and cdi and the special behaviour of different application servers concerning those topics - but still...

Disclaimer: No new was called during my research.

Wyck answered 3/12, 2015 at 11:51 Comment(14)
have you tried to add a ejb-jar.xml descriptor to the ejb jars?Peipus
@StefanHeimberg: Yes tried that as well - still the same problem - I will update the question with this information - thanks for the suggestionWyck
i have played a little bit around... can you clone github.com/StefanHeimberg/stackoverflow-34065368, build and deploy "parent/sample-app/target/sample-app-1.0-SNAPSHOT.ear" on your glassfish? and then have a look at the output. can you verify that all is working? AStartupEJB -> BApplicationCDIBean -> BEJBPeipus
and can you have also a look at the other branch "call_bejb_over_shared_cdibean"? is this your constellation? i get the "CDI deployment failure:WELD-001408: Unsatisfied dependencies" cause of "WELD-001474: Class com.sample.shared.SharedApplicationCDIBean is on the classpath, but was ignored because a class it references was not found: com.sample.b.ejb.BEJB". just to be sure that i can reproduce your situation...Peipus
ah... versions i used: Netbeans 8.1, Glassfish 4.1.1, Weld 2.2.13.Final, Java EE 7 Spec, Maven 3.0.5, JDK1.8.0_60Peipus
@StefanHeimberg: Thanks Stefan, yes the master variant works. But it is a little different from the actual situation, which is my fault - i started building a minimal show case yesterday evening and noticed in omitting some details (there is an interfaces involved) for an easier presentation I probably have hindered the process. That's also the reason why the error message from your faulty case does not match our error message. I'll provide the showcase during the next days - lesson learned for the next time: First the showcase then the bounty!Wyck
ok... its not a problem... thats the reason why i first try to reproduce the problem for myself before i answer something... (that was my lesson learned)...Peipus
btw,,, what is the reason for the shared library?? is the shared library used by the ejbs?? or is the shared library using the ejbs? if it is the second one, then i think that this "layering" is not the best... / or should be changed...Peipus
@StefanHeimberg: The shared library contains the client code for an external webservice that is to be integrated into an already existing webapp. The client also needs some initialization (hence [ad]Startup + [ad]Singleton) that I wanted to keep away from the webapp code. By now I've found a pure CDI way that works without EJB: rmannibucau.wordpress.com/2015/03/10/cdi-and-startupWyck
@StefanHeimberg: I added a minimal version here: github.com/bseiller/stackoverflow-34065368Wyck
have you tried it with "@EJB private IAEjb aEjb;" instead of @ Inject... with @ EJB you enforce to look for a EJB implementing the interfacePeipus
BTW. you could use Steve C's answer to get it working... but i think this is not according the java ee specification as he said. (not portable). i think there is something wrong in the architecture. have you the ability to refactor your application to solve this problem? i think this would be better for the future of your application.Peipus
@StefanHeimberg: No I haven't tried "@EJB private IAEjb aEjb;" yet but as I said in my previous comment by now the "@Startup @Singleton" initialization is replaced with a CDI variant which works out of the box, so it's fine. Portability is not such a big issue for us, but working against the specification might be a problem since the next update of Glassfish will come for sure... I'll test the "@EJB" and manifest solutions tonight just to be sure :)Wyck
@Peipus "@EJB" doesn't work, it stays null no matter what I do. Also I couldn't get the MANIFEST.MF hack to work - but the first half of Steven Cs answer is what I was looking for...Wyck
T
2

The rules for class visibility in EAR files are laid out in §8 of the Java EE Specification, v7.

In summary:

Each module in the EAR effectively gets it's own class loader.

The jars in the EAR/lib directory are considered to be in a single module for the purposes of class visibility. Classes in the EAR/lib module class loader are automatically made visible to all of the other modules (as described n §8.3).

The converse is not true. Classes in the other modules are not automatically accessible to those in the EAR/lib module.

Some Java EE implementations provide ways of getting around these restrictions (at the expense of making your application non-portable).

One possible solution is to move shared.jar into the root of the EAR and use manifest Class-Path entries in each jar to ensure access.

ie. the META-INF/MANIFEST.MF in shared.jar would then contain:

Class-Path: b-ejb.jar

If your ejb-jars need to see classes in the moved sample.jar then they would then need their own manifest class-path entries.

I think the jar needs to be moved because in my experience the following doesn't work.

Class-Path: ../b-ejb.jar
Turco answered 11/12, 2015 at 5:37 Comment(1)
The adaptation of the MANIFEST.MF did not solve the situation, but as mentioned before, we no longer need a "@Singleton @Startup" EJB but use the solution described here rmannibucau.wordpress.com/2015/03/10/cdi-and-startup to get our code initializedWyck
T
0

You should inject the EJB into the CDI bean using the @EJB annotation.

public class ACdiManagedBeanPojo {
  @EJB
  private AEjb aEjb;

  @Inject
  private AnotherCdiDependency anotherCdiDependency;        
}

Worked for me on your test application on GitHub and deployed successfully to Payara 4.1.154

Transfuse answered 7/1, 2016 at 18:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.