Maven : Remove duplicate jars from EAR - maven

We are using maven to build an EAR that contains WAR, the JARS are duplicated on both EAR's root and WAR's lib folder, I read about the skinny jars to remove the jars from the WAR but I don't want this as I want to keep the WAR as stand alone unit,
IS there a way to do it the other way around and remove the JARs from the EAR's root folder ?
attached is the EAR POM
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.6</version>
<configuration>
<modules>
<webModule>
<groupId>com.csv.xyz</groupId>
<artifactId>web</artifactId>
</webModule>
</modules>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.csv.xyz</groupId>
<artifactId>web</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>war</type>
<scope>compile</scope>
</dependency>
</dependencies>

The "maven-skinny-war" solution isn't any drawback in your case. Also have a look at this question and my answer: How to make maven place all jars common to wars inside the same EAR to EAR root?
With this solution you will first get WARs packaged with their own dependencies and second, an EAR module with skinny WARs. So everything is deployable on its own and nothing is duplicated.

I don't think this would be a good idea because of the class loader architecture. If a JAR is part of a WAR, it's defined by the web app class loader, which may result in multiple instances. If it's part of an EAR, it's defined by the enterprise app class loader, which is a different class loader.

To remove a dependency from the EAR lib folder, declare the dependencies as provided in the EAR pom, for example to remove commons-lang:
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
<scope>provided</scope>
</dependency>
</dependencies>
Just make sure if you have EJB modules that they don't require the dependency! Also webModules do not contribute to the EAR's root lib folder, do you have more dependencies in you ear pom?

Related

Add external library .jar to Spring boot .jar internal /lib

I have an external .jar that cannot be imported from public repositories using pom.xml, it's sqljdbc41.jar.
I can run the project locally from my IDE, and everything will work. I referenced the library after downloading it like so:
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc41</artifactId>
<version>4.1</version>
<scope>system</scope>
<systemPath>${basedir}/lib/sqljdbc41.jar</systemPath>
</dependency>
When I run mvn clean package to create my .jar file and try to run the created .jar, a mistake will pop up, which mentions the SQL Server references are not valid. I then extracted my .jar file and true enough, everything that is referenced in the pom.xml file properly gets downloaded and added, however, my SQL Server does not.
I can, in a very hacky way* just manually add the sqljdbc41.jar to my /lib folder after it's been compiled as a .jar, and it'll work, however that seems highly unoptimal. What would be a better approach?
*Opening the .jar file with Winrar, going to the /lib folder, manually selecting my sqljdbc41.jar file, then make sure to select the No Compression option bottom left where Winrar gives you compression options, in case you find this by Google and no one answered.
you can set 'includeSystemScope' to true.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
You could install the sqljdbc41.jar in your local repository :
mvn install:install-file -Dfile=path/to/sqljdbc41.jar -DgroupId=com.microsoft.sqlserver -DartifactId=sqljdbc41 -Dversion=4.1 -Dpackaging=jar
And then declare the dependency as a standard dependency :
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc41</artifactId>
<version>4.1</version>
</dependency>
If you use a remote artifact repository (nexus, archiva...) you also need to deploy the artifact on this repository. You can find more here : https://maven.apache.org/guides/mini/guide-3rd-party-jars-remote.html
Another way, you can put it into the resources folder, such as resources/lib/xxx.jar, then config the pom.xml like this:
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc41</artifactId>
<version>4.1</version>
<scope>system</scope>
<systemPath>${basedir}/src/main/resources/lib/sqljdbc41.jar</systemPath>
</dependency>
In Spring Boot: I also faced similar issue and below code helped me.
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.7.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>
It works for me:
project {root folder}/libs/ojdbc-11.2.0.3.jar
pom.xml:
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc</artifactId>
<version>11.2.0.3</version>
<scope>system</scope>
<systemPath>${basedir}/libs/ojdbc-11.2.0.3.jar</systemPath>
</dependency>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
In my case, the fault was providing a version number without "dot" in tag:
<dependency>
<groupId>jdk.tools</groupId>
<artifactId>jdk.tools</artifactId>
<scope>system</scope>
<version>1</version>
<systemPath>${basedir}/src/main/resources/lib/tools.jar</systemPath>
</dependency>
This one works:
<dependency>
<groupId>jdk.tools</groupId>
<artifactId>jdk.tools</artifactId>
<scope>system</scope>
<version>1.8</version>
<systemPath>${basedir}/src/main/resources/lib/tools.jar</systemPath>
</dependency>
When Spring-Boot projects are used with maven or gradle plugins they packaged the applicaiton by default as executable jars.
These executable jars cannot be used as dependency in any another Spring-Boot project because the executable jar add classes in BOOT-INF/classes folder. This means that they cannot be found when the executable jar is used as a dependency because the dependency jar will also have the same class path structure as shown below.
If we want to use project-A as a maven dependency in project-B then we must have two artifacts. To produce the two artifacts, one that can be used as a dependency and one that is executable, a classifier must be specified. This classifier is applied to the name of the executable archive, leaving the default archive for use as a dependency.
To configure a classifier of exec in Maven, you can use the following configuration:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>
So the MAJIC WORD here is <classifier>exec</classifier> this will create a jar structure as below and then it could easily be conusmed by spring-boot project as maven dependency jar on class path.
The above plugin need to be add in project-A pom that is going to be used as dependency in project-B. Same is explained in spring documentation section 16.5. as well.
In order to work through the local repository, the target .jar file that we will work with must be in the s2 folder. Several methods can be used for this:
The file can be taken manually and put in the relevant place (not
preferred). The same process can be done by installing it via the
console.
Relevant Remote URL is written in the .pom file dependencies and
automatically places it in the s2 folder when Intellij is refreshed
(validate) in the IDE used.
The same process can be done by addressing the .pom file dependencies via the centeral repository.
Attention: ComponentScan should not be forgotten for the related jar work on SpringBot.

