I am starting to learn Maven by reading https://spring.io/guides/gs/maven/.
In the examples, after running mvn compile successfully, how can I run the program via maven? This part seems missing from the article.
Thanks.
You can invoke a Java program (i.e. with a public static void main(String[] args) signature) with the classpath of the combined dependencies for the current pom.xml using
mvn -q exec:java
You need to configure the main class to invoke in your pom.xml similar to
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>demo.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
This is useful for testing and development, but not deployment
See http://www.mojohaus.org/exec-maven-plugin/usage.html for full details.
The Maven build process has a number of lifecycles, or points in the process. compile is one of the build steps, but most likely running the following would resolve your issue:
mvn clean package
This would generate a JAR file, in the folder where you ran it. You can then try running this JAR file using java.
Generally, maven is not used for running code. This is a build tool that you can use for compiling, running unit or integration tests, deploying you your code locally and remotely, etc..
It is based around the idea of a build lifecycle where which is in its turn is defined by a list of build phases. For example, the default lifecycle has the following phases:
validate - validate the project is correct and all necessary information is available
compile - compile the source code of the project
test - test the compiled source code using a suitable unit testing framework. These tests should not require the code be packaged or deployed
package - take the compiled code and package it in its distributable format, such as a JAR.
verify - run any checks on results of integration tests to ensure quality criteria are met
install - install the package into the local repository, for use as a dependency in other projects locally
deploy - done in the build environment, copies the final package to the remote repository for sharing with other developers and projects.
For more information you can refer to this.
UPDATE:
Having said that, it is possible as mentioned in Thorbjørn Ravn Andersen answer here.
Related
This is a really weird one. I have a Kotlin web service that was originally written as a hybrid app of both Kotlin and Java but I've recently migrated to pure Kotlin (although many of its libraries are still in Java). The framework I'm using is sparkjava and I'm using Maven to manage dependencies and packaging. The service in the past was built with manually included dependencies as JAR files and was built using an IntelliJ configuration, this was horribly messy and difficult to reproduce so I moved all the dependencies into Maven and set up a process for this. This is where things get weird:
I included this plugin in my pom.xml to manage the creation of the fat JAR which looks like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<archive>
<manifest>
<mainClass>unifessd.MainKt</mainClass>
</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>
When I run this confuration however, I get a JAR that won't execute. I didn't think this was a major problem, as running the "package" lifecycle in Maven does produce an executable JAR. This resultant JAR will happily run on my development machine (macOS Big Sur) and will pass all my external testing scripts. However, when I deploy the very same JAR to my production environment which is a FreeBSD server on AWS, it will start up correctly but whenever I make a request I get the following error:
[qtp248514407-20] WARN org.eclipse.jetty.server.HttpChannel -
//<redacted.com>/moderation/users/administrators
java.lang.NoClassDefFoundError: Could not initialize class
de.mkammerer.argon2.jna.Argon2Library
at de.mkammerer.argon2.BaseArgon2.hashBytes(BaseArgon2.java:267)
at de.mkammerer.argon2.BaseArgon2.hashBytes(BaseArgon2.java:259)
at de.mkammerer.argon2.BaseArgon2.hash(BaseArgon2.java:66)
at de.mkammerer.argon2.BaseArgon2.hash(BaseArgon2.java:49)
at [...]
I've truncated the stack trace to keep things concise but all it's doing before that is opening the appropriate DAO and hashing the password attempt. The offending class is of course de.mkammerer.argon2, which is a dependency I use to hash passwords using the argon2 algorithm. This has me really stumped for the following reasons:
When this dependency was linked in manually using a JAR in IntelliJ, it worked absolutely fine in production.
Even though the class fails to load in production, it works fine locally despite the packages being identical.
macOS and FreeBSD aren't exactly a million miles apart in terms of how they're put together, so why are they behaving so differently?
A few other points in my efforts to debug this:
I've tried linking in my argon2 library in the old way, and it's still failing in the same fashion.
IntelliJ isn't recognising the main class of my Kotlin app any more if I try and create an artifact without Maven. This is really weird, I can set up a Kotlin build and run configuration just fine by specifying unifessd.MainKt as my main class, but when it comes to building an artifact it's simply not having it. It doesn't appear in the artifact creation dialogue and when I specify it as my Main-Class in MANIFEST.MF, IntelliJ tells me it's an invalid main class. What on Earth is going on here? It'll run just fine when I tell Maven that's my main class and package it in a JAR, even in the faulty production environment.
Robert and dan1st were correct, the problem was that my argon2 library had a dependency on JNA and native code that was incompatible with FreeBSD. I tested the JAR on an Ubuntu server to confirm that this was the case and the program ran correctly.
I'm not a Java dev and am unfamiliar with the packaging and building of Java programs. I'm trying to run this file: https://github.com/CodinGame/SpringChallenge2020/blob/master/src/test/java/Spring2020Main.java
by doing
mvn clean install
java -jar .\target\spring-2020-1.0-SNAPSHOT.jar
but I get this error:
no main manifest attribute, in .\target\spring-2020-1.0-SNAPSHOT.jar
I can't figure out for the life of me what I need to add to the pom.xml or whatever else I need to do to get this to work.
Any help will be appreciated.
A few things to understand about Java:
1) If you have a Maven project like this, code is divided between src/main/ and src/test/ directories. src/test/ is intended for unit tests. In your case, Spring2020Main is not actually set up as a unit test, so I'm not sure what the author intended here.
2) When you compile using mvn clean install, a jar (library) is built, but nothing from src/test will be included in the output.
Generally, tests are executed during build. And this one would have been, except it's not set up as a real junit test, so it didn't run during build.
3) You can move the file from src/test/java to src/main/java and it will be built into your resulting jar.
4) In this case, when you run the JVM, you need to specify a classpath. This is a list of all libraries to include when the application starts. You also need to specify the (fully qualified) name of the class to run:
java -cp target/spring-2020-1.0-SNAPSHOT.jar Spring2020Main
...the above won't work directly since there are more unsatisfied dependencies (the top level pom.xml brings in at least 3 other deps you'd also need to provide on the classpath).
As others pointed out, a solution could be to build a self-executing jar, but simplest for you would be to run this from an IDE:
Run this from IntelliJ. If you haven't installed it, install it.
1) File > New From Existing Sources, find the directory where this is coned to.
2) When asked, Import Project from Existing Model (Maven)
3) When the Project view is available (alt-1), or View > Tool Windows > Project, you can expand the structure till you find Spring2020Main in the test directory.
4) Right-click it and select Run.
For me, it exposed a web server running at http://localhost:8888/test.html
You can follow the steps below:
Move Spring2020Main.java to src/main/java/com/codingame directory
Add the following to your pom.xml after the </dependencies>:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.codingame.Spring2020Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Run maven build using mvn clean install
Execute the program using java -jar target/spring-2020-1.0-SNAPSHOT.jar
Info: Apache Maven Shade Plugin helps in building what is called an uber-jar or a fat-jar. This means that all the dependencies are packaged as part of the resultant jar file without the need for any 'libraries' that you'd need to add in the classpath when executing the jar file. As part of the final jar, we need to specify which file needs to be treated as the main file to be executed. This is typically done using META-INF/MANIFEST.MF file inside the uber-jar. That's what the transformer specified inside the configuration of the plugin does for us.
The project you've linked has only a basic setup for compilation (that would be enough to run it from IDE though).
What you need is an executable jar. Check this thread.
As others mentioned (and I failed to notice) the class you linked to is a test class, so it may not be included in a jar by default. Run it through IDE or set it up in a proper source directory.
I have a multi-module maven project. I'm using intellij-idea as my IDE.
I have Maven configured with the clover plugin to automatically instrument on build.
How can I get IntelliJ to recognize those changes and refresh its coverage data.(NOTE: having to click the "Refresh Coverage" toolbar button is fine.)
I've tried configuring maven-clover2-plugin like so:
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-clover2-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<baseDir>${project.basedir}</baseDir>
<cloverMergeDatabase>
${project.basedir}.clover\cloverMerge.db
</cloverMergeDatabase>
</configuration>
<executions>
<execution>
<id>main</id>
<phase>package</phase>
<goals>
<goal>instrument</goal>
<goal>aggregate</goal>
<goal>check</goal>
</goals>
</execution>
<execution>
<id>site</id>
<phase>pre-site</phase>
<goals>
<goal>instrument</goal>
<goal>aggregate</goal>
<goal>check</goal>
</goals>
</execution>
<execution>
<id>clean</id>
<phase>clean</phase>
<goals><goal>clean</goal></goals>
</execution>
</executions>
</plugin>
I then configured my project settings to use:
.clover\cloverMerge.db and checked the relative to project directory. checkbox.
But that didn't work.
NOTE:
At the bottom of Configuring Instrumentation it says
Do not set these locations explicitly if you have a multi-module project.
So I also tried leaving the location as the default for both Maven and IDEA and that didn't work either.
Also in the Clover for IDEA installation GUIDE - Known Issues
If you are using the Maven build tool, you should avoid using the same > IntelliJ output directory as Maven does. As Maven uses the target/classes and target/test-classes directories,
avoid specifying these ones. The clover.db location for IntelliJ should also be distinct from that used by Maven.
WHY should they be distinct is there some file corruption issue? If they're kept distinct then HOW can I get awesome coverage highlighting/etc, without having to repeat builds in a completely separate process?
Well I finally figured out an answer. I'm leaving this here for posterity.
The solution is complicated and somewhat of a Hack but it WORKS.
Update the parent projects pom.xml file
cloverDB: <cloverDatabase>${project.basedir}.clover\clover.db</cloverDatabase>
Merge CloverDB:
<cloverMergeDatabase>
${project.basedir}.clover\cloverMerge.db
</cloverMergeDatabase>
Create your Unit Tests to Run in IntelliJ IDEA
setup a Before launch - Run Maven Goal
clean clover2:setup prepare-package -DSkipTests
Create a Maven Run Configuration
Make the Unit-Tests a Before launch condition
In the command line have Maven run clover2:aggregrate
Update Intellij Project Settings for clover to point to the merge file
Make sure the Relative to project directory. checkbox is checked.
InitString to User specified with the value the same as your pom file.
in my case: .clover\cloverMergeDB
Once the command is run, just click the Referesh Coverage icon to see and work with the coverage data in idea.
If the tests fail you will also have the nice IntelliJ Test runner Tab to figure out why.
At the bottom of Configuring Instrumentation it says
Do not set these locations explicitly if you have a multi-module project.
Documentation actually says: Do not set these locations explicitly (using absolute path) if you have a multi-module project. The reason is simple - if you use an absolute path, then you will not have a separate clover.db for every module, but only a single clover.db file.
"If you are using the Maven build tool, you should avoid using the same IntelliJ output directory as Maven does. As Maven uses the target/classes and target/test-classes directories, avoid specifying these ones" [...] WHY should they be distinct is there some file corruption issue?
The problem is as follows: IntelliJ IDEA uses it's own engine to compile sources. It means that it does not have to call the original project's build system (a Maven, for instance) to compile sources.
It means that:
- if you have a Maven-based project and it has the Clover-for-Maven plugin installed and
- at the same time you have the Clover-for-IDEA installed in the IntelliJ IDE
- and these two Clover integrations use the same output folders for classes and databases
... then these two Clover integrations may start overwriting their files.
In most cases this is not a desired behaviour because any source code modification / project rebuild action etc in IDEA will trigger source recompilation; which can delete results obtained previously by Clover-for-Maven.
I'd like to compress all of my javascript files and aggregate them
using YUICompressor, and I saw that there was a maven plugin to allow
me to do this. I got it working for the most part.
I am also using the Mojo tomcat plugin as well. When i go to run the
tomcat:run goal, tomcat does not read from the target's output
directory (this is where the YUI compressor put my javascript files) -
but rather, it reads from the actual source files in my "src/main/
webapp/scripts" directory. Of course, the aggregated javascript file
(all.js) is not there.
I have a few questions.
How can I get the tomcat plugin to read the target's output folder
that the yui compressor plugin created?
Do I have to run the yui compressor maven goal every time I want to
update my javascript files during development?
Is there a better way to achieve this? Essentially, my end goal is
to be able to develop JavaScript and test my source files in
development mode, but I want to compress and aggregate the files and
use the all.js script when the application is running in production
mode.
While the Rails people have certainly figured this out, this seems to
be a non-trivial thing to do with Maven and Spring.
I would appreciate any and all assistance on how I can get this
running correctly. Thanks!
I was just investigating this very problem and found my answer by looking at the plugin documentation.
mvn tomcat:run - Runs the current project as a dynamic web application
using an embedded Tomcat server.
What this means in practice is that the package execution phase has not been reached when the embedded tomcat runs.
The answer is to instead use:
mvn tomcat:run-war - Runs the current project as a packaged web
application using an embedded Tomcat server.
This allows the maven build to get as far as packaging the WAR file and therefore allows the yuicompressor-maven-plugin to do what it needs to before the embedded tomcat starts up.
As for having to run it every time, you should attach the run of the yui plugin to the "generate-sources" execution phase.
Add the following to your plugin (the important part is the "phase" element to attach it to the lifecycle):
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>compress</goal>
</goals>
</execution>
</executions>
<configuration>...</configuration>
</plugin>
This way the plugin will run every build during the generate-sources phase. So any time you change your java scripts which you have configured the plugin for, the output .js file will be updated as soon as you run something like:
mvn compile
mvn test
mvn install
mvn package
and so forth.
The above does cause the minified (and possibly aggregated) files to be created earlier in the lifecycle but tomcat:run cannot find them!
I'm new to maven and somewhat new to java. Tried google and related sources, but I didn't find one which resembled my situation.
Right now, I have maven project X and Y. X can be seen as a shared library with some utilities, Y is a simple JFrame with a "hello world" printed and a call to a static method in X.
I do a "run as maven install" on project X, I get a "build successful". I add project X as dependency in project Y (using the pom-editor in Eclipse, browsing the repository and locating it). I do a "run as maven package" on project Y, I get a "build successful". Upon running project Y either via java -jar or inspect the produced jar, project X is missing everywhere and I get a fancy class not found exception. Eclipse finds it and there are no compile errors in the source editor.
Why is it only working in the Eclipse editor and not as jar?
POM:
<dependency>
<groupId>com.company.deployment.shared</groupId>
<artifactId>com.company.deployment.shared</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
Maven doesn't produce a combined JAR file for you. What Eclipse is doing is looking at the Maven configuration and adding all the required classes / jars to your classpath for you when it runs.
If you want to run your program from the command-line, you will need to add all the JARs manually to your classpath.
Alternatively, you could run your program directly from Maven which should set up all your dependencies. There are a number of options depending on what you want to do, i.e. if it's an application which is meant to be run by an end-user you could look into the one-jar Maven plugin.
I recommend that you take a look at the Maven shade plugin. This produces an "uber-jar" comprising your project and all of its dependencies. It can also do other things such as setting the entry point class to make your JAR file an executable JAR.
You may also find exec-maven-plugin helpful
mvn exec:java -Dexec.mainClass="com.example.Main" [-Dexec.args="argument1"] ...
mvn exec:exec -Dexec.executable="maven" [-Dexec.workingdir="/tmp"] -Dexec.args="-X myproject:dist"
If your client can not download dependencies from maven m2 repo on the fly like behind firewall or no internet connection, then you also need to package the dependencies using maven-dependency-plugin to copy all dependencies and maven-assembly-plugin to assemble dependencies
It doesn't work because Maven resolves dependencies when building your project, but doesn't put all the dependencies magically in your jar. You're supposed to run your app with all its dependencies in the classpath:
java -classpath X.jar;Y.jar com.foo.bar.Main
Or you have to customize the maven jar plugin in order to create an executable jar, as described here. And you may also use the maven assemby plugin to copy all your Y project's dependencies to the target directory, next to the generated Y.jar.
The artifact produced in project Y contains only build results in project Y only, not including its dependencies.
If you want to build a JAR in Y, which u can execute directly, you can consider using assembly plugin.
For example, the easiest way to build a uber-jar for project Y:
<project>
...
<build>
...
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-all-in-one-jar</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
...
</project>
Apart from a normal artifact, an assembly which contains classes etc from dependencies will be created, which is suitable to be executed by java -jar
visit http://maven.apache.org/plugins/maven-assembly-plugin/ for more sophisticated usage.
Phil Sacre already explained the basic problem well (there basically is just no information on where to find the X.jar embedded in your Y.jar).
Additionally you can also look at the appassembler-maven-plugin (which can e.g. generate launch scripts for your Y project that already have the right classpath set) and/or the exec-maven-plugin (which you can use to e.g. directly launch Y with the right classpath using maven).