Stop Maven from including dependencies in the built artifact (jar) - java

I have a Jenkins build server that automatically builds the project into a jar when a new commit has been pushed to the GitHub project. I looked at file size of the artifacts that Jenkins creates and I was surprised. I came to the conclusion that all the third-party dependencies were included in the jar artifact!
I don't need Maven to include them in the artifact as that will increase the size dramatically and it isn't useful. So I fiddled around with my pom.xml file, but I couldn't get it working. The dependencies keep being included in the jar.
I'm relatively new to Maven and I would appreciate it a lot if someone can help me out!
Sources (if you need any):
Pom.xml

You can avoid packaging your dependencies inside your jar file by providing the scope they should be wrapped in. But since I looked to your pom.xml descriptor and find nothing misconfigured, I will suggest to use the maven-jar-plugin to exclude all third party libraries as follows:
<project>
...
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<configuration>
<excludes>
<exclude>*.jar</exclude>
</excludes>
</configuration>
</plugin>
...
</plugins>
</build>
...
</project>
Hope this helps.
BR.

My guess is that this is the root cause:
<resource>
<directory>libs</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
if you (also) have all your jars in this folder, then they will end up on the classpath ( see target/classes ), hence they will be part of the jar.
You only have to specify the jars as dependencies, Maven will do the rest.
Resources are used for non-java (or non-compilable) files, which should end up at the classpath as well, like config files for Spring or Hibernate

Related

Maven : How to package external jars(folder) in Maven project

I am having a group of external jars(in hundreds) which I have added in the build path of my project to make it work.
But while packaging it is failing as these jar's are not available to maven.
I have gone though many articles and all the solutions(like adding the jar at system path) are for a single jar only.
<dependency>
<groupId>com.sample</groupId>
<artifactId>sample</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/Name_Your_JAR.jar</systemPath>
</dependency>
Is there any way we can add the group of jars(folder) to the packaging on the project? or any other solution by which my project can build successfully?
can we create a single jar containing all my jars inside and then use the system scope of maven
I have tried creating jar by jar -cvf my_jar.jar * and placed this jar in the system scope. But it does not worked for me.
My solution : Maven pluggin addjar let us add all jar at a place(projectdirectory/lib in this case).
this enables you to add these jar's in the final package(jar in my case) when you maven build, but to run locally you have to add those jar files directly in the classpath.
<plugin>
<groupId>com.googlecode.addjars-maven-plugin</groupId>
<artifactId>addjars-maven-plugin</artifactId>
<version>1.0.5</version>
<executions>
<execution>
<goals>
<goal>add-jars</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>${basedir}/lib</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
Now create a shade jar using mvn clean install shade:shade
The bad news: For a proper Maven project, you need to add each and every artifact you use as <dependency> in your POM.
The good news: I very much doubt that these 100 jars are all
- directly used in your source code
- not available in a public Maven repository like MavenCentral
So the better strategy would be to figure out what you really need and find that in MavenCentral. Then Maven finds all the transitive dependencies for you. So if you really need 10 of the jars and all other jars are just dependencies of your dependencies, just add these 10 ones (from MavenCentral) and you are done.

Distribute plugin resource files to host project

I have a maven plugin that exposes a Mojo, with a goal that runs at the compile stage. The project was generated using mvn archetype:generate, and the POM contains all the standard stuff that comes with running that, very little deviation. The project includes a couple of resource files, e.g. filea.txt and fileb.txt, that are packaged up as part of the jar.
When the plugin is used in a project, I'd like the files that are included in the jar to be extracted and copied to the target\test-classes directory of the host project. I'm trying to use the plugin jar to both distribute some files + expose some functionality that can then use those files.
Is this a valid approach, and if so, are there settings I can add to the plugin POM to indicate that content from the plugin should be extracted and copied? I want to centralise this logic in the plugin, rather than having to do in the plugin host.
I feel like it's something with maven-dependency-plugin or maven-resources-plugin or build-helper-maven-plugin:attach-artifact, have tried a couple of different approaches but think I'm missing something obvious:
e.g. something like this in plugin POM?
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<outputDirectory>${basedir}/target/test-classes</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>filea.txt</include>
<include>fileb.txt</include>
</includes>
</resource>
</resources>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.6.0</version>
</plugin>
// etc etc
Google fu has let me down, keep ending up on maven resources page. Can post directory structure / more information if needed.
Cheers
First I would suggest to put resources which needs to be distributed into src/main/resources which looks like you have done ...but remove the configuration for the maven-resources-plugin and let maven do it's work. This is automatically copied into target/classes/ which in result is packaged into the resulting jar later.
If your plugin needs to get those files those can accessed as a usual resource via this.getClass().getResourcesAsStream("/...") and reading and writing them into a new location preferable into target/...

