Как программно получить все установленные Java JVM (не по умолчанию), используя Java? - PullRequest
8 голосов
/ 27 июня 2011

Кто-нибудь знает, как программно получить все установленные JVM (не по умолчанию) с использованием Java ?

Например, на компьютере пользователя установлено 2 JVM:

JDK 5
JDK 6

Мне нужно знать все установленные версии, чтобы переключить ту, которая используется (по умолчанию), и затем программно вызвать javac для компиляции некоторого исходного кода с использованием определенной версии JDK.

Я искал некоторую информацию в Интернете, я нашел:

Но я не смог найти то, что искал.

Ответы [ 10 ]

13 голосов
/ 07 августа 2012

Я недавно имел дело с очень похожей ситуацией. Следующий код делает почти то, что вам нужно. Он ищет java JRE и JDK, не только JDK, но его довольно легко редактировать в соответствии с вашими потребностями. Осторожно: только для окон

/**
 * Java Finder by petrucio@stackoverflow(828681) is licensed under a Creative Commons Attribution 3.0 Unported License.
 * Needs WinRegistry.java. Get it at: /49612/chtenie-zapis-v-reestr-windows-s-ispolzovaniem-java
 *
 * JavaFinder - Windows-specific classes to search for all installed versions of java on this system
 * Author: petrucio@stackoverflow (828681)
 *****************************************************************************/

import java.util.*;
import java.io.*;

/**
 * Helper class to fetch the stdout and stderr outputs from started Runtime execs
 * Modified from http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4
 *****************************************************************************/
class RuntimeStreamer extends Thread {
    InputStream is;
    String lines;

    RuntimeStreamer(InputStream is) {
        this.is = is;
        this.lines = "";
    }
    public String contents() {
        return this.lines;
    }

    public void run() {
        try {
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader    br  = new BufferedReader(isr);
            String line = null;
            while ( (line = br.readLine()) != null) {
                this.lines += line + "\n";
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();  
        }
    }

    /**
     * Execute a command and wait for it to finish
     * @return The resulting stdout and stderr outputs concatenated
     ****************************************************************************/
    public static String execute(String[] cmdArray) {
        try {
            Runtime runtime = Runtime.getRuntime();
            Process proc = runtime.exec(cmdArray);
            RuntimeStreamer outputStreamer = new RuntimeStreamer(proc.getInputStream());
            RuntimeStreamer errorStreamer  = new RuntimeStreamer(proc.getErrorStream());
            outputStreamer.start();
            errorStreamer.start();
            proc.waitFor();
            return outputStreamer.contents() + errorStreamer.contents();
        } catch (Throwable t) {
            t.printStackTrace();
        }
        return null;
    }
    public static String execute(String cmd) {
        String[] cmdArray = { cmd };
        return RuntimeStreamer.execute(cmdArray);
    }
}

/**
 * Helper struct to hold information about one installed java version
 ****************************************************************************/
class JavaInfo {
    public String  path;        //! Full path to java.exe executable file
    public String  version;     //! Version string. "Unkown" if the java process returned non-standard version string
    public boolean is64bits;    //! true for 64-bit javas, false for 32

    /**
     * Calls 'javaPath -version' and parses the results
     * @param javaPath: path to a java.exe executable
     ****************************************************************************/
    public JavaInfo(String javaPath) {
        String versionInfo = RuntimeStreamer.execute( new String[] { javaPath, "-version" } );
        String[] tokens = versionInfo.split("\"");

        if (tokens.length < 2) this.version = "Unkown";
        else this.version = tokens[1];
        this.is64bits = versionInfo.toUpperCase().contains("64-BIT");
        this.path     = javaPath;
    }

    /**
     * @return Human-readable contents of this JavaInfo instance
     ****************************************************************************/
    public String toString() {
        return this.path + ":\n  Version: " + this.version + "\n  Bitness: " + (this.is64bits ? "64-bits" : "32-bits");
    }
}

/**
 * Windows-specific java versions finder
 *****************************************************************************/
public class JavaFinder {

