Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the path to the currently running Java command-line path? (before symbolic links)

I've written a program that outputs a usage hint. It currently echos back the path to the main jar file as was originally entered on the command line.

Usage: java -jar path/to/MyJar.jar <params> ...

For completeness, I'd like to make sure that the java bit is echoed back as well, as there are various ways to access java, (beyond just the word java, and shorter than the canonical path to /us/opt/java-1.8.0-u123/bin/java)

Usage: /us/opt/java7/bin/java -jar MyJar.jar <params> ...
Usage: ./bin/java -jar MyJar.jar <params> ...
Usage: java -jar MyJar.jar <params> ...
# whatever the user typed in

How can I determine what command-line was used to evoke the JVM?
I would like the original command-line value, prior to evaluating symbolic links.

I'm not using System.getProperty("java.home") because it has no respect for the original command-line value, just the final 'canonical' location of the JVM. (Having a usage note like Usage: /us/opt/java-1.8.0-u123/jre/bin/java -jar ... would be rather verbose,
especially when using simple java on the command line.)

Is determining the command-line location of java possible using pure Java code?
(i.e. not using a wrapper script in bash)

like image 766
700 Software Avatar asked Nov 09 '22 11:11

700 Software


1 Answers

Use following command

jps -mlvV

This should print everything about running java processes.

Where as ps -e should give you executable path.

Following is pure Java solution, it doesn't print the actual command used to execute the application but it produces a command which will have the same effect.

import java.io.File;
import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.Map.Entry;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        System.out.println("Printing command");
        createCommand();
    }
    public static void createCommand() {
        try {
            String jvm = getJvmExecutable();
            String mainClassName = findMainClass();
            String processDir = System.getProperty("user.dir");


            String arguments = getArguments();
            String classpath = ManagementFactory.getRuntimeMXBean().getClassPath();


            String command = String.format("cd %s & %s %s -classpath %s %s",processDir, jvm, arguments, classpath, mainClassName);

            System.out.println(command);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private static String getJvmExecutable() {
        String jvm = "";
        jvm = System.getProperty("java.home");
        jvm += File.separator + "bin" + File.separator + "java";
        jvm = '"' + jvm + '"';
        return jvm;
    }

    private static String getArguments() {
        List<String> argsList = ManagementFactory.getRuntimeMXBean().getInputArguments();
        String args = argsList.stream().collect(Collectors.joining(" "));

        return args;
    }

    public static String findMainClass() throws ClassNotFoundException{
        for (Entry<Thread, StackTraceElement[]> entry : Thread.getAllStackTraces().entrySet()) {
            Thread thread = entry.getKey();
            if (thread.getThreadGroup() != null && thread.getThreadGroup().getName().equals("main")) {
                for (StackTraceElement stackTraceElement : entry.getValue()) {
                    if (stackTraceElement.getMethodName().equals("main")) {

                        try {
                            Class<?> c = Class.forName(stackTraceElement.getClassName());
                            Class[] argTypes = new Class[] { String[].class };
                            //This will throw NoSuchMethodException in case of fake main methods
                            c.getDeclaredMethod("main", argTypes);
                            return stackTraceElement.getClassName();
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null;
    }
}

Note: It will work with plain java projects or normal JARS, however it will not work with special classloading like WAR, OSGI or Spring Boot's classloading.

I used the findMainClass() method from this answer https://stackoverflow.com/a/8275751/5343269

like image 69
11thdimension Avatar answered Nov 14 '22 23:11

11thdimension