generated sources of other modules

I have a multi-module maven project. I use maven build helper plugin to automatically add generated sources to the classpath.
I am able to use the generated sources of module-X in module-X, however, when I add module-X as a dependency to module-Y, the generated sources of module-X are not visible because they are not included in the X.jar file.
Is there a way to include the generated sources in the jar file or force maven to generate sources of dependencies?
You can explicitly specify that the generated classes should be part of the output jar file:
<project>
...
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<includes>
<include>generatedClassesFolderPath</include>
</includes>
</configuration>
</plugin>
...
</plugins>
</build>
...
</project>
Replace the generatedClassesFolderPath with the relative path of the folder where the generated classes are.
More info:
How to include/exclude content from jar artifact
I had the same question and I solve it as follows:
Add an application class under package such as src/main/java/com..... in your module-X and add a #SpringBootApplication annotation. In addition to this, the application class can be no content.
Make sure module-X in module-Y dependencies and restart `module-Y.

Maven project doesn't recognize any classes from included sibling dependency [duplicate]

I am writing a project for acceptance testing and for various reasons this is dependent on another project which is packaged as a WAR. I have managed to unpack the WAR using the maven-dependency-plugin, but I cannot get my project to include the unpacked WEB-INF/lib/*.jar and WEB-INF/classes/* to be included on the classpath so the build fails. Is there a way to include these files into the classpath, or is there a better way of depending on a WAR?
Many thanks.
There's another option since maven-war-plugin 2.1-alpha-2. In your WAR project:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
This creates a classes artifact which you can use in the acceptance tests project with:
<dependency>
<groupId>your-group-id</groupId>
<artifactId>your-artifact-id</artifactId>
<version>your-version</version>
<classifier>classes</classifier>
</dependency>
Indeed, by design, Maven doesn't resolve transitive dependencies of a war declared as dependency of a project. There is actually an issue about that, MNG-1991, but it won't be solved in Maven 2.x and I'm not sure that I don't know if overlays allow to workaround this issue. My understanding of the suggested solution is to duplicate the dependencies, for example in a project of type pom.
(EDIT: After some more digging, I found something interesting in this thread that I'm quoting below:
I have been helping out with the development of the AppFuse project over
the last month where we make heavy use of the war overlay feature in the
Maven war plugin. It is a really nifty feature!
To get max power with war overlays I have developed the Warpath plugin
that allows projects to use war artifacts as fully fledged dependencies.
In brief:
1) The contents of the /WEB-INF/classes directory in the war dependency
artifacts can be included in the project's classpath for normal compile,
etc tasks.
2) Transitive dependencies from the war dependency artifacts become
available for use by other plugins, e.g. compile and ear - so no more
having to include all the dependencies when creating skinny wars!
The plugin has now been actively used in the AppFuse project for the
last few months, and I feel it is at a point where it is both usable and
stable.
Would the war plugin team be interested in including the warpath
functionality inside the war plugin? It would seem to be the most
natural place to host it.
So, I don't have any experience with it, but the maven warpath plugin actually looks nice and simple and is available in the central repo. To use it,include the following plugin configuration element in your pom.xml file:
[...]
<build>
<plugins>
<plugin>
<groupId>org.appfuse</groupId>
<artifactId>maven-warpath-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>add-classes</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
And add the war dependencies you want included in the classpath as warpath type dependencies:
[...]
<dependencies>
<dependency>
<groupId>org.appfuse</groupId>
<artifactId>appfuse-web</artifactId>
<version>2.0</version>
<type>war</type>
</dependency>
<dependency>
<groupId>org.appfuse</groupId>
<artifactId>appfuse-web</artifactId>
<version>2.0</version>
<type>warpath</type>
</dependency>
</dependencies>
[...]
Both the war and warpath dependency types are needed: the war type is used by the Maven war plugin to do the war overlay, the warpath type is used by the Warpath plugin to determine the correct list of artifacts for inclusion in the project classpath.
I'd give it a try.)
Use overlays. First, your test project need to have also packaging war.
Declare dependency of war project you want to test:
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>your-project-arftifactId</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>test</scope>
</dependency>
then configure maven-war-plugin overlay:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webResources>
<resource>
<directory>${basedir}/src/main/webresources</directory>
<filtering>true</filtering>
</resource>
</webResources>
<overlays>
<overlay/>
<overlay>
<groupId>your.group</groupId>
<artifactId>your-project-artifactId</artifactId>
</overlay>
</overlays>
</configuration>
</plugin>
In the above example in test project I overwrite webresources configuration files (like conxtext etc.).
EDIT: This solution wasn't tested with Maven 3.
Good point, Justin. That got me actually solving my problem, namely: including a war into an assembly AND including all its transitive dependencies.
I could not duplicate the war-dependency as 'jar' as you suggested since the assembly plugin would not find a jar referenced by that groupId/artefactId, but
duplicating the war-dependency as type pom
works!
The war and its transitive dependencies are not included in the assembly.
To exclude the (now also appearing) pom file I had to add an exclude element like this:
<excludes>
<exclude>*:pom</exclude>
</excludes>
into my assembly.xml file.
I think this could also be a workaround for the original question of this thread.
If you list the dependency on the war project as a jar dependency it seems to pickup the required jars/resources. I'm using Maven 2.2 + m2eclipse.

Obfuscating WAR file with Proguard

I want to obfuscate my web application built as WAR archive, as this sensitive application in first time deployed outside our data center. I tried to use the Proguard GUI tool to obfuscate the input war, with all the service jar required for the UI application, with other external dependencies. Though the Proguard runs successfully with some warnings, ex., duplicate definition of library class [javax.servlet.UnavailableException], the output war contains no classes, but has lib with the library jars and web.xml files. Any steps I mess? Any right document on this? I would appreciate if anyone can provide the right document or steps to successfully obfuscate a WAR file with dependent project (a .jar file) and other external jar files (that needs no obfuscation).
you wouldn't obfuscate a war but rather the jars your using. What you can do here is setup your project so the project that makes up the war - configuration xml, WEB-INF content, resources and the web content and servlet definitions and put your java in a library project. Obfuscate the library project and use those obfuscated jars in your web project.
That's what I do, hope it helps.
Protector4j is the best solution to obfuscate the war file, due to graphic user interface its too easy to use and their eclipse plugin is also available.
You will download it from this link
https://doc.protector4j.com/protect-tomcat-web-app
I have done the same way. I used the below url for code obfuscation and i am successful.
http://bratonfire.blogspot.com/2012/01/war-file-obfuscation-using-proguard.html
I created a new folder and redirected output of classes to this folder. But the strange thing is that i am able to see the .java and .class files in the two locations. I am also worried about recreating a war file. can someone mention the clear and detailed steps.
Thanks,
Rahul
We also have the same issue and need to obfuscate all classes packaged in war file.Here is the approach that I followed.
Firstly we need to set order of plugins **(compiler, proguard, war)**declared in pom.xml file as below.
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.0.14</version>
<configuration>
</configuration>
<executions>
<execution>
<!-- Dont worry about compiler error. For first time, change this value to package so that plugin installs successfully. -->
<phase>process-classes</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<warName>mfs-transaction-management</warName>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
<!-- Exclude your default packages from war packaging. Do not include "**" in double quotes in actual code -->
<packagingExcludes>
WEB-INF/classes/com/package/mypackage1/"**",
WEB-INF/classes/com/package/mypackage2/"**",
</packagingExcludes>
<webResources>
<webResource>
<directory>${project.build.directory}/proguardClasses</directory>
<targetPath>WEB-INF/classes</targetPath>
</webResource>
</webResources>
</configuration>
</plugin>
</plugins>`
Then create a file proguard.conf under the root of your project at the same level where pom.xml is placed.
Add your own configuration regarding proguard in the file and the add below two lines in this file to tell input and output folder to proguard plugin.
You need to set paths according to your project structure in these lines
-injars 'C:\Users\Rajdeep\git\dfs-core\mfs-transaction-management\target\classes'
-outjars 'C:\Users\Rajdeep\git\dfs-core\mfs-transaction-management\target\proguardClasses'
Apart from this you need to install proguard-base manually in maven repository using mvn install command.
Provide your own groupid, artifact and version and made same changes to pom.
It is proguard.jar found under proguard6.0.3\lib folder when you download proguard manually.
I think everything will be ok and now when you run mvn clean package, your war file should included obfuscated class files.
Use Proguard GUI to obfuscate war files.
Once you run proguardgu.bat or proguardgui.sh file from bin folder of your proguard directory. You can select wars by clicking Input/output menu.

Categories