5

I would like to find the JDK path on multiple operating systems.

I'm not sure if there's a nice way of doing this as I've been trying and failing.

For Windows it would be something like this - C:\Program Files\Java\jdk1.7.0_07 or this C:\Program Files(x86)\Java\jdk1.7.0_07

For Linux it would be something like this - /usr/java/jdk1.7.0_07

I want this to work for any version of JDK installed, so the numbers after Java\jdk are irrelevant.

I will be using System.setProperty("java.home", path);

Basically, what I am looking to do is when I run my program, set java.home to be the JDK installed on the current machine, but getting the JDK path is proving very difficult, any solutions?

Jakob Weisblat
  • 7,450
  • 9
  • 37
  • 65
Ciphor
  • 732
  • 4
  • 11
  • 25
  • 2
    Why do you need to find the path of the JDK? I'm confused as to why one would want this information. – Makoto Mar 31 '13 at 02:07
  • 4
    this is what the `JAVA_HOME` environment variable is for! –  Mar 31 '13 at 02:08
  • I'm using it to compile other classes. My program, compiles other programs. – Ciphor Mar 31 '13 at 02:08
  • Maybe he's trying to create a easy way to fix some troubles that can be caused by this path. – Castiblanco Mar 31 '13 at 02:09
  • `System.getProperty("java.home")` might get you started – jedwards Mar 31 '13 at 02:09
  • @jedwards, I will be using `System.setProperty("java.home", path);` – Ciphor Mar 31 '13 at 02:10
  • Be aware, many system properties are read once when the JVM starts. It is probably too late to set "java.home" once you are able to do so. See the warning in `Writing System Properties` here http://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html . – Christian Trimble Apr 08 '13 at 19:25
  • You may want to have a look at `Going Native` by Brian McCallister http://theholyjava.wordpress.com/2012/09/25/using-java-as-native-linux-apps-calling-c-daemonization-packaging-cli-brian-mccallister/ . Although this talk focuses on Unix like operating systems, you probably want something like his daemonization code. – Christian Trimble Apr 08 '13 at 19:28
  • 2
    This question is very ambiguous. There can be many JDKs installed so we are not talking about one JDK path but about multiple JDK paths. Second off, is it that you want to find the path to the java binary that is currently executing your code? So you need to clarify, find all JDK paths or find the path of the JDK that is currently executing the .class (doing the lookup). – Menelaos Apr 09 '13 at 14:38
  • Your question is ambiguous. Your comment referring to a 'current machine' suggests that your program could run on various machines with an unknown environment - hence your wish to detect a jdk. As others have said, there may be more than one installation. There is no guarantee that any detected install would be able to compile the code you supply it (e.g. 1.7 code, 1.6 jdk). Could your users specify a jdk, if not what is the use case? – Romski Apr 11 '13 at 13:57
  • Just curious ... if u want to compile other java code at runtime, why not use the Java Compiler API ? Unless you are invoking the java compiler by using the Runtime exec() – Satiya Prasath Apr 11 '13 at 11:18

13 Answers13

8

You may be able to find the JDK path by looking to see where javac is installed. Assuming that "javac" is within the environment paths of the system then you can retrieve the path by passing "where javac" to code such as the following

public static String getCommandOutput(String command)  {
    String output = null;       //the string to return

    Process process = null;
    BufferedReader reader = null;
    InputStreamReader streamReader = null;
    InputStream stream = null;

    try {
        process = Runtime.getRuntime().exec(command);

        //Get stream of the console running the command
        stream = process.getInputStream();
        streamReader = new InputStreamReader(stream);
        reader = new BufferedReader(streamReader);

        String currentLine = null;  //store current line of output from the cmd
        StringBuilder commandOutput = new StringBuilder();  //build up the output from cmd
        while ((currentLine = reader.readLine()) != null) {
            commandOutput.append(currentLine);
        }

        int returnCode = process.waitFor();
        if (returnCode == 0) {
            output = commandOutput.toString();
        }

    } catch (IOException e) {
        System.err.println("Cannot retrieve output of command");
        System.err.println(e);
        output = null;
    } catch (InterruptedException e) {
        System.err.println("Cannot retrieve output of command");
        System.err.println(e);
    } finally {
        //Close all inputs / readers

        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                System.err.println("Cannot close stream input! " + e);
            }
        } 
        if (streamReader != null) {
            try {
                streamReader.close();
            } catch (IOException e) {
                System.err.println("Cannot close stream input reader! " + e);
            }
        }
        if (reader != null) {
            try {
                streamReader.close();
            } catch (IOException e) {
                System.err.println("Cannot close stream input reader! " + e);
            }
        }
    }
    //Return the output from the command - may be null if an error occured
    return output;
}

