簡単にJREを変更してjarを実行
※本コードはjavaSwitcher:任意のJRE上で実行形式jarファイルを実行するアプリとしてアプリ形式で配布することにしたので参照されたい。また、以下のコードにはカレントディレクトリがそのままになっているというバグがある。本来実行形式jarファイルをダブルクリックして実行する際には、そのjarファイルの置かれたフォルダをカレントとしなくてはいけない
PCに複数のJREをインストールすることはできるが、一度に使用できるのは一つのみである。もちろん、そのパスを指定してjava.exeを実行すれば可能だが、いかにも面倒。もっと楽にJREを選択してjarファイルを実行する方法は無いものかと考えた。
※以下はWindowsを前提としているが、プログラムは改変すれば他の環境でも使用できるかと思う。
環境変数を変更する方法
最初は、環境変数Pathを変更することで何とかならないかと思ったのだが、なぜか自分の環境ではうまくいかなかった。検索してみると、setではなくsetxを使用すれば永続的に変更できるとのことだったのだが、管理者モードで行おうが何をしようが全く変化無し。
一体どのようにすればまともに動くのか未だにわからない。結局のところ、環境変数を変更するには、Rapid Environment Editorで書き換えてセーブ、Windows自体をログアウトして再度ログインなどという非常に面倒な手順を踏まなければいけない。
最終的に採用した方法
最終的に採用した方法としては以下の原理である。
- c:\program files\Javaやc:\program files (x86)\javaにあるすべてのjreのリストを作成する。
- そのうちの一つを実行対象として選択する。
- jarファイルがドロップされたら、一時フォルダにバッチファイルを作成して、それを実行する。バッチファイルの中身としては、
- 上記で選択されたJREのbinフォルダを、ただ一つのPATHとして設定する。
- 上記のjarファイルをjava -jar *.jarで実行する。
- jarファイルの実行が終了したら、一時フォルダのバッチファイルを消す。
やっていることはこれだけである。以下のプログラムを起動すると、次の画面が表示される。
いずれかのJREをクリックした後、下部にjarファイルをドロップすればよい。
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.table.*;
public class Main {
private TableModel tableModel;
private ListSelectionModel selectionModel;
private String tmpDir = System.getProperty("java.io.tmpdir");
void createWindow() {
JFrame frame = new JFrame("JRE SWITCHER ON " + System.getProperty("java.version"));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(50, 50, 400, 300);
frame.setLayout(new BorderLayout());
JTable table = new JTable();
JScrollPane scroll = new JScrollPane(table);
frame.add(scroll, BorderLayout.CENTER);
table.setModel(tableModel = getJres());
(selectionModel = table.getSelectionModel()).setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JLabel dropPanel = new JLabel("Drop Jar file here", SwingConstants.CENTER);
dropPanel.setPreferredSize(new Dimension(400, 100));
frame.add(dropPanel, BorderLayout.PAGE_END);
dropPanel.setDropTarget(new DropTarget() {
@Override
public synchronized void drop(DropTargetDropEvent dtde) {
Transferable transfer = dtde.getTransferable();
if (!transfer.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
return;
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
try {
@SuppressWarnings("unchecked")
List<File> fileList = (List<File>)transfer.getTransferData(DataFlavor.javaFileListFlavor);
execute(fileList.get(0));
} catch (Exception ex) {
error(ex.getMessage());
}
}
});
frame.setVisible(true);
}
private TableModel getJres() {
Object[] cnames = { "JREs", };
DefaultTableModel model = new DefaultTableModel(cnames, 0);
for (String top : new String[] { "C:\\Program Files\\Java", "C:\\Program Files (x86)\\Java" }) {
Arrays.stream(new File(top).listFiles()).filter(f -> f.getName().startsWith("jre")).forEach(f -> {
model.addRow(new Object[] { new File(f, "bin").getAbsolutePath() });
});
}
return model;
}
private void execute(File dropped) throws Exception {
int index = selectionModel.getMinSelectionIndex();
if (index < 0) {
error("JRE not selected");
return;
}
List<String> list = new ArrayList<String>();
list.add("set PATH=" + tableModel.getValueAt(index, 0));
list.add("java -jar " + dropped.getAbsolutePath());
Path path = Files.createTempFile(Paths.get(tmpDir), "jreSwitcher", ".bat");
Files.write(path, list);
ProcessBuilder c = new ProcessBuilder("cmd", "/c", path.toFile().getAbsolutePath());
Process p = c.start();
new Thread(() -> {
try {
p.waitFor();
} catch (InterruptedException ex) {}
path.toFile().delete();
}).start();
}
void error(String message) {
JOptionPane.showMessageDialog(null, message, "Error", JOptionPane.ERROR_MESSAGE);
}
public static void main(String[] args) throws Exception {
new Main().createWindow();
}
}