Maven modify dependency jar manifest files

I'm sorry in advance I can't give the exact code as I don't have it at hand right now. However, I ran into a problem while trying to package my project into a jar. I used maven assembly plugin in my pom.xml to assemble all dependencies and project jar into one place. But now I need all of those dependency jars to have a custom manifest file. Is it possible to inject some properties with Maven itself somehow? Now the only solution I came up with is to use Maven's shade plugin and create an uber-jar, but the problem is that some of dependencies have custom manifests (like Spring framework ones) which gets lost and only one manifest is generated for the uber-jar. Is it possible to somehow tell maven to unpack dependencies, edit manifestEntries and pack them up again and assemble together with the project jar in a zip?
Long story short: basically what I want to find out, is would it be possibly to somehow modify a file inside one of the dependencies jar or in all dependency jars at once? Let's say my project has a dependency of spring-beans. Now I would like to modify a specific file inside spring-beans.jar, specifically manifest.md before I assemble them in one zip which should contain project.jar and spring-beans.jar (with a modified manifest.md). I think something similar is achievable with maven antrunner plugin?
Example:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>project</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Project</name>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/src.xml</descriptor>
</descriptors>
</configuration>
</plugin>
</plugins>
</build>
</project>
I want to modify manifest.md in spring-core.jar, spring-context.jar and spring-beans.jar. I know I can use shade plugin to make an uber jar which would have one manifest.md which I could edit within shade's configuration, but if it is possible to somehow modify specific dependency jars alone I think it would be more fool proof and I could use these libraries among several applets.

Multi-module maven build : different result from parent and from module