The string returned will be the exact location of javac so you may need extra processing to get the directory that javac resides in. You will need to distinguish between Windows and other OS

public static void main(String[] args) {

    //"where" on Windows and "whereis" on Linux/Mac
    if (System.getProperty("os.name").contains("win") || System.getProperty("os.name").contains("Win")) {
        String path = getCommandOutput("where javac");
        if (path == null || path.isEmpty()) {
            System.err.println("There may have been an error processing the command or ");
            System.out.println("JAVAC may not set up to be used from the command line");
            System.out.println("Unable to determine the location of the JDK using the command line");
        } else {
            //Response will be the path including "javac.exe" so need to
            //Get the two directories above that
            File javacFile = new File(path);
            File jdkInstallationDir = javacFile.getParentFile().getParentFile();
            System.out.println("jdk in use at command line is: " + jdkInstallationDir.getPath());
        }//else: path can be found
    } else {
        String response = getCommandOutput("whereis javac");
        if (response == null) {
            System.err.println("There may have been an error processing the command or ");
            System.out.println("JAVAC may not set up to be used from the command line");
            System.out.println("Unable to determine the location of the JDK using the command line");
        } else {
            //The response will be "javac:  /usr ... "
            //so parse from the "/" - if no "/" then there was an error with the command
            int pathStartIndex = response.indexOf('/');
            if (pathStartIndex == -1) {
                System.err.println("There may have been an error processing the command or ");
                System.out.println("JAVAC may not set up to be used from the command line");
                System.out.println("Unable to determine the location of the JDK using the command line");
            } else {
                //Else get the directory that is two above the javac.exe file
                String path = response.substring(pathStartIndex, response.length());
                File javacFile = new File(path);
                File jdkInstallationDir = javacFile.getParentFile().getParentFile();
                System.out.println("jdk in use at command line is: " + jdkInstallationDir.getPath());
            }//else: path found
        }//else: response wasn't null
    }//else: OS is not windows
}//end main method

Note: if the method returns null / error it doesn't mean that javac doesn't exist - it will most likely be that javac isn't within the PATH environment variable on windows and so cannot be found using this method. This isn't likely on Unix as Unix usually adds the jdk/bin directory to the PATH automatically. Also, this will return the javac version currently in use at command line, not necessarily the latest version installed. so if e.g. 7u12 and 7u13 are installed but command prompt is set to use 7u12 then that's the path that will be returned.

Only tested on multiple Windows machines but works fine on them.

Hope this is helpful.

tomgeraghty3
  • 1,234
  • 6
  • 10
2

JAVA_HOME is supposed to point to JDK installation path and JRE_HOME to JRE installation path in all OS

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
  • That's what I think is the correct solution too, but the official [installation guide](http://docs.oracle.com/javase/7/docs/webnotes/install/windows/jdk-installation-windows.html) doesn't say anything about `JAVA_HOME` – Sotirios Delimanolis Apr 10 '13 at 16:21
2

I don't know what the big deal is.

public class Main implements Serializable{
    public static void main(String[] args) {
        System.out.println(System.getenv("JAVA_HOME"));
    }
}

Prints C:\Program Files\Java\jdk1.7.0 on windows and /usr/java/jdk1.7.0_13 on unix system. If the environment property JAVA_HOME isn't set, then null is returned. You should take that to mean that java hasn't been correctly installed/configured and therefore your application can't function.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
2

Your best bet is probably to look at the value of System.getProperty("sun.boot.class.path"), tokenize it on the value of System.getProperty("path.separator"), and look for standard JDK JAR files.

For example, on my system, I get (truncated for readability):

sun.boot.class.path = "/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/jsse.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/laf.jar:"

and

path.separator = ":"

This easily lets me work out that all system JAR files are in /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/.

Unfortunately, this isn't terribly helpful because I'm running OS X, which has a non-standard Java installation structure. If you're not targeting OS X machines, you can work out the installation directory through the value we just computed (I believe it's the value's parent directory).

If you also want to support OS X, you might have to use the os.name system property and write add-hoc code.

Nicolas Rinaudo
  • 6,068
  • 28
  • 41
1

The JAVA_HOME variable in System.getProperties() refers to the JRE and not the JDK. You should be able to find the JDK with:

Map<String, String> env = System.getenv();
 for (String envName : env.keySet())
 {
 System.out.format("%s=%s%n",
 envName,
 env.get(envName));
 }
Sukane
  • 2,632
  • 3
  • 18
  • 19
0

System.getProperty("java.home") not good enough for you?

If it ends in "jre" you'll know that's the jre, you could try to walk and find the root folders and check for distinct files that come only with the JDK to be sure.

