Move All Dependencies in EAR to Subfolder in Maven - java

I am currently building an EAR file in Maven. When I build it, I get the following in my target folder:
-target/
-MyProject.ear
-MyProject/
-MainProject.jar
-Dependency.jar
If I open up MyProject.ear in 7Zip, I see the same file structure that exists in MyProject/
I have been asked to change this so that all dependencies are in a subfolder, like this:
-target/
-MyProject.ear
-MyProject/
-MainProject.jar
-lib/
-Dependency.jar
Now I can make this work for the one dependency by making the following change to my pom.xml file:
<build>
[...]
<plugins>
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<version>2.9</version>
<configuration>
<modules>
<jarModule>
<groupId>Dependency</groupId>
<artifactId>Dependency</artifactId>
<bundleDir>lib</bundleDir>
</jarModule>
</modules>
</configuration>
</plugin>
</plugins>
</build>
However in the real project, I have about 30 dependencies. I could manually add a <jarModule> tag for each and every dependency, but ideally I would like for it to automatically move all of the dependencies to a subdirectory (making an exclusion for MainProject.jar).
I had hoped that I could declare <jarModule> once and use wild card characters for the groupId and artifactId, like Maven allows with exclusions:
<!-- Moving all for the time being, add the exclusion if it works -->
<jarModule>
<groupId>*</groupId>
<artifactId>*</artifactId>
<bundleDir>lib</bundleDir>
</jarModule>
I would expect the above to take all artifacts and put them into a lib folder. Unfortunatley, this doesn't seem to work in Maven 3.2.1, providing an error saying that Artifact[jar:*:*] is not a dependency of the project
So how can I move all of my dependencies to a subfolder when building an EAR in Maven?

You should move the bundle directory restriction under your maven-ear-plugin build configuration as below:
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>${maven-ear-plugin.version}</version>
<configuration>
<modules>
<jarModule>
<groupId>${group_id}</groupId>
<artifactId>${artifact_id}</artifactId>
<bundleDir>lib</bundleDir>
</jarModule>
<webModule>
...
</webModule>
</modules>
<defaultLibBundleDir>/lib</defaultLibBundleDir>
</configuration>
</plugin>
</plugins>
Hope it helps.

Thanks to a happy accident of failing to fully clean up my pom file after a test, I discovered how to do this.
In the <configuration> tag, add <defaultLibBundleDir>/lib</defaultLibBundleDir>. This will put all modules by default in a lib folder in a root of a directory. No wildcards are needed; in fact, Maven doesn't support wild cards in this part, probably because there are no clear bounds (it could be interpreted as "move all artifacts ever"). Wild cards only work for exclusions because there are clear bounds; it's a subset of a clearly defined set of artifacts.
If you'd like to make an exception, then you specify the module and type in <bundleDir>/</bundleDir>, which will place it back in the root. The full XML looks like this:
<build>
[...]
<plugins>
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<version>2.9</version>
<!-- All dependencies not otherwise specified are going in /lib -->
<defaultLibBundleDir>/lib</defaultLibBundleDir>
<modules>
<jarModule>
<!-- An exception to keep the main project in the root -->
<groupId>MainProject</groupId>
<artifactId>MainProject</artifactId>
<bundleDir>/</bundleDir>
</jarModule>
</modules>
</configuration>
</plugin>
</plugins>
This results in the original goal of putting all dependencies in a lib folder except for MainProject.jar:
-target/
-MyProject.ear
-MyProject/
-MainProject.jar
-lib/
-Dependency.jar

Related

Maven jandex plugin does not generate index for local custom maven repositories (sometimes)