I am migrating an application from ant build to maven 3 build.
This app is composed by :
A parent project specifying all the modules to build
A project generating classes with jaxb and building a jar with them
A project building an ejb project
3 projects building war modules
1 project building an ear
Here is an extract from my parent pom :
<groupId>com.test</groupId>
<artifactId>P</artifactId>
<packaging>pom</packaging>
<version>04.01.00</version>
<modules>
<module>../PValidationJaxb</module> <-- jar
<module>../PValidation</module> <-- ejb
<module>../PImport</module> <-- war
<module>../PTerminal</module> <-- war
<module>../PWebService</module> <-- war
<module>../PEAR</module> <-- ear
</modules>
I have several problems which I think have the same origin, probably a dependency management issue that I cannot figure out :
The generated modules are different depending on if I build from the parent pom or a single module. Typically if I build PImport only, the generated war is similar to what I had with my ant build and if I build from the parent pom, my war took 20MB, a lot of dependencies from other modules had been added. Both wars are running well.
My project PWebService has unit tests to be executed during the build. It is using mock-ejb which has cglib as dependency. Having a problem of ClassNotFound with this one, I had to exclude it and add a dependency to cglib-nodep (see last pom extract). If I then build only this module, it is working well. But if I build from the parent project, it fails because other dependencies in other modules also had an implicit dependency on cglib. I had to exclude it in every modules pom and add the dependency to cglib-nodep everywhere to make it run.
Do I miss something important in my configuration ?
The PValidation pom extract :
It is creating a jar containing an ejb with interfaces generated by xdoclet, as well as a client jar.
<parent>
<groupId>com.test</groupId>
<artifactId>P</artifactId>
<version>04.01.00</version>
</parent>
<artifactId>P-validation</artifactId>
<packaging>ejb</packaging>
<dependencies>
<dependency>
<groupId>com.test</groupId>
<artifactId>P-jaxb</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.5.ga</version>
<exclusions>
<exclusion>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2.2</version>
</dependency>
...
[other libs]
...
</dependencies>
<build>
...
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<configuration>
<ejbVersion>2.0</ejbVersion>
<generateClient>true</generateClient>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>xdoclet-maven-plugin</artifactId>
...
The PImport pom extract :
It depends on both Jaxb generated jar and the ejb client jar.
<parent>
<groupId>com.test</groupId>
<artifactId>P</artifactId>
<version>04.01.00</version>
</parent>
<artifactId>P-import</artifactId>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>com.test</groupId>
<artifactId>P-jaxb</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.test</groupId>
<artifactId>P-validation</artifactId>
<version>${project.version}</version>
<type>ejb-client</type>
</dependency>
...
[other libs]
...
</dependencies>
The PWebService pom extract :
<parent>
<groupId>com.test</groupId>
<artifactId>P</artifactId>
<version>04.01.00</version>
</parent>
<artifactId>P-webservice</artifactId>
<packaging>war</packaging>
<properties>
<jersey.version>1.14</jersey.version>
</properties>
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.rte.etso</groupId>
<artifactId>etso-validation</artifactId>
<version>${project.version}</version>
<type>ejb-client</type>
</dependency>
...
[other libs]
...
<dependency>
<groupId>org.mockejb</groupId>
<artifactId>mockejb</artifactId>
<version>0.6-beta2</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>cglib</groupId>
<artifactId>cglib-full</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2.2</version>
<scope>test</scope>
</dependency>
</dependencies>
Many thanks
Solution after modification of the configuration :
When I got the projects already mavenized, it didnt respect the folder layout convention, but as it was declared in the pom where to find the sources, I thought it would be working.
Anyway, i changed it to match the recommended structure.
To build a single module I was executing mvn clean install directly at its level. It is this way I obtained a different result (which is in fact the one I wanted).
Anyway, my problem is solved, I put all the dependencies of the PValidation project as provided, as I am only including the generated client in other modules and they dont require all what is needed for the implementation.
But still I dont get why I had different result for the same configuration.
The first important thing is you should create the structure of your project appropriate to the modules structure which means having the following folder structure:
+-- parent
+-- PValidationJaxb
+-- PValidation
+-- PImport
+-- PTerminal
+-- PWebService
+-- PEAR
This means having a pom.xml which contains the modules definition in the parent folder.
if you follow the above recommendation you can simplify the modules list to the following:
<modules>
<module>PValidationJaxb</module> <-- jar
<module>PValidation</module> <-- ejb
<module>PImport</module> <-- war
<module>PTerminal</module> <-- war
<module>PWebService</module> <-- war
<module>PEAR</module> <-- ear
</modules>
Furthermore a best practice in Maven is to use lowercase artifacts which mean in your case pvalidationjaxb instead of PValidationJaxb.
An other important thing is your version which does NOT follow the Maven conventions. Furthermore your version will be from the Maven point of view a release which is not the case you are doing development on this. In Maven you should use a so called SNAPSHOT for such purposes like 1.0.0-SNAPSHOT.
I hope you have followed the folder layout recommendation of Maven which says to put production code (which will be packaged into the resulting jar) into src/main/java whereas test code into src/test/java.
The problem you described having different dependencies sounds weired. The question is how have you tried to build a single moduel? This can usualy be achieved by using the following from the parent location:
mvn -pl module clean package
The problem with your unit tests sounds like a missing dependencies etc. but here is the questions how have you tried to run the unit tests and have you configured maven-surefire-plugin ? Or do you have integration tests? This is only a guess cause i don't see any configuration of Maven plugins in your poms.