Gubatron
  • 6,222
  • 5
  • 35
  • 37
  • 2
    System.getProperty("java.home") will give me JRE – Ciphor Mar 31 '13 at 02:11
  • can't you use that folder as a starting point? walk to the parent, then check for certain files to see if the JRE you're using is the one that comes with the JDK, or if it's just a simple JRE – Gubatron Mar 31 '13 at 02:15
0

The JAVA_HOME variable in System.getProperties() refers to the JRE and not the JDK. You should be able to find the JDK with:

Map<String, String> env = System.getenv();
        for (String envName : env.keySet())
        {
            System.out.format("%s=%s%n",
                    envName,
                    env.get(envName));
        }
Héctor van den Boorn
  • 1,218
  • 13
  • 32
  • This lists every single environment variable! Pretty cool, but I need a way of extracting just that one path? Any ideas? – Ciphor Mar 31 '13 at 02:18
0

Here is my take on this: You can choose where you want to install jdk and also you can install multiple jdk's. So i dont think there can be a standard variable for this.

Lets assume standard directory structure has been used for installing jdk. In this scenario jre and jdk installations will lie under same directory.

So once you get System.getProperty("java.home") then simple search the directory.

Hope that helps.

Lokesh
  • 7,810
  • 6
  • 48
  • 78
0

God this was so convoluted, but I got it done. Though it has only has been test on Windows.

import java.io.File;

public class Main {
    public static void main(String[] args) {
        String JDK_VERSION = "jdk" + System.getProperty("java.version"); // finds the JDK version currently installed
        String PATH_VARIABLE = System.getenv("PATH"); // finds all the system environment variables

        // separates all the system variables
        String[] SYSTEM_VARIABLES = PATH_VARIABLE.split(";");

        // this object helps build a string
        StringBuilder builder = new StringBuilder();

        // loop through all the system environment variables
        for (String item : SYSTEM_VARIABLES) {
            // if the system variable contains the JDK version get it! (all lower case just to be safe)
            if (item.toLowerCase().contains(JDK_VERSION.toLowerCase())) {
                // adds the JDK path to the string builder
                builder.append(item);
            }
        }

        // stores the JDK path to a variable
        String result = builder.toString();
        // turns the path, which was a string in to a usable file object.
        File JDK_PATH = new File(result);
        // since the path is actually in the JDK BIN folder we got to go back 1 directory
        File JDK_PATH_FINAL = new File(JDK_PATH.getParent());
        // prints out the result
        System.out.println(JDK_PATH_FINAL);
    }
}

What is basically does is get all the system variables and finds if one of the contains the java version (my way of getting the path to the JDK). Since the system variable path is actually in the JDK bin folder it turns the JDK path String to a File and goes back one folder into the JDK directory.

Joban
  • 1,318
  • 7
  • 19
  • this wont work always when installing i can change the path and semi colon is not the File separator for all OSes use the constants – tgkprog Apr 10 '13 at 11:02
0

You can use the getenv function of java to get the PATH.

0

I think your best and surest bet (because Java_home etc do not HAVE to be declared to get a JVM up, I can use full paths in a script and launch Java.

Get java process id, use an API to get the path of that process.

This is not a full solution but a guide line for how to do it.

If you are sure that java.home is set accurately in all your java apps then can use that as described in other answers

Help to get a process id's path How do I get the path of a process in Unix / Linux

similarly need for windows. am sure its there as have seen it in tools

Community
  • 1
  • 1
tgkprog
  • 4,493
  • 4
  • 41
  • 70
0

If you want to compile programs in your program why don't you just take the following approach:

    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    compiler.run(/* your arguments here */);

Full description here.

Community
  • 1
  • 1
Nándor Krácser
  • 1,128
  • 8
  • 13
0

After thinking about the answer of @Nicolas Rinaudo, I started to write something that just checks any path in the System's properties. I tested this on Windows 10 and Linux (Debian 9) and it pretty much works.

private static final Pattern JDK_REGEX = Pattern.compile("jdk[0-9].[0-9].[0-9]_(.*?)" + StringEscapeUtils.escapeJava(File.separator));

public static String findJDKPath() {
        Enumeration<Object> properties = System.getProperties().elements();
        List<String> possibilities = new ArrayList<>();
        String separator = System.getProperty("path.separator");
        while(properties.hasMoreElements()) {
            Object element = properties.nextElement();
            if (!(element instanceof String)) {
                continue;
            }
            String string = (String) element;
            String[] split = string.split(separator);
            for(String s : split) {
                if (s.contains("jdk") && s.contains(File.separator)) {
                    possibilities.add(s);
                }
            }
        }
        for(String s : possibilities) {
            Matcher matcher = JDK_REGEX.matcher(s);
            if (matcher.find()) {
                String group = matcher.group();
                return s.substring(0, s.indexOf(group) + group.length());
            }
        }
        return null;
    }
Displee
  • 670
  • 8
  • 20