Simple as that, I am trying to deploy this app https://github.com/pac4j/spark-pac4j-demo to my heroku instance.
I can run it locally with: mvn compile exec:java
But on heroku, there is no maven installed:
2016-04-12T18:34:21.074629+00:00 heroku[web.1]: Starting process with command `mvn compile exec:java`
2016-04-12T18:34:23.303776+00:00 app[web.1]: bash: mvn: command not found
2016-04-12T18:34:23.303620+00:00 app[web.1]: Setting JAVA_TOOL_OPTIONS defaults based on dyno size. Custom settings will override them.
I have no clue how to set all the class paths per hand. I would appreciate some help here.
You'll first need to vendor your dependencies (i.e. copy them into the target/ directory). You can do so by adding this to your pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals><goal>copy-dependencies</goal></goals>
</execution>
</executions>
</plugin>
Then the correct command to run the app will probably be something like java -cp target/classes:target/dependency/* Main (where Main should be replaced with your class that contains the public static void main method).
Here is a sample app using Spark so you can see how this all comes together.
Maven is not a good way to run an application in production. It creates an additional dependency for your app and adds layers of indirection to the process execution.
Related
I've recently moved to Java 17 and with it came a couple restrictions requiring me to use --add-opens because of one dependency when running my application.
I need to add this when the java -jar command is ran. For now I found these solutions:
I can add it to the command line argument in my Dockerfile that runs the project
java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/sun.util.calendar=ALL-UNNAMED -jar my.jar
I can add it in my MANIFEST.MF through my maven pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Add-Opens>java.base/sun.util.calendar java.base/java.util</Add-Opens>
</manifestEntries>
</archive>
</configuration>
</plugin>
Both work fine for production apparently. However when running my app through IntelliJ, it's not picking up the options which is normal I guess. I have to set them in my run configuration (which is also committed to my project by the way) as VM arguments.
I'm looking for a way to ensure consistency automatically and not have to maintain in parallel two places where I declare my add-opens.
EDIT: I'm wondering if something is doable with argfiles. Like have an argfile inside my project that would be referenced in the jar and that could be referenced in an y run configuration. I haven't found much evidence yet but that's the path I'm currently pursuing.
EDIT 2: I added an addopens file at the root of my project and can now reference this from the various points where I need it. For tests, I added this and it worked out of the box with IntelliJ tests AND maven tests together:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- This adds the options contained in the addopens file to the test JVM arguments -->
<argLine>#addopens #{argLine}</argLine>
</configuration>
</plugin>
I also can ship that addopens file in my docker to use in production. I still need to add to my Run configuration in IntteliJ the #addopens manually.
You can use the option to add the JDK parameters in the maven plugins like surefire plugin.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
--add-opens java.base/java.time=ALL-UNNAMED
${surefireArgLine}
</argLine>
</configuration>
</plugin>
I have tried the above approach for IntelliJ IDE and Java 17 (Temurin-17.0.1). It works fine on running via java -jar command, as well as on running the app via IDE.
If you have multiple such JVM options to add, try keeping those assigned to a property and use that property here in the argLine.
Follow steps: edit run/debug configuration -> add the below option in VM options:
--add-opens java.base/java.lang=ALL-UNNAMED
Current state:
I have a project which is build with: Java 1.8.161, Maven 3.3.9, SpringBoot 2.0.1, tools: Jenkins and GitLab. I would like to use google java format as a standard for whole team.
My investigation / solution:
During the investigation I found solution, which sounds really easy. Just update pom file with:
<build>
<plugins>
<plugin>
<groupId>com.coveo</groupId>
<artifactId>fmt-maven-plugin</artifactId>
<version>2.5.0</version>
<executions>
<execution>
<goals>
<goal>format</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
And it works. If I run compile, package, verify, install or deploy Maven lifecycle the code is formatted.
Question:
How can I run this after i.e. each commit for all team members without any extra steps in their IDEA? Because right now, I need to run Maven before each commit. But during the run of an application it is not necessary, so the team can avoid it.. Which of course will lead to problems with history in git.
You can let pre-commit hook trigger formatter for files staged for commit.
git-code-format-maven-plugin uses google-java-format formatter and can install client-side pre-commit git hook during compile phase. It requires Maven 3.5.x, which should be enforced.
<build>
<plugins>
<plugin>
<groupId>com.cosium.code</groupId>
<artifactId>git-code-format-maven-plugin</artifactId>
<version>VERSION</version>
<executions>
<execution>
<goals>
<goal>install-hooks</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<version>VERSION</version>
<executions>
<execution>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireMavenVersion>
<version>[3.5.4,)</version>
</requireMavenVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Point to standalone Maven in IDE as git-code-format-maven-plugin does not play along nicely with embedded Maven.
mvn compile to get hook installed. For IDEA, that's it.
As git-code-format-maven-plugin only formats changed files (which is good), it is probably good to format whole project upfront once (mvn git-code-format:format-code -Dgcf.globPattern=**/*).
Workaround for Eclipse
Because of a bug in EGit, which sometimes ignores Git hooks completely, developers using Eclipse on Windows should have Cygwin in PATH. An empty cygpath.exe will do. Run 'Command Prompt' as a administrator and execute C:\>echo "" > /"Program Files"/Git/bin/cygpath.exe (kudos to hook is not working eclipse egit client).
Reboot.
A note on java import statements ordering
Optimise imports or reformat in IDE or reformat with plugins, can lead to changes in imports ordering. A nasty surprise if an older version of git-code-format-maven-plugin is being used together with fmt-maven-plugin (to format or validate code later in CI, for example).
git-code-format-maven-plugin will sort imports (since version 1.20)
fmt-maven-plugin will always sort imports
googleformatter-maven-plugin can optionally sort imports (not per default)
In order to run this formatter after each developer commit, you will have to first have a Jenkins commit hook in place, that will trigger a Jenkins build. One of the phases of the build, should execute the fmt-maven-plugin's (or any others) check functionality in order to ensure that the code is properly formatted.
Adding a webhook
First thing to do is add a webhook that will trigger a Jenkins build after every commit in your git repository. You can find how to do this here. For Gitlab specific instructions, this post from medium may be helpful.
Executing the check
This can be done by executing the check goal on the fmt-maven-plugin
Maven acceps either <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal> as a means of calling a plugin goal, so for your specific problem, you can run:
mvn fmt:check
That being said, you will have to add a Jenkins build step, that will run the mentioned command. Step 5 from this tutorial shows you how to add a build step.
Hope that this actually helps :D
I need to run Maven before each commit
You do not need to run multiple maven goals. For eg no need to run maven install for the formatting to take place. A simple maven compile will formate the classes.
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.
I followed this Tutorial:
As init.d service
The executable jar has the usual start, stop, restart, and status
commands. It will also set up a PID file in the usual /var/run
directory and logging in the usual /var/log directory by default.
You just need to symlink your jar into /etc/init.d like so
Assuming that you have a Spring Boot application installed in
/var/myapp, to install a Spring Boot application as an init.d service
simply create a symlink:
$ sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp
Then start the Service with:
/etc/init.d/myapp start
When I do this exactly like it is described there, I get following error in the Ubuntu 14.04 console:
ubuntu#spring:/var/myapp$ /etc/init.d/myapp start
-bash: /etc/init.d/myapp: cannot execute binary file: Exec format error
You can't run a jar this way, since it's just a binary file. You have to run it with the installed java (as it's mentioned in the MrPsion's answer)
java -jar /var/myapp/myapp.jar
But you can't create a symlink to such a command. You can create a bash script, with the command above, make it executable and create a symlink to this script.
Alternatively, in Ubuntu you may use a binfmt-support. Just install it first
sudo apt-get install binfmt-support
Then make your jar executable
chmod a+x myapp.jar
And then you can run it (and use for the symlink) just as:
/var/myapp/myapp.jar
Update:
Since you have a Spring Boot application, check whether your jar is build with the executable property set to true
springBoot {
executable = true
}
This should let you run your jar the way you wanted, whitout make it an executable or require any additional libraries.
One more, according to the comments, the plugin version you're using doesn't support this feature yet. You have to update a plugin version in order to get an executable jar. According to the plugin sources and commit history you need atleast 1.3 version
The answers are incorrect, you can indeed launch a spring boot application jar as a service with init.d. There is even a spring tutorial explaining how to do it, as pointed out by Stanislav: https://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html
The problem was probably in your maven file. I had the same issue and solved it adding the following to my maven file:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.7.RELEASE</version>
<configuration>
<executable>true</executable>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
Detailed instructions here: https://springjavatricks.blogspot.com/2017/11/installing-spring-boot-services-in.html
You need to "execute" the jar using java
java -jar /var/myapp/myapp.jar
and init scripts are not generally links to executable.
This post will show you how to create an init script for java applications.
Run a Java Application as a Service on Linux
This is my first time using maven on a project. Basically, I am working in the src on a webapp and when I am ready to push a change to the target i do a mvn clean install (this was what I was told to do).
The issue is that if I am just making a minor html tweak in a jsp and want to see the results I have to wait for tests, compile copy the war over deploy, server restart and then I have to log in again.
There's got to be a better way to do this. It's making my development speed slow to a crawl.
You can use maven tomcat plugin to run an in-memory tomcat over your maven project. Any jsp or static resource changes will apply immediately. Java code changes still require you to manually stop and start the server.
To do so use following maven goal
mvn clean tomcat:run
One other choice is jetty plugin. add jetty plugin to pom.xml,and run,that's ok.
<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.11.v20130520</version>
<configuration>
<scanIntervalSeconds>0</scanIntervalSeconds>
<contextPath>/</contextPath>
</configuration>
</plugin>
</plugins>
</build>
run your application:
mvn jetty:run