3

I have a setup of multiple Maven project, ultimately packaged as EAR archive. Those Projects are of the Type jar,ejb or war.

Now I have a javax.enterprise.context.SessionScoped CDI Bean, annotaded as javax.enterprise.inject.Default, carrying informations about the current User (Mainly retrieved from Shiro-Framework). I also have two autonomous Web applications, that are supposed to use this Bean, so I put the Bean in a Project, referenced by both Projects

My Problem now is, that I get an Exception during Deployment, telling me that the Bean could not be Injected, because there are two possible dependencies, referring to the exact same Class. I guess that's because the project containing the Bean (Jar Project) is attached to both Web-Projects, and the Bean therefor is discovered multiple times.

So here is my Question: Is there a well-known Strategy to deal with this kind of problem, or some means to signal the Application Server/ CDI Implementation (Glassfish 4.x in my case uses Weld Framework), to only read this once?

I did noticed that there is a possibility using javax.enterprise.inject.Instance, but I would like to not use that, because it is to crucial to the Application to allow the Possibility of variating Snapshots of the current operating User. I also thought about the approach to provide those Bean via an API and Implementation Project, referencing only the API as dependency, but that would create a vast overhead, since those projects currently would contain only one Class each.

This is my Beans Class Header:

package omega1001.mediaserver.domainmodel.web;

import ...;


@SessionScoped
@Default
public class OmegaMediaServerSubject implements Serializable {

This is how I try to inject my Bean:

@Inject
    private OmegaMediaServerSubject subject;

This is the Exception I get on Deployment:

org.jboss.weld.exceptions.DeploymentException: WELD-001409: Ambiguous dependencies for type OmegaMediaServerSubject with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private omega1001.mediaserver.servlet.messageProcessor.DefaultMessageProcessor.subject
  at omega1001.mediaserver.servlet.messageProcessor.DefaultMessageProcessor.subject(DefaultMessageProcessor.java:0)
  Possible dependencies: 
  - Managed Bean [class omega1001.mediaserver.domainmodel.web.OmegaMediaServerSubject] with qualifiers [@Default @Any],
  - Managed Bean [class omega1001.mediaserver.domainmodel.web.OmegaMediaServerSubject] with qualifiers [@Default @Any]
    at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:367)
    at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:281)
    at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:134)
    at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:155)
    at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:518)
    at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:504)
    at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:479)
    at org.jboss.weld.bootstrap.WeldStartup.validateBeans(WeldStartup.java:443)
    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:483)
    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:144)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
    at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:309)
    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:317)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:292)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1139)
    at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer.service(GrizzlyHttpContainer.java:375)
    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:206)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
    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:283)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:132)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:111)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:536)
    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:591)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571)
    at java.lang.Thread.run(Thread.java:745)
Cœur
  • 37,241
  • 25
  • 195
  • 267
Omega1001
  • 502
  • 6
  • 14
  • In my opinion it is not a good idea to share CDI beans accross different projects. I would rather refactor the user information into a separate project e.g. UserService, which provides a clear interface (e.g. JAX-RS) and can be consumed by both web applications. You will face less problems, if the web applications are self contained without dependencies to shared libraries. – simdevmon Apr 12 '16 at 12:05
  • 1
    This smells a lot like you have the jar containing the `OmegaMediaServerSubject` bean built both into the EAR as well as the WEB-INF/lib directory of one or both of your WAR files. You need to ensure that you have the maven-ear-plugin configured to build [skinny wars](https://maven.apache.org/plugins/maven-ear-plugin/examples/skinny-wars.html). – Steve C Apr 12 '16 at 14:18
  • @simdevmon Your Idea is similar to my API / Impl approach. But as I pointed out, that would be "a vast overhead, since those projects currently would contain only one Class each". Besides, it is mere chance that this is about providing User Informations. So I think this is a valid approach in general, but not exactly what I'm looking for. Thank you anyway – Omega1001 Apr 12 '16 at 15:43
  • @SteveC You're right, Maven packaged the Common Project along with both Web Projects. I'm going to verify this is the the answer to my problem and then formulate an Answer. Thanks for showing the Way. – Omega1001 Apr 12 '16 at 15:47

1 Answers1

0

I got this figured out now.

It was as Steve C pointed out:

The Project containing the Bean in question was packaged along with both Web Projects.

The easy Solution was to change the Dependencies Maven scope to provided in the Web Projects, and then provide it as library in the EAR.

So to answer my Question:

Yes, there is a well-known Strategy to deal with this kind of problem, by making sure, to provide the Project containing your shared Beans for the bigger picture, but never actually package the Project with any other Project besides your target EAR.

Thanks to Steve C, for giving Directions

Best regards,

J.Adam

Omega1001
  • 502
  • 6
  • 14