Building war and runnable jar with Maven - java

I have started a new Java project using Maven.
I wrote a set of core functionalities, a REST web service which use them, and a command line interface.
When I run maven package, I would like to be able to:
Build a war with the web service, AND
Build a runnable jar which packs the dependencies and starts the command line interface
How have I to configure Maven in order to reach the goal?
Let me add some details.
I already know how to produce only a WAR, and how to produce only a JAR.
What I need is to produce BOTH with ONE maven package.
The WAR have to be deployable on a Tomcat, which should display the index.jsp page.
The JAR have to be runnable from the console.

With regards to the Runnable JAR (point 2), you should use maven-assembly-plugin, which will create a JAR with all the dependencies you need, and you can run it from the command line. On the plugins section of your pom.xml, you have to add something like this:
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
The you can run:
mvn clean compile assembly:single
More info, can be found here.
Hope it helps!

For point 1, I would start by using Maven itself to create a pom.xml that can be used to build your web app.
$ mvn archetype:generate -DgroupId={project-packaging}
-DartifactId={project-name}
-DarchetypeArtifactId=maven-archetype-webapp
-DinteractiveMode=false
See this link for more.
Once you've added your code to the source tree appropriately and built the WAR, you can copy it to your application server and it should be ready to go.

Related

java.lang.NoClassDefFoundError: org/telegram/telegrambots/meta/exceptions/TelegramApiException