I have a multi module maven project wie quarkus modules and some custom libraries which are local maven repositories (so they can be used by the other maven projects/modules). However, so that local maven repositories are recognizable und usable by your other local maven projects, you have to manually index them for some reason. I.e. add a config like this for quarkus index to the application.properties of the project including the local maven repo dependency:
quarkus.index-dependency.<index-name>.group-id = <group-id-of-local-maven-repo>
quarkus.index-dependency.<index-name>.artifact-id = <artifact-id-of-local-maven-repo>
The problem is, this causes issues for me becausse if you have 3 layers of project dependencies, say:
Project A (custom local maven repo library)
Project B (custom local maven repo library, includes Project A dependency)
application.properties (indexing Project A library dependency)
Project C (Local maven project for an end product, includes Project B
library dependency - and through it indirectly Project A).
application.properties (indexing Project B library dependency and config for datasources or other app related things)
Then when you generate an uber-jar (fat jar) of Project C for deployment, it for some reason uses application.properties of Project B in the packaged jar, instead of from the project which im building (Project C). Thus, the app is missing key configs and does not work. Maven seems to use an inverse priority here, which i dont know if thats a bug or not. When i asked about this, i was simply told that:
"My dependencies should not have application.properties".
I tried to find a way to prevent manual indexing via application.properties and found the maven jandex plugin - which is supposed to generate an index. The next problem is, this seems to only work in some projects but not in others in the dependency hierarchy, resulting in the same situation as before, and i don't understand why. This is the pom.xml config for the plugin i have included in all 3 projects (the entire pom.xml for all is too long, so let me know if you need more info):
<properties>
...
<jandex.skip>false</jandex.skip>
...
</properties>
...
<build>
...
<plugin>
<groupId>io.smallrye</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>3.0.5</version>
<inherited>true</inherited>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
<configuration>
<skip>${jandex.skip}</skip>
</configuration>
</plugin>
...
The odd thing is, this works to the extend that i no longer have to index Project B library dependency in Project C application.properties, but Project B library dependency still has to manually index Project A library dependency - thus rendering the entire exercise futile. Project C having an application.properties was never the issue, and is obviously needed. Project B still requires a properties file to point to Project A now, how do i solve this?
I have a parent module POM in the root folder containing all these projects, over which this maven jandex dependency is distributed to all modules, so it looks like this:
Maven parent module (contains all dependencies and versions used by all project sub modules)
Project A (custom local maven library repo), own pom.xml with inheritance from parent module
Project B (custom local maven library repo, includes Project A library), own pom.xml with inheritance from parent module
application.properties - Indexes Project A dependency manually, this is the problematic one which needs to go!
Project C (Local maven project for REST API etc., includes Project B library), own pom.xml with inheritance from parent module
pom.xml (parent module POM, containing maven jandex dependepency among others)
Edit: One of the projects, "entity", where all the database access objects are stored, does not run the jandex plugin during mvn clean install. This is the POM of the project:
<?xml version="1.0" encoding="UTF-8"?>
<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.compamny.project</groupId>
<artifactId>entity</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm</artifactId>
<version>2.16.1.Final</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator</artifactId>
<version>2.16.1.Final</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
<version>2.16.1.Final</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.13.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.smallrye/jandex-maven-plugin -->
<dependency>
<groupId>io.smallrye</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin>
<groupId>io.smallrye</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>3.0.0</version>
<inherited>true</inherited>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
When i force the execution of the jandex goal with mvn io.smallrye:jandex-maven-plugin:3.0.0:jandex it creates an META-INF/jandex.jdx file, but it does not produce one when i run mvn clean install. This is not a solution since i need to build the project, run the jandex plugin and install it into my local repositories separately. Also, notice that im using the "io.smallrye" version of the jandex plugin since the "org.jboss" version seems to not work at all.
I figured it out. The jandex plugin was set in the <pluginManagement> section of the POM configuration, which made it not run on mvn clean install. I had to move it to the plugins section so it gets executed. Thanks #Ladicek for making me look closer and keep trying!

JAR under EAR(src/main/application/lib) are not part of ClassPath in Maven - [Resolved]

