It actually took me a long while to notice. When I run the project in netbeans, it works just as expected. But when I do the Build I get PROJECTNAME-1.0-SNAPSHOT.jar file that doesn't do anything. When unpacked, it looks like this:
This is suspicious, before Maven, my compiled file looked like this:
Shouldn't the Main class be in the jar file root? How does JVM know which main class to run?
There's something disturbing about the MANIFEST.MF too:
Old manifest
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.9.1
Created-By: 1.7.0_45-b18 (Oracle Corporation)
Class-Path: lib/alloy.jar lib/jna-platform.jar lib/jna.jar
X-COMMENT: Main-Class will be added automatically by build
Main-Class: Main
New manifest
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: Jakub
Build-Jdk: 1.8.0_31
Seems like Main-Class entry is missing...
Use maven-jar-plugin for make your jar executable. For me actual code below:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>my.main.class</mainClass>
</manifest>
</archive>
<outputDirectory>${project.build.directory}/result</outputDirectory>
</configuration>
</plugin>
Alse usefull exec-maven-plugin:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<mainClass>my.main.class</mainClass>
<!--
<commandlineArgs>-d 5409 -c 467 -t 2 -dlg true</commandlineArgs>
-->
</configuration>
</plugin>
Sadly many IDE's provide a simple mechanism for packaging all of your library jars into your main build jar. This is both frowned-upon and potentially hazardous to your deployable - you should really deploy all of the used libraries separately and use your class-path to join them all up.
As Maven attempts to make doing it right the easiest way it is designed to by default build your jar to contain just your code and no more. If you can stick with this solution then it may be worth your while doing so.
However, sometimes it is necessary to make this happen, perhaps to duplicate existing build results while switching to Maven or maybe deployment is enough of a nightmare without having to deploy dozens of libraraies too. To achieve this you can build what the Maven community call an Uber-Jar using the Maven Shade plugin.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<filters>
<filter>
<!-- Make sure jaxb is included. -->
<artifact>com.sun.xml.bind:jaxb-impl</artifact>
<includes>
<include>*.*</include>
</includes>
</filter>
<filter>
<!-- Make sure jtds is included. -->
<artifact>net.sourceforge.jtds:jtds</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
<exclude>META-INF/*.sf</exclude>
<exclude>META-INF/*.dsa</exclude>
<exclude>META-INF/*.rsa</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
Note that building uber-jars is generally not the best approach - there are many discussions about this online. Also there are many relational problems with the maven-shade-plugin itself as it interferes with Maven's mechanism for determining dependencies.
That said - if you must do it then the shade plugin is your guy.
NB: Just because this excludes licences does not mean this is a good idea - this is there to avoid duplicate file name issues in the uber jar.
See this interesting blog by MKYong about the pros and cons of using assembly/shade/one-jar.
Related
I have a java project that sends email built with maven (using Eclipse) and it works within Eclipse with no problem, but when trying to package a runnable jar, I am having an issue
Error: Unable to initialize main class com.my.package.MyClass
Caused by: java.lang.NoClassDefFoundError: javax/mail/MessagingException
I have this for my dependency:
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
and plugins set up like so:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.mypackage.MyClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.mypackage.MyClass</mainClass>
<manifestEntries>
<Multi-Release>true</Multi-Release>
</manifestEntries>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
I can see javax.mail-1.6.2.jar in my maven dependencies, so not sure why I am unable to run the jar...is there a config option I missed?
thanks!
I searched around and tried numerous variations of the shade and jar plugins, I expected to be able to run the jar off the command line using java -jar myjar.jar. Most of the posts I found in my search recommended adding the mail jar to the classpath, but that looks like it's already done, as the jar is in the list of maven dependencies.
Update
Have tried multiple variations, as per suggestions below. Tried the maven-assembly-plugin making sure to add the <mainClass>com.etcetera.MyClass</mainClass> tag. With those variations I got no main manifest attribute, in myjar.jar. I then added in the maven-jar-plugin plugin, also adding the main class and I'm now back to the original error.
Update2
when I open up the archive, I see this:
Manifest-Version: 1.0
Created-By: Apache Maven 3.8.4
Built-By: myUserName
Build-Jdk: 15
which appears to be missing the Main-Class: com.javabyexamples.java.jar.HelloWorld line
Resolution
I resolved the issue by building the project twice in Eclipse: clean package and then clean compile assembly:single
When building a web app, dependencies are, of course, bundled in the .WAR/.EAR.
However, by default, Maven will not bundle dependencies inside your .jar file. (In other words, jars will not be put inside of other jars).
Nevertheless, you can use the jar-with-dependencies descriptor. More details can be found on the questions below:
Including dependencies in a jar with Maven
How can I create an executable/runnable JAR with dependencies using Maven?
Alternatively, you could add the mail-1.6.2.jar on the Java classpath like so:
java -jar "myjar.jar" -cp "./path/to/mail-1.6.2.jar:./path/to/other.jar"
It is not necessary to create an executable JAR. You can package a regular jar, allow Maven to generate the MANIFEST.MF, making sure to add the regular JAR to the Java classpath, and specify the class with the main function on the command line:
java -cp "./path/to/mail-1.6.2.jar:./path/to/other.jar:/path/to/myjar.jar" "com.mypackage.MyClass" "param1 param2 etc"
Please note that classpath separators are different on Linux (colon) vs Windows (semi-colon)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/Application.java</exclude>
</excludes>
</configuration>
</plugin>
this is my pom.xml , maven-compiler-plugin.version is 3.8.1 .
but i see the Applciation.class still in my jar package by maven
You are looking at the wrong location. From what I see in the screenshot, you've found some Application file from the External Libraries. What the maven-compiler-plugin does is to generate the target folder. That's where the class file should be excluded from. Check the existence of the file class under:
target/classes/...
And don't forget to run mvn clean install before (with emphasis on clean - this will wipe out your target folder)
In a project, I had to do a similar thing, due I need to exclude the module-info.java. I resolved using this configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<excludes>
<exclude>**/module-info.java</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
If you want the entire project you can get it from GitHub. I hope this helps.
Hello people of stackoverflow, on my working project I have 5 dependencies.
I'm working on a project which doesn't contain any main method.
What I would like to do is including 2 (HikariCP and slf4j) out of my 5 dependencies in the final jar, but I don't figure how to do this, it's always adding all of them.
Edit: I'm using eclipse
Using Maven
You can use the maven-shade-plugin to generate a fat-jar (or uber-jar). It will package all your dependencies inside the jar:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<finalName>YOUR_JAR_FINAL_NAME</finalName>
</configuration>
</plugin>
</plugins>
</build>
Documentation related to the maven-shade-plugin can be found in here
UPDATE: As you want to include just a few dependencies inside of it, you can check the Selecting contents for Uber JAR section:
You can use the include or exclude tag to select which content will be provided to the jar, you can find some examples from the docs below:
Excluding
<configuration>
<artifactSet>
<excludes>
<exclude>classworlds:classworlds</exclude>
<exclude>junit:junit</exclude>
<exclude>jmock:*</exclude>
<exclude>*:xml-apis</exclude>
<exclude>org.apache.maven:lib:tests</exclude>
<exclude>log4j:log4j:jar:</exclude>
</excludes>
</artifactSet>
</configuration>
Including and excluding
<configuration>
<filters>
<filter>
<artifact>junit:junit</artifact>
<includes>
<include>junit/framework/**</include>
<include>org/junit/**</include>
</includes>
<excludes>
<exclude>org/junit/experimental/**</exclude>
<exclude>org/junit/runners/**</exclude>
</excludes>
</filter>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
UPDATE 2: For a runnable jar file, you can follow this section of the documentation related to Executable Jars
In Eclipse
You can use the Package required libraries into generated JAR option, the downside of it is that you can't really select which dependencies do you want to include into to, since it is assessing all the required libs for you project.
I believe if you really want to remove some stuff, you would need to use Maven to package, or remove manually the dependencies you don't like from the generated jar, generating a custom jar with your own hands:
Is there a way to add an arbitrary classpath entry to a JAR file manifest using onejar-maven-plugin?
I found the way to configure maven-jar-plugin to do this, but it appears that there is no such option for onejar-maven-plugin.
This is not done to find additional classes (otherwise why use the onejar plugin, right?), but rather to locate a configuration file that must be external to the JAR.
Is there a direct solution or a workaround for this?
Is the usage of the one-jar plugin really required?
You can achieve the same goal (packaging in one single jar your application AND all the required dependencies, including transitive ones, AND add configuration for Class-Path AND using a more stable/standard plugin) applying the following approach:
Configure the Class-Path entry in your application Jar using the Maven Jar Plugin and the approach you mentioned in the question
Use the Maven Assembly Plugin to package one single JAR including dependencies, as explained here, in another stackoverflow question/answer.
An example of one-jar executable file (without using the one-jar plugin) could be as following:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<!-- your further configuration here -->
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.sample.MainApp</mainClass>
<!-- your further configuration here -->
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
If you need to further play with classpath and Maven, I would suggest to also check this question here on stackoverflow.
Adding arbitrary manifest entries is possible in 1.4.5:
<plugin>
<groupId>org.dstovall</groupId>
<artifactId>onejar-maven-plugin</artifactId>
<version>1.4.5</version>
<executions>
<execution>
<configuration>
<manifestEntries>
<Build-Status>Yes</Build-Status>
</manifestEntries>
</configuration>
<goals>
<goal>one-jar</goal>
</goals>
</execution>
</executions>
</plugin>
The onejar-maven-plugin project doesn't seem to be in active development anymore, so you might want to switch to other solutions (e.g. maven-assembly-plugin) eventually.
The plugin is not available on Maven Central. Someone else put up a version of it to Maven Central with a different group ID.
Additional libraries can be added to the classpath at the time of launch.
The property one-jar.class.path can be used
one-jar.class.path
Extra classpaths to be added to the execution environment. Use platform independent path separator '|'
Example: --one-jar.class.path="./lib/two.jar|/opt/lib/three.jar"
Source: http://one-jar.sourceforge.net/index.php?page=details
I already have a working solution where I can specify with maven which classes to not compile when using a particular maven profile.
But I would like to use a general solution and use an annotation instead
The current solution that I have is like
<plugin>
<!-- Exclude some web services used only for internal testing -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<optimize>true</optimize>
<excludes>
<exclude>**/something/*ClassPattern.java</exclude>
</excludes>
<testExcludes>
<exclude>**/something/*ClassPatternTest.java</exclude>
</testExcludes>
</configuration>
</plugin>
But Some thing like
#NotCompiledForProduction
would be rather nice on top of a class.
It seems to me that this might be hard (or impossible to do) without changing maven's behaviour. That is not the scope here. And this kind of annotation
You cannot (I assume) use an annotation to determine what source code gets presented to the java compiler, because you need to compile the source code in the first place to process the annotation.
It seems like you need to create different modules in your maven project: one that generates a jar file with the production code, and one module that generates a jar file with testing implementation with a dependency on the production artifact.
If the code really does need to be in the same maven module, then the code should always be compiled. You can however use maven-jar-plugin to create multiple artifacts at the package phase: the default artifactId.jar, and an artifactId-test-lib.jar artifact. You can do this by specifying multiple executions for the plugin, and using <includes> and <excludes> to split the jar files as required.
you can try this...
<build> <plugins>
<!-- Run annotation processors on src/main/java sources -->
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
</execution>
</executions>
</plugin>
<!-- Disable annotation processors during normal compilation -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgument>-proc:none</compilerArgument>
</configuration>
</plugin>
</plugins> </build>