    /**
     * @return: A list of javaExec paths found under this registry key (rooted at HKEY_LOCAL_MACHINE)
     * @param wow64  0 for standard registry access (32-bits for 32-bit app, 64-bits for 64-bits app)
     *               or WinRegistry.KEY_WOW64_32KEY to force access to 32-bit registry view,
     *               or WinRegistry.KEY_WOW64_64KEY to force access to 64-bit registry view
     * @param previous: Insert all entries from this list at the beggining of the results
     *************************************************************************/
    private static List<String> searchRegistry(String key, int wow64, List<String> previous) {
        List<String> result = previous;
        try {
            List<String> entries = WinRegistry.readStringSubKeys(WinRegistry.HKEY_LOCAL_MACHINE, key, wow64);
            for (int i = 0; entries != null && i < entries.size(); i++) {
                String val = WinRegistry.readString(WinRegistry.HKEY_LOCAL_MACHINE, key + "\\" + entries.get(i), "JavaHome", wow64);
                if (!result.contains(val + "\\bin\\java.exe")) {
                    result.add(val + "\\bin\\java.exe");
                }
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
        return result;
    }

    /**
     * @return: A list of JavaInfo with informations about all javas installed on this machine
     * Searches and returns results in this order:
     *   HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment (32-bits view)
     *   HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment (64-bits view)
     *   HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit     (32-bits view)
     *   HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit     (64-bits view)
     *   WINDIR\system32
     *   WINDIR\SysWOW64
     ****************************************************************************/
    public static List<JavaInfo> findJavas() {
        List<String> javaExecs = new ArrayList<String>();

        javaExecs = JavaFinder.searchRegistry("SOFTWARE\\JavaSoft\\Java Runtime Environment", WinRegistry.KEY_WOW64_32KEY, javaExecs);
        javaExecs = JavaFinder.searchRegistry("SOFTWARE\\JavaSoft\\Java Runtime Environment", WinRegistry.KEY_WOW64_64KEY, javaExecs);
        javaExecs = JavaFinder.searchRegistry("SOFTWARE\\JavaSoft\\Java Development Kit",     WinRegistry.KEY_WOW64_32KEY, javaExecs);
        javaExecs = JavaFinder.searchRegistry("SOFTWARE\\JavaSoft\\Java Development Kit",     WinRegistry.KEY_WOW64_64KEY, javaExecs);

        javaExecs.add(System.getenv("WINDIR") + "\\system32\\java.exe");
        javaExecs.add(System.getenv("WINDIR") + "\\SysWOW64\\java.exe");

        List<JavaInfo> result = new ArrayList<JavaInfo>();
        for (String javaPath: javaExecs) {
            if (!(new File(javaPath).exists())) continue;
            result.add(new JavaInfo(javaPath));
        }
        return result;
    }

    /**
     * @return: The path to a java.exe that has the same bitness as the OS
     * (or null if no matching java is found)
     ****************************************************************************/
    public static String getOSBitnessJava() {
        String arch      = System.getenv("PROCESSOR_ARCHITECTURE");
        String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432");
        boolean isOS64 = arch.endsWith("64") || (wow64Arch != null && wow64Arch.endsWith("64"));

        List<JavaInfo> javas = JavaFinder.findJavas();
        for (int i = 0; i < javas.size(); i++) {
            if (javas.get(i).is64bits == isOS64) return javas.get(i).path;
        }
        return null;
    }

    /**
     * Standalone testing - lists all Javas in the system
     ****************************************************************************/
    public static void main(String [] args) {
        List<JavaInfo> javas = JavaFinder.findJavas();
        for (int i = 0; i < javas.size(); i++) {
            System.out.println("\n" + javas.get(i));
        }
    }
}

Вам также понадобится обновленный WinRegistry.java для чтения значений как из 32-битных, так и из 64-битных разделов реестра Windows: https://stackoverflow.com/a/11854901/828681

Я обычно не программист Java, поэтому мой код, вероятно, не соответствует соглашениям Java. Подайте в суд на меня.

Вот пример запуска с моей 64-битной машины Win 7:

>java JavaFinder

C:\Program Files (x86)\Java\jre6\bin\java.exe:
  Version: 1.6.0_31
  Bitness: 32-bits

C:\Program Files\Java\jre6\bin\java.exe:
  Version: 1.6.0_31
  Bitness: 64-bits

D:\Dev\Java\jdk1.6.0_31\bin\java.exe:
  Version: 1.6.0_31
  Bitness: 64-bits

C:\Windows\system32\java.exe:
  Version: 1.6.0_31
  Bitness: 64-bits

C:\Windows\SysWOW64\java.exe:
  Version: 1.6.0_31
  Bitness: 32-bits
3 голосов
/ 04 ноября 2011

Я сделал быструю проверку реестра Windows, и этот ключ, кажется, предоставляет различные версии Java, установленные в системе

HKEY_LOCAL_MACHINE \ SOFTWARE \ JavaSoft \ Java Runtime Environment

При дальнейшем поиске в Google было подтверждено, что это правильное местоположение. Прочитайте эти статьи для деталей ...

Быстрое получение доступной Java JVM на рабочей станции (Windows)

Java 2 Runtime Environment для Microsoft Windows

3 голосов
/ 01 августа 2012

На платформах Windows вы можете запросить, существует ли установленный JRE:

java -version:1.6 -version

Эта команда вернется с "java version" 1.6.0_xx "", если она у вас установлена.Если он не установлен, он скажет: «Невозможно найти спецификацию совещания JRE 1.6»

Похоже, что это не работает в Linux, возможно потому, что в Linux нет стандартного способа установки Java.

2 голосов
/ 27 июня 2011

В принципе, нет способа перечислить всю JVM, даже не из кода Java. Рассмотрим различные платформы, разных поставщиков JDK, JDK в комплекте с другими продуктами, от баз данных до авиасимулятора и движка рендеринга видео. Большая часть JDK - это простая ссылка на другую, например, v.1.2 указывает на установленный v.6. Обычное дело - как получить версию: java -version Но у нас есть несколько моментов:

  1. Для Windows посмотрите реестр HKEY_LOCAL_MACHINE \ Software \ JavaSoft \. Также рассмотрим режим Wow6432Node для 64-битной ОС. Проверьте продукты от основных поставщиков, которые создают программное обеспечение на Java.
  2. Mac OS X /System/Library/Frameworks/JavaVM.framework/Versions + Open JDK
  3. Linux и некоторые другие Unix - какие java, / etc / alternatives / java rpm -qa | grep java и т. Д.
1 голос
/ 12 февраля 2013

В командной строке Windows вы можете запустить следующие 2 команды (или запустить вместе как командный файл). Это будет выглядеть в Windows Установка и удаление программ (записи реестра) и сообщит, какие версии JAVA найдены с помощью ссылок установки / удаления, вместе с путем к папке и некоторыми другими вещами.

wmic product where "name LIKE '%%java%%'" get * /format:textvaluelist > temp_javavers.txt 

notepad.exe temp_javavers.txt
1 голос
/ 27 июня 2011

установлено довольно расплывчато - даже если JRE и JDK поставляются с установщиком , на самом деле нам просто нужно скопировать файлы JRE или JDK на компьютер и используйте сразу.

Так что в общем случае вам нужно найти все java или java.exe исполняемые файлы на вашем локальном компьютере и вызвать java -versionчтобы увидеть 1 , если этот исполняемый файл с именем java / java.exe действительно является (частью) JRE.


Только что увидел, что вы попросили для JVM и хотите вызвать компилятор. Если вы ищете JDK, используйте описанный выше метод, но найдите все javac / javac.exe.У них тоже есть опция -version.


1 нет риска - нет удовольствия , который идет с этим методом - пожалуйста, внимательно посмотрите наКомментарий Шона!Если вы не можете доверять машине (или пользователям ), то вы можете проверить, является ли исполняемый файл скриптом / пакетом или двоичным файлом, даже если двоичный файл можетПротрите свой диск тоже, даже оригинальный исполняемый файл javac может быть заменен каким-то злобным кодом ...

0 голосов
/ 06 августа 2012

Как уже говорилось, HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment должен перечислять доступные JVM, НО я только что узнал, что, хотя этот реестр в настоящее время перечисляет только 64-битную 1.6.0_31 JVM на моей машине, у меня также есть 32-битная Java, установленная подC:\Windows\SysWOW64.

Таким образом, информация, указанная в реестре, не отображает полную картину, и если вы хотите запустить 32-битную JVM в 64-битной Windows, вам также следует попробовать C:\Windows\SysWOW64.

0 голосов
/ 27 июня 2011

Чтобы найти версии Java, лучший подход, чем поиск javac.exe, - проверить реестр. Java создает раздел реестра HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment со строкой CurrentVersion, для которой задан номер версии, например 1,5 или 1,6.

Вы можете использовать эту информацию для поиска JVM:

  • HKEY_LOCAL_MACHINE \ Software \ JavaSoft \ Java Runtime Environment \ 1.5 \ JavaHome = C: \ Program Files \ Java \ j2re1.5
  • HKEY_LOCAL_MACHINE \ Software \ JavaSoft \ Java Runtime Environment \ 1.5 \ RuntimeLib = C: \ Program Files \ Java \ j2re1.4.2 \ bin \ client \ jvm.dll

Вы можете увидеть больше здесь: http://java.sun.com/j2se/1.4.2/runtime_win32.html

Я не знаком с доступом к реестру из Java, но вы всегда можете запустить интерфейс командной строки regedit и проанализировать результаты, что я и сделал.

0 голосов
/ 27 июня 2011

.. скомпилируйте некоторый исходный код, используя определенную версию JDK.

Используйте JavaCompiler (в последнем JDK, на который пользователь может возложить руку) с соответствующими параметрами для -source, -target & -bootclasspath. Последние два являются частью Опции кросс-компиляции из javac.

Что касается поиска JDK, вставьте JFileChooser с путем к текущему JRE в качестве каталога по умолчанию. Если пользователь не может перейти оттуда к JDK, сомнительно, что он должен писать код.

0 голосов
/ 27 июня 2011

Я не уверен, отвечает ли это на ваш вопрос, но вы можете контролировать, какую основную версию JRE будет запускать апплет или приложение WebStart, используя функцию семейного управления версиями.Это позволяет вам указать основной выпуск Java, на котором работает апплет.Вы должны быть в состоянии получить местоположение javac оттуда.

http://www.oracle.com/technetwork/java/javase/family-clsid-140615.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...