I'm trying to deploy my first java application using Maven. In this case, this is just a simply telegram bot, but I get this error when trying to run it locally. After a little investigation, I found that java.lang.NoClassDefFoundError is an error that occurs when a jar file is not able to access a specific class in runtime, and in order to solve this, is necessary to add that class on classpath.
I understand that when working on Maven, there is a simple way to add classes on the classpath, and it's by adding the right dependency on the pom.xml file.
So this is what i've added:
<dependencies>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-abilities</artifactId>
<version>5.0.1.1</version>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>5.0.1</version>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-meta</artifactId>
<version>5.0.1.1</version>
</dependency>
</dependencies>
And I think it was successfully added on the classpath because this is what I get when I read the MANIFEST.MF file on my jar file:
Manifest-Version: 1.0
Created-By: Apache Maven 3.6.3
Built-By: agujared
Build-Jdk: 15.0.1
Class-Path: telegrambots-abilities-5.0.1.1.jar commons-lang3-3.11.jar ma
pdb-3.0.8.jar kotlin-stdlib-1.2.71.jar kotlin-stdlib-common-1.2.71.jar
annotations-13.0.jar eclipse-collections-api-11.0.0.M1.jar eclipse-coll
ections-11.0.0.M1.jar eclipse-collections-forkjoin-11.0.0.M1.jar lz4-1.
3.0.jar elsa-3.0.0-M5.jar slf4j-api-1.7.30.jar telegrambots-5.0.1.jar j
ackson-annotations-2.11.3.jar jackson-jaxrs-json-provider-2.11.3.jar ja
ckson-jaxrs-base-2.11.3.jar jackson-module-jaxb-annotations-2.11.3.jar
jackson-core-2.11.3.jar jakarta.xml.bind-api-2.3.2.jar jakarta.activati
on-api-1.2.1.jar jackson-databind-2.11.3.jar jersey-hk2-2.32.jar jersey
-common-2.32.jar osgi-resource-locator-1.0.3.jar jakarta.activation-1.2
.2.jar hk2-locator-2.6.1.jar aopalliance-repackaged-2.6.1.jar hk2-api-2
.6.1.jar hk2-utils-2.6.1.jar javassist-3.25.0-GA.jar jersey-media-json-
jackson-2.32.jar jersey-entity-filtering-2.32.jar jersey-container-griz
zly2-http-2.32.jar jakarta.inject-2.6.1.jar grizzly-http-server-2.4.4.j
ar grizzly-http-2.4.4.jar grizzly-framework-2.4.4.jar jakarta.ws.rs-api
-2.1.6.jar jersey-server-2.32.jar jersey-client-2.32.jar jersey-media-j
axb-2.32.jar jakarta.annotation-api-1.3.5.jar jakarta.validation-api-2.
0.2.jar json-20180813.jar httpclient-4.5.13.jar httpcore-4.4.13.jar com
mons-logging-1.2.jar commons-codec-1.11.jar httpmime-4.5.13.jar commons
-io-2.8.0.jar telegrambots-meta-5.0.1.1.jar guava-30.0-jre.jar failurea
ccess-1.0.1.jar listenablefuture-9999.0-empty-to-avoid-conflict-with-gu
ava.jar jsr305-3.0.2.jar checker-qual-3.5.0.jar error_prone_annotations
-2.3.4.jar j2objc-annotations-1.3.jar
Main-Class: domain.Main
As you can see, telegrambots-meta-5.0.1.1.jar is part of the classpath attribute.
How can I solve this?
By the way, I'm using Heroku Cloud to deploy this
Sounds like you want and need to create a runnable/ executable JAR file (with external dependencies).
This requires your build process to be enhanced by this step, regardless of where it is executed Heroku, Jenkins, Bamboo or on your local - this is a maven setting and will affect each of them.
Also on your local you can run the build of your project by executing mvn clean package in your IDE and afterwards to run the created JAR from the target folder with: java -jar ${yourJarName}. It'll likely fail for the same reason.
This is, because Maven dependencies are added with a so called scope. These are for example:
compile
provided
runtime
test
Whereby compile is the default one and being implicitly applied in case you don't specify it - like in your case. (You can read more about the scopes here)
This means Maven will add your dependency to your IDE at compile time, but it will be missing at the runtime, when your trying to execute it.
The solution is to create a runnable/ executable JAR file (also called *fat JAR *) containing all the needed dependencies.
You can do it directly within Maven with the help of the maven-assembly-plugin like so:
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
Then you need to build your JAR like:
mvn clean compile assembly:single
Note: The compile goal must be added before assembly:single or otherwise the code on your own project is not included.
To ease the handling of the process this goal commonly is tied to a Maven build phase to execute automatically. This ensures the JAR is built when executing mvn clean package, mvn clean install or performing a deployment/ release:
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Like this you can simply build your project with the mvn clean package command (probably the most common one) and it'll include the creation of the runnable/ executable JAR file. This will include all your needed dependencies and should resolve your java.lang.NoClassDefFoundError issue.
Just a short additional note
Creating runnable/ executable JAR file respectively fat JAR is not the only solution and maybe in some contexts unwanted. Since fat JAR files include all their needed dependencies, they are fairly big with all the related drawbacks (requires more bandwith to transmit, download size increases, same dependencies might be carried in multiple different JARs, ...).
For this reasons the fat JAR creation is avoided in Web Application Development with Java EE. Dependencies are only added at compile time, since it is known that a Servlet Container or Application Container like Tomcat or Wildfly will provide these at runtime to avoid the java.lang.NoClassDefFoundError. Therefore the different applications (JARs or in this context called WARs) don't need to provide the dependencies themself.
In your case it might also be the solution that you'll still build the thin JAR, but will provide the needed dependencies at runtime (e.g. separately downloading it and then specifying in the classpath before the execution).

How to use an entire Java project inside another Java project and instantiate and use classes and methods?

I came out with a situation i have a maven proyect with several clases and methods... and i need to have the same project classes and methods across some other projects that needs them.
After reading some about Git submodules, and Git Subtrees, and other ways to acomplish this. what i decided was to export a Jar file with its dependencies, and copy it to all other projects in the '${basedir}/lib/' subdirectory. This way i keep it simple enough for all the devs in my QA team (we are not SO much experienced devs, as we came from QA world) and also i can control that all of them use the same libs in all projects.
I exported to Jar file with the assembly maven plugin, adding this to my POM file in the first repo:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
And running
$ mvn clean compile assembly:single
I have the Jar file in the 'target' directory which i copied to all other repos. in the 'lib' directory of each repo.
Then in the POM files of the other repos i added to their POMs dependencies section:
<dependency>
<groupId>myDep</groupId>
<artifactId>myDep</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>system</scope>
<systemPath>${basedir}/lib/myDep-1.0-SNAPSHOT-jar-with-dependencies.jar</systemPath>
</dependency>
The thing is that i could not figure it out how to import the Jar in my classes to use the methods i need from this imported Jar. As i tried to import like
import myDep.*
But its not working.
Could you point me in the right direction? thank you so much!
Usually, before you start using Maven, you set up some infrastructure:
a Nexus or Artifactory server for the artifacts (jars, wars etc.)
a build server like Jenkins.
Then you build your jars (without anything like maven assembly plugin) on the Jenkins with mvn clean deploy. Then they are avaible in the Nexus/Artifactory.
If the developers have a settings.xml pointing to the right Nexus/Artifactory, they can then just add
<dependency>
<groupId>myDep</groupId>
<artifactId>myDep</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
to their pom.xml without specifying any path or copying anything around. Maven will then do the magic to resolve that dependency from Nexus/Artifactory.