How to exclude jars from ear

I am bundling EAR from a WAR file. The JARS are placed both in WARFile/WEB-INF/lib folder as well as EARFile/lib folder with duplication.
Do we need the JARS again in EARFile/lib folder inspite of having in WARFile/WEB-INF/lib?
If we do not need in EAR/lib filder, How can we remove them? The EAR file size became double due to duplication JARs presence in both WAR and EAR.
Please help me.
Thanks
Good read here on "skinny" wars. Basically, you put the jars in the ear, but not the war files:
http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html
You have to define the dependency to your war project in the following way:
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>xyz-web</artifactId>
<version>${project.version}</version>
<type>war</type>
</dependency>
and furthermore you have to configure the ear plugin like the following:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<configuration>
<version>6</version>
<modules>
<!-- Register our War as a web module, and set the context root -->
<webModule>
<groupId>${project.groupId}</groupId>
<artifactId>xyz-web</artifactId>
<contextRoot>/xyz</contextRoot>
</webModule>
</modules>
</configuration>
</plugin>

creating war file using maven-ear-plugin and defining it in one pom.xml

I am at the starter level of the maven usage. I hope I can explain my problem clearly, I want to create an ear file which contains war file inside it. And I planned to use to create a war file from the start. Also I want to do it in my pom.xml at my project and there is only one pom.xml, here is the problem;
Can I create ear file and which contains this war that I created at the same time in one pom.xml file?
when I try to create war file in webmodule tag, here is the problem that I encounter " Artifact[war:denem.denem:denem] is not a dependency of the project." I understood so that's why I added dependency for this file in the same pom.xml but this time I encountered that problem
(By the way my command to build this pom is "mvn clean package" )
"1 required artifact is missing.
for artifact:
com.denem.denem:com.denem.de2:ear:v0.1"
It tries to find this war file but I want to create it not to find it. Here the code in my pom.xml file;
<parent>
<groupId>denem.denem</groupId>
<artifactId>com.denem.denem</artifactId>
<version>v0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>denem.denem</groupId>
<artifactId>com.denem.de2</artifactId>
<version>v0.1</version>
<packaging>ear</packaging>
<properties>
<cxf.version>2.2.5</cxf.version>
</properties>
<dependencies>
<dependency>
<groupId>denem.denem</groupId>
<artifactId>denem</artifactId>
<version>v0.1</version>
<type>war</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.5</version>
<configuration>
<finalName>edu</finalName>
<defaultLibBundleDir>lib</defaultLibBundleDir>
<modules>
<webModule>
<groupId>denem.denem</groupId>
<artifactId>denem</artifactId>
<contextRoot>/WebContent</contextRoot>
</webModule>
</modules>
</configuration>
</plugin>
</plugins>
</build>
I guess I am doing lots of things wrong. But If you can help me I will be glad. Thank you anyway.
You need to create a modular project.
Create:
a parent project of type "pom";
a child project of type "war";
if needed, child projects of type "ejb";
if needed, child projects of type "jar" (common libraries);
one project of type "ear", that has all of the above as dependencies.
In the latter you need to configure the ear plugin putting all the modules that you need.

Resources