I am working on converting a J2EE application to Maven where the EAR project will contain a WAR module. I have followed the below URL to convert the project and it does work with some minor changes:
https://www.ibm.com/docs/en/wasdtfe?topic=projects-converting-existing-maven
In the current project, there are some libraries under the EAR folder which I cannot move to the local maven repository. The reason is old legacy code which expects these library names to be intact (myCommon.jar and no version to be added like myCommon-1.0.jar).
As a workaround, I placed these libs under EAR->src->main->application->lib folder. There is no build failure observed but the major problem is with the ClassPath for these EAR lib files as shown below:
[err] java.lang.ClassNotFoundException: com.myClass.classFromWAR
[err] at java.lang.Class.forNameImpl(Native Method)
[err] at java.lang.Class.forName(Class.java:332)
E.g. myCommon.jar contains code like the below:
public void EARLibFunc( string classNameFromWAR){
.........
//E.g. classNameFromWAR = "com.myClass.classFromWAR";
final Class warClass = Class.forName( classNameFromWAR );
.........
}
Calling above function from the java files inside WAR module reports ClassNotFoundException: EARLibFunc("com.myClass.classFromWAR");
The directory structure looks like the below:
WARProject
-src
----com
--------myClass
------------classFromWAR.java
EARProject
-src
----main
--------application
------------lib
----------------myCommon.jar
The jar files from EAR/src/main/application don't seem to be part of the ClassPath.
Can you please suggest the best practice to handle such an issue? What should be the correct layout of the EAR libraries to make it part of the ClassPath? Please be informed that the code from the EAR libraries cannot be changed (legacy code dependency issue).
For reference here are my pom settings:
WARProject pom.xml:
.......
.......
<groupId>MyApp</groupId>
<artifactId>MyApp</artifactId>
<version>3.5</version>
<packaging>war</packaging>
<description>MyApp Maven</description>
........
<build>
<resources>
<resource>
<directory>Java Source</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<warSourceDirectory>Web Content</warSourceDirectory>
</configuration>
</plugin>
</plugins>
</build>
......
EAR Project pom.xml (contains WAR module as dependency):
.....
<groupId>EARProject_EAR</groupId>
<artifactId>EARProject_EAR</artifactId>
<version>3.5</version>
<packaging>ear</packaging>
<description>My Project EAR</description>
<build>
<plugins>
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<version>2.10</version>
<configuration>
<version>7</version>
<skinnyWars>true</skinnyWars>
<defaultLibBundleDir>lib</defaultLibBundleDir>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>MyApp</groupId>
<artifactId>MyApp</artifactId>
<version>3.5</version>
<type>war</type>
</dependency>
</dependencies>
......
SOLUTION:
The crash reported for the CLASSPATH is resolved. Since I am moving an old legacy application to Maven, there were some old references to be cleaned-up. Below changes were required:
There were duplicate classpath references in the eclipse Project
(Project -> Properties -> Java Build Path). Even though I had
dependencies mentioned in the pom.xml of the WAR file, the project
properties were also having its references. This may or may not be
the real reason.
Reverted earlier workaround solution. Removed libraries from
EAR->src-main->application->lib and added those as dependency in the
WAR pom.xml reference. Though it has re-created other legacy issue
but I believe this will adhere to the best practices.
I think, it should be possible this way:
Install the jar in your local maven repository.
Configure the maven-ear-plugin to include third party libraries as shown here.
Add <bundleFileName>myCommon.jar</bundleFileName> to jarModule in order to give your JAR file the desired name within the EAR.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>3.2.0</version>
<configuration>
[...]
<modules>
<jarModule>
<groupId>artifactGroupId</groupId>
<artifactId>artifactId</artifactId>
<includeInApplicationXml>true</includeInApplicationXml>
<bundleFileName>myCommon.jar</bundleFileName>
</jarModule>
</modules>
</configuration>
</plugin>
</plugins>
</build>
More information can be found at the usage page of the plugin.

How can I remove maven dependency jar in Eclipse

I'm really new to Maven and just converted my app-engine project to a Maven project.
I've added dependencies in the pom.xml file in order to get rid of the errors.
but now I get in my code
The method getPart(String) is undefined for the type HttpServletRequest
So after doing a bit of research on Stack Overflow it appears I need to have a single and updated package of servlet-api to make that work properly.
Apparently I may have a conflict with an older version that is in my Maven dependencies but I never added it in the pom.xml and now I'm stuck with this jar not knowing why it is imported and how I can delete it.
Here is my pom.xml:
<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>my-project</groupId>
<artifactId>my-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<webResources>
<resource>
<directory>${basedir}/src/main/webapp/WEB-INF</directory>
<filtering>true</filtering>
<targetPath>WEB-INF</targetPath>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>appengine-maven-plugin</artifactId>
<version>1.3.1</version>
<configuration>
<deploy.promote>true</deploy.promote>
<deploy.stopPreviousVersion>true</deploy.stopPreviousVersion>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.mailjet</groupId>
<artifactId>mailjet-client</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>com.google.appengine.tools</groupId>
<artifactId>appengine-gcs-client</artifactId>
<version>0.8</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
and here are images of what I get in Maven dependencies in my build path.
my guess is that the error comes from having a 2.5 version of the servlet-api.
So any help is greatly appreciated, I saw something about the exclusion
tag but don't even know where to put it as it doesn't look like anything in the pom.xml is asking for this jar.
You'd better open in Eclipse your pom.xml file and switch to the "dependency hierarchy" tab. Look for the undesired library (type in "serlvet" in the filter) and add exclusion on it through the context menu. This will modify your pom.xml file.
Delete project from workspace and don't check Delete project content on disk. Delete the jar from .m2 folder as well. Import the project using eclipse. Open the pom file and click on dependency Hierarchy. Select the the jar you want to delete. Right click and click on Exclude Maven Artifact. Next time you run the proejct it will not download the jar.

Classloader with Maven built jar

I am working on a project which contains a number of subprojects. The structure is something like Project 1, Project 2 and ProjectClassLoader.
Using separate configuration files, I pass in the binary names of the classes from Projects 1 and 2 that need to be loaded each time as arguments to the ProjectClassLoader project.
The ProjectClassLoader gets a handle to the system classloader
ClassLoader loader = ClassLoader.getSystemClassLoader();
which in theory allows it to load any classes which are contained in the classpath.
I'm using Maven to build the projects and handle their associated dependences. Thus each project has it's own individual pom.xml file. The ProjectClassLoader defines a parent pom.xml over Projects 1 and 2 which inherit from this. The parent pom contains dependency entries for both Project 1 and 2.
My understanding was that any dependencies specified in the pom.xml files of these projects would get added to the classpath at runtime. However when trying to load classes using the system classloader, I'm getting class not found execptions.
I have tried using the mvn:exec plugin which I understand includes the dependencies in the classpath when executing jars on the command line but this has not worked.
I'd grately appreciate any help in furthering my understanding of why I can load the classes even though the dependencies are defined in the pom...Thanks in advance
Can you check if your pom matches this configuration a bit?
<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">
...
<properties>
...
<exec.maven.plugin.version>1.2.1</exec.maven.plugin.version>
...
</properties>
<build>
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
</plugin>
...
</plugins>
<pluginManagement>
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${exec.maven.plugin.version}</version>
<configuration>
<executable>java</executable>
<arguments>
<argument>-classpath</argument>
<!-- automatically creates the classpath using all project dependencies, also adding the project build directory -->
<classpath />
<argument>com.example.Main</argument><!-- your mainClass -->
</arguments>
</configuration>
</plugin>
...
</plugins>
</pluginManagement>
</build>
<dependencies>
...
<dependency>
<groupId>groupId.for.project1</groupId>
<artifactId>project1</artifactId>
</dependency>
<dependency>
<groupId>groupId.for.project2</groupId>
<artifactId>project2</artifactId>
</dependency>
...
</dependencies>
<dependencyManagement>
<dependencies>
...
<dependency>
<groupId>groupId.for.project1</groupId>
<artifactId>project1</artifactId>
<version>${project1.version}</version>
</dependency>
<dependency>
<groupId>groupId.for.project2</groupId>
<artifactId>project2</artifactId>
<version>${project2.version}</version>
</dependency>
...
</dependencies>
</dependencyManagement>
...
</project>
Where you fill them with the correct artifacts.
You should then be able to start it with:
mvn exec:exec
Can you post your configuration for your pom plz if it doesn't match, that way it's easier to understand what exactly you currently have in your pom.

How to export interfaces from maven project as new artifact

I have a maven project that creates a JCA connector (.rar file). Now to use this connector in another project I build this thing for, I want to import the interfaces for the connector.
Can I somehow add a build target to the connector pom.xml, which creates a new maven artifact with just the interfaces from the connector project (lets say connector-interfaces)?
Thanks!
Maven has a strong rule, that 1 project -> 1 artifact. I suggest to split your project:
connector
+ pom.xml
++ connector-interfaces
+++ pom.xml
++ connector-impl
+++ pom.xml
The pom.xml of the connector would contain 2 modules:
<modules>
<module>connector-interfaces</module>
<module>connector-impl</module>
</modules>
In the module connector-impl, you will need to add a dependency on connector-interfaces. Add this in the pom.xml of connector-impl:
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>connector-impl</artifactId>
<version>${project.version}</version>
</dependency>
If you use the maven release plugin, add this to the parent pom:
<project>
<build>
<plugins>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<configuration>
<autoVersionSubmodules>true</autoVersionSubmodules>
</configuration>
</plugin>
</plugins>
</build>
</project>
That way, maven will only ask for the version 1 time when you release.
Although #WimDeblauwe is suggesting a best practice and it would probably be best to follow it his way, there is another way you can accomplish this. There is an assembly plugin that can be used to do this. Normally it's meant to package your whole project in one jar, but it can also be used to make a subset of classes and make a jar out of that.
It can be a little tricky though. To do it you'll probably need to create a custom descriptor and reference this documentation to see how to format your descriptor file. Here's an example from the documentation of how to point to a custom descriptor:
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/src.xml</descriptor>
</descriptors>
</configuration>
[...]
</project>
In that src.xml file you'll want to <excludes> all classes except for the interfaces and set <includeDependencies> to false.

Categories