Running maven project via apache-maven server

Dear all I have a maven project and I need to run it using apache-maven I'm using the command mvn install to compile and add it to .m2 repository but how can I run this maven project via apache-maven server without using IDE's
Thanks in advance
In order to run a simple Java project, you have to identify the Main class. If you are using Maven for the build, the packaging will have to specify which class contains the main method.
You can do the above in Maven POM by adding a manifest in the configuration for the maven-jar-plugin which is responsible for the packaging. In other words, you simply add the following to your POM.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>libs/</classpathPrefix>
<mainClass>
org.baeldung.executable.ExecutableMavenJar
<!--Full classified name of the class that contains the main method -->
</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
Once the JAR is created, you can execute it by invoking the following:
java -jar jarName.jar
You can find more details on the topic at http://www.baeldung.com/executable-jar-with-maven
You can follow these steps to find the solution of the main question:
https://www.mkyong.com/maven/how-to-deploy-maven-based-war-file-to-tomcat/

Java: Maven and Library compiling

I'm trying to compile a project which has got Maven dependencies and normal dependencies (the ones you would add the .jar to your buildpath/lib). However, I can only choose one ;( Either, I compile with Maven, or I compile with artifacts, and that won't make the project work.
I use
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>me.expdev.testproject.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
and
mvn clean compile assembly:single
to compile. But I also have 5 jars (which are not available as Maven) which I need included in the packaging jar output! It works fine when I run Main in my IDE.
I USE IntelliJ Community Edition.
You can package the 3rd party jars as Maven artifacts.
mvn install:install-file -Dfile=<path-to-file> -DgroupId=<group-id> \
-DartifactId=<artifact-id> -Dversion=<version> -Dpackaging=jar
The <group-id>, <artifact-id> and <version> fields are completely up to you to fill, choose values that seem appropriate to you. The artifact will be available to Maven by these values. See other Maven artifacts already in your project for examples. For the group id, choose some prefix to make it clear that it's not a publicly published jar, to avoid confusion. For example custom., as in custom.some.package, but it's really up to you.
For more details, see: Guide to installing 3rd party JARs
Also keep in mind that other developers who want to use the project will have to do the same, and manually install the jars in their local Maven repositories. Another option is to run your own Maven repository. See this article: http://stuartsierra.com/2009/09/08/run-your-own-maven-repository
.

m2eclipse maven build parameters

I am developing a spring mvc app using eclipse kepler with the m2eclipse plugin. How do I create a war file from within eclipse using the m2e plugin?
Do I use run as... maven build...? If so, how do I configure it? I right clicked on the root folder for the app in the eclipse workspace and chose run as... maven build..., which resulted in the following dialog box:
But I do not know what parameters to enter into the dialog box. Can anyone guide me through how to create the war file?
Put Goals as clean compile package
There are three built-in build lifecycles: default, clean and site. The default lifecycle handles your project deployment, the clean lifecycle handles project cleaning, while the site lifecycle handles the creation of your project's site documentation.
Each of these build lifecycles is defined by a different list of build phases, wherein a build phase represents a stage in the lifecycle.
Read more about Build Lifecycle Basics
Here is the complete description with snapshots Using the M2Eclipse Maven Plugin in Eclipse
Please have a look at Tutorial - Maven Eclispe IDE Integration
First of all you need war plugin configured in your pom.xml
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<!-- In version 2.1-alpha-1, this was incorrectly named warSourceExcludes -->
<packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
...
</project>
which is associated with one of the phase (generally package) then you need to put clean package in goals

Categories

Resources