Valid project structure in EAR - java

I have an application packed in .ear file. This is the structure:
EmployeeManager
|---EmployeeManagerEJB.jar
---src/ (1)
|---EmployeeManagerJSF.war/
---index.xhtml
---WEB-INF/
---classes/ (2)
---lib/
|---lib/
---EmployeeManagerIntegration.jar
---src/ (3)
I use CDI to inject to classes located in (2) EJBs which interfaces are in (3) and implementations are in (1). However CDI throws exception " Unsatisfied dependencies for type ...". I assume something is wrong with my EAR structure. What should I do to fix this thing up?

CDI does not work by default between sub-deployments as they do not use the same classloader.
You could try placing your CDI beans in the EAR/lib folder this may work
make sure all sub-deployments have beans.xml in them if they are using CDI
there is no reason for this to be an EAR deployment, you can put both jars in WAR/lib and things will work fine
You can define inter-sub-deployment dependencies by adding class-path values into meta-inf/manifest.mf (This is somewhat standard between containers, here's the wildfly example: https://docs.jboss.org/author/display/WFLY8/Class+Loading+in+WildFly)
Or you can rely on your container implementation and turn off sub-deployment isolation (For wildfly see the following: https://docs.jboss.org/author/display/WFLY8/Class+Loading+in+WildFly)
You could copy your CDI beans to each sub-deployment that use them

Related

stateless ejb in WAR > package to EAR > local ejb call

I have an ear which contains 2 war files and each war contains stateless ejb and jersey rest classes. The interfaces locate in commons.jar file. The EAR structure looks like this:
EAR
-- /lib/commons.jar
-- rest-1.war
-- stateless-ejb-1.java
-- jersey-rest-1.java
-- rest-2.war
-- stateless-ejb-2.java
-- jersey-rest-2.java
I am trying to use stateless-ejb-1 from stateless-ejb-2 with #Inject annotation but I get a CDI deployment failure:WELD-001408: Unsatisfied dependencies error during deployment time. When I use #EJB in stateless-ejb-2 then the ear is deployed but I get a remote lookup error while calling jersey-rest-2.
This are my method call chains:
jersey-rest-1 > stateless-ejb-1: works fine
jersey-rest-2 > stateless-ejb-2 > stateless-ejb-1: I get an ejb-1 lookup error
I do not want to use remote ejb call because everything is packaged in the same ear (I would like to use #Inject instead of #EJB) but it does not work.
I guess that if I pack stateless-ejb-1.java to a jar and put it under EJB/lib than it will work. But I do not want to create a new module in my project just to pack this one file to separated jar file.
What is the solution?
You need to move stateless-ejb-1 into an ejb-jar module in the EAR.
Classes in different WAR files are never visible to each other, even when built into an EAR file.

Pass the bean to a jar in lib folder

We got Java EE 7 project with the following structure:
app.ear
META-INF
application.xml
lib
framework.jar
webapp.war
core.jar
Framework.jar is our framework that uses some kind of command pattern.
This is how it works. Each command has it's own ejb attached to it that does all the business logic. This command ejb extends CommandEJB class that have an execute method.
For example, this is an example of a command ejb:
public class cmdCreateBookEJB<T extends cmdCreateBook> extends CommandEJB<T> {
#Override
public void execute() {
//do something
}
}
And in our framework, we also have CommandExecutorEJB that sets the appropriate ejb for the command and execute it.
Example:
CmdCreateBook cmdCreateBook = new cmdCreateBook();
cmdCreateBook.setEjb(cmdCreateBookEJB.class.getSimpleName());
commandExecutorEJB.execute(cmdCreateBook);
The problem is our framework, specifically CommandExecutorEJB(that is packed in framework.jar inside lib folder) needs to know about ejb's from core.jar, so it can handle the command. What actually happens in the framework is that the the specific command ejb(cmdCreateBookEJB) in my example is cast to CommandEJB and then it's execute method is called.
The question is how to make the framework know about command ejbs.
I know that one option is to specify am env-entry in ejb-jar.xml with the core jar module name, and then use #Resource in commandExecutorEJB to find the entry, and then use the JNDI lookup to find the resource that would be cast to CommandBean.
But, I would like not to use ejb-jar.xml as we're using ejb 3.2 and ejb-jar.xml isn't necessary anymore.
EDIT:
To better explain here is how the jndi lookup string would look like for my example: java:app/core.jar/cmdCreateBookEJB
Because framework isn't and shouldn't be aware of the core.jar(The name core.jar name is just an example, someone could name it BookStoreCore.jar), I somehow need to pass module name(in my example core.jar), so that the framework know where to look for classes to find a specific command EJB, in my example cmdCreateBookEJB.
I know that I can use an env-var in ejb-jar.xml to pass module name to the framework. Here's an example:
<session>
<ejb-name>CommandExecutorEJB</ejb-name>
<ejb-class>com.mypackage.CommandExecutorEJB</ejb-class>
<session-type>Stateless</session-type>
<env-entry>
<env-entry-name>com.mypackage.CommandExecutorEJB/moduleName</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>core</env-entry-value>
</env-entry>
</session>
But, I would love to eliminate ejb-jar.xml from our project setup
You're using Java EE 7.
You can completely avoid class visibility problems by putting everything in your WAR file. core.jar and framework.jar can both be added to your WEB-INF/lib directory.
You can then directly inject EJBs where ever they're needed.

Glassfish 3 EJB Injection from the jar archive fails

I have a strange problem with EJB injection in the glassfish 3. Maybe I just not completely understand what I do :)
So this is a problem: My project consists of 2 modules that will be assembled with gradle.
Module A
Module B
Module A is a usual glassfish module that also works fine. Module B contains general purpose staff. Module B is also a dependency of A. Module A will be deployed to glassfish as a *.war archive and Module B is in the appropriate lib folder as *.jar archive:
module-a.war and somewere inside of it ../lib/module-b.jar
What I want is: Create in the Module B a "general purpose" stateless bean and use it in the Module A. But it doesn't work...
In the Module B I created a bean:
#Stateless
public class GeneralPurposeBean {}
and I try to use it in the Module A as follows:
...
#EJB
private GeneralPurposeBean genPurpBean;
...
So how I already mentioned the GeneralPurposeBean is in the *.jar
Each time when I try to use the bean it fails with following exception:
javax.ejb.CreateException: Could not create stateless EJB
When I move the bean to the Module A it works fine but I want share this bean with other modules, that will be developed in the future. Can someone explain to me what is wrong here? So the bean will be recognized but it can't be created. What I found out through debugging is that
JCDIServiceImpl#_createJCDIInjectionContext
Doesn't recognize the bean as an enterprise bean. So everything in the *.war that directly accessible will be properly created but not what lies in the *.jar's.
For the case someone has the same problem:
If you treat one of your modules as a dependency and this module contains EJB beans you want be injected the solution for my problem was to put /META-INF/beans.xml file into the module. Otherwise container doesn't recognize the beans as EJB.
That's it.

Annotation-specified bean name conflicts with existing, non-compatible bean definition

I'm using Spring 2.5.4 and am creating a Java application that I'm deploying onto Weblogic.
I have a class in an external library (which included in the WEB-INF/classes directory of the resulting WAR file of my application) that I want to use in my code. I've created an instance variable for an object of the class in my code and added the #Autowired annotation and a getter and setter. In my application context file I have declared a bean of the library class' type and added the following:
<context:annotation-config />
<context:component-scan base-package="com.mycompany" />
... in order to register an AutowiredAnnotationBeanPostProcessor that will scan the classes and process the annotation.
When I try and deploy the application, I get the following error:
java.lang.IllegalStateException: Annotation-specified bean name 'myBean' for bean
class [com.mycompany.package.ClassName] conflicts with existing, non-compatible
bean definition of same name and class [com.mycompany.otherPackage.ClassName]
I think this is because there's a class in the library which has the same name as one in my application code (both class' package names start with "com.mycompany"). Nb. this is NOT the class that I have added, but a different one. Is there any way I can circumvent this problem without changing the name of the class in my application?
Thanks for any assistance.
Old question but throwing my 2c of bad experience with similar problem.
If you have 2 classes with same name, but in different packages was there a time when you had your other class referenced by the failing Spring context? If so, I'd recommend to clean the AS cached files (typically the place where the WAR is extracted), clean/rebuild your WAR and deploy again. Restarting the app server is also recommended.
I found that application servers and web containers alike (Weblogic, WAS, Jboss, Tomcat) tend to leave behind the old classes and when application is deployed those stale .class files are loaded in JVM via some old references, which most of the time messes up the Spring context loader.
Typical scenario is when you have renamed/moved a class from one package to another, or even kept the package name the same but moved it to another module (jar). In such cases cached (left over) files in the AS work directory can cause big headaches. Wiping out the work directory in your AS should resolve the issue outright.
You should use #qualifier to avoid this kind of conflict please refer section 3.9.3.
I fixed the problem by removing the autowiring completely and accessing the bean by explicitly creating a reference to it through the application context and the getBean() method.
This would better fit as a comment to #Pavel Lechev's answer, but I don't have enough rep to comment yet.
For other's finding this, here's what I did to solve this problem. I am using Wildfly 9.0.2.Final and, IntelliJ IDEA 2016.1.3 Build #IU-145.1617. These steps should presumably work with JBoss as well.
Stop Wildfly server.
Navigate to $WILDFLY_HOME/standalone/. Delete the three following folders: lib/, log/ and temp/.
In IntelliJ, Build > Build Artifacts > All Artifacts > Clean (or just the artifacts you are deploying).
In IntelliJ, Build > Rebuild Project
Restart Wildfly and redeploy your artifact(s).
These steps remedied my issue of duplicate bean names detected in the Spring context after refactoring a package name upstream from a couple of Controllers.

Importing Spring beans from other Maven modules inside a WAR?

I have a new web app that is packaged as a WAR as part of a multi-module Maven project. The applicationContext.xml for this WAR references beans that are imported from the "service" module, which in turn imports beans from the "dao" module. The import statement in applicationContext.xml looks like this:
<import resource="classpath*:service.xml" />
and the one inside the service.xml file looks like this:
<import resource="classpath*:dao.xml" />
Neither Spring STS, nor Eclipse show any warnings or errors in my bean files. I reference the imported beans all over the place. The Maven build works fine and the DAO integration tests all pass (they use the beans). I don't have any service integration tests yet.
But when I start up the WAR in Jetty I get an error:
Error creating bean with name 'securityService'
Cannot resolve reference to bean 'userDAO' while setting constructor argument
All of the imported bean XML files can be found inside their respective JAR files in the WEB-INF/lib directory. Indeed, the service bean that threw the error is itself defined inside the service.xml file inside the service module's JAR file.
Apparently the service module can't find the bean that it imported from the dao module. Obviously I don't understand something...seems like this should this Just Work?
I enabled DEBUG logging for 'org.springframework' in order to see if I could learn anything. What I found were messages to the effect that the DAO beans had been created, but there was also a message about them having no name or id.
I check the file, and they all did have an id. So what was it? I check the XML namespace and saw:
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"
and noticed it was old (I am using Spring 3.0.2) and changed it to:
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
Once I changed it, Spring instantly threw half a dozen errors regarding beans that were defined incorrectly (but never used apparently). Once I fixed those errors, everything Just Worked. I've since gone through the entire system checking Spring XML file namespace versions.
Thanks to all for the help. Can't believe I wasted a day on this stupidity!!
The difference between the classpath:thingy.xml and classpath*:thingy.xml notation is that the former uses the standard classpath mechanism to resolve one resource (using ClassLoader.getResource(name)), whereas the latter will use ClassLoader.getResources(name) to retrieve all matching resources on the classpath, a distinction that should be irrelevant in your situation as I guess there is only one dao.xml file on the class path.
I think your problem is different, you are missing a leading slash.
Use this for a single resource
<import resource="classpath:/dao.xml" />
and this for multiple resources
<import resource="classpath*:/dao.xml" />
See
Spring Reference: The classpath*
prefix
Sun JavaDocs: ClassLoader
It should be like
<import resource="classpath:service.xml"/>
Are you having multiple applicationContexts and possibly the parent context is referring to a bean defined in the child context?

Categories

Resources