How to specify JVM argument for Maven built executable JAR
Asked Answered
T

5

11

When using Maven to build an executable JAR, how do I specify the JVM arguments that are used when the JAR is executed?

I can specify the main class using <mainClass>. I suspect there's a similar attribute for JVM arguments. Specially I need to specify the maximum memory (example -Xmx500m).

Here's my assembly plugin:

  <plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <mainClass>com.me.myApplication</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>

Edit/Follow-up: It seems that it might not be possible to specify JVM arguments for an executable JAR according to this and this post.

Triquetrous answered 11/10, 2008 at 0:43 Comment(0)
T
5

I don't know of any such mechanism. The JVM configuration is specified by the calling java command.

Here's the jar file specification which conspicuously doesn't mention any attribute other than Main-Class for stand-alone execution:

http://java.sun.com/javase/6/docs/technotes/guides/jar/jar.html

Tractor answered 12/10, 2008 at 2:34 Comment(0)
N
3

First off, let me say that anything this tricky is probably hard for a reason.

This approach that may work for you if you really need it. As written, it assumes "java" is on the caller's path.

Overview:

  1. Declare a Bootstrapper class as the main class in the jar's manifest.

  2. The bootstrapper spawns another process in which we call java (passing in any command-line arguments you want) on the "real" main class.

  3. Redirect the child processes System.out and System.err to the bootstrapper's respective streams

  4. Wait for the child process to finish

Here's a good background article.

src/main/java/scratch/Bootstrap.java - this class is defined in pom.xml as the jar's mainclass: <mainClass>scratch.Bootstrap</mainClass>

package scratch;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;

public class Bootstrap {
    class StreamProxy extends Thread {
        final InputStream is;
        final PrintStream os;

        StreamProxy(InputStream is, PrintStream os) {
            this.is = is;
            this.os = os;
        }

        public void run() {
            try {
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                String line = null;
                while ((line = br.readLine()) != null) {
                    os.println(line);
                }
            } catch (IOException ex) {
                throw new RuntimeException(ex.getMessage(), ex);
            }
        }
    }

    private void go(){
        try {
            /*
             * Spin up a separate java process calling a non-default Main class in your Jar.  
             */
            Process process = Runtime.getRuntime().exec("java -cp scratch-1.0-SNAPSHOT-jar-with-dependencies.jar -Xmx500m scratch.App");

            /*
             * Proxy the System.out and System.err from the spawned process back to the user's window.  This
             * is important or the spawned process could block.
             */
            StreamProxy errorStreamProxy = new StreamProxy(process.getErrorStream(), System.err);
            StreamProxy outStreamProxy = new StreamProxy(process.getInputStream(), System.out);

            errorStreamProxy.start();
            outStreamProxy.start();

            System.out.println("Exit:" + process.waitFor());
        } catch (Exception ex) {
            System.out.println("There was a problem execting the program.  Details:");
            ex.printStackTrace(System.err);

            if(null != process){
                try{
                    process.destroy();
                } catch (Exception e){
                    System.err.println("Error destroying process: "+e.getMessage());
                }
            }
        }
    }

    public static void main(String[] args) {
        new Bootstrap().go();
    }

}

src/main/java/scratch/App.java - this is the normal entry point for your program

package scratch;

public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World! maxMemory:"+Runtime.getRuntime().maxMemory() );
    }
}

Calling: java -jar scratch-1.0-SNAPSHOT-jar-with-dependencies.jar Returns:

Hello World! maxMemory:520290304
Exit:0
Nollie answered 12/10, 2008 at 18:20 Comment(1)
This really seems more like a fragile hack. Considering that on many, many machines, java(.exe) is either not in the PATH, or the one in the PATH is not the one the caller would want to use, I can't see how this wouldn't cause more problems than solve.Outsider
U
0

In response to David Carlson's answer, you can make it less brittle by using the java.home system property to locate the java executable instead of relying on the user's path to find it. In addition you should probably be redirecting standard input to the child process as well.

Unplug answered 5/6, 2013 at 16:57 Comment(0)
I
0

I think this can be done if you think of it this way. Generate a .bat file that will have a command:

> java .. yourClass.. -D<jvmOption1> -D<jvmOption2>...

You can try looking on this app assembler plugin for maven.

I tried it, and seems to work. I am still not clear how to make .bat file to be generated with the somewhat different content, but I think it is doable.

As another option, you may always try to create the .bat file in the resource sub folder of your project and include that sub folder with your distribution.

Ironworks answered 16/4, 2018 at 21:31 Comment(0)
P
-2

Ancient question but came up on my Google search for this exact problem so I'm answering it.

Try

<configuation>
...
<argLine> -Xmx500m </argLine>
...
</configuation>
Parasitize answered 21/10, 2011 at 10:16 Comment(1)
If this piece of XML code is for Maven exec plugin, than FYI it will not solve the OT problem...Thyratron

© 2022 - 2024 — McMap. All rights reserved.