From e9bce19ec0789929b513ef414c54a380f690f16b Mon Sep 17 00:00:00 2001 From: Shanyu Thibaut Juneja Date: Sun, 29 Dec 2024 12:16:31 +0200 Subject: [PATCH] fix: gui bugs and qol --- .../obfuscator/SkidfuscatorMain.java | 1 + .../obfuscator/gui/ActionPanel.java | 9 +-- .../obfuscator/gui/ConfigPanel.java | 72 ++++++++++++----- .../obfuscator/gui/ConsolePanel.java | 2 +- .../obfuscator/gui/LibrariesPanel.java | 5 +- .../obfuscator/gui/MainFrame.java | 46 +++++++++-- .../obfuscator/gui/SkidPanel.java | 5 ++ .../gui/config/SkidfuscatorConfig.java | 11 ++- .../obfuscator/util/LogoUtil.java | 3 +- .../obfuscator/util/Observable.java | 76 ++++++++++++++++++ .../src/main/resources/images/warning.png | Bin 0 -> 22117 bytes .../skidfuscator/obfuscator/Skidfuscator.java | 8 +- .../obfuscator/util/JdkDownloader.java | 9 +-- 13 files changed, 202 insertions(+), 45 deletions(-) create mode 100644 dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/SkidPanel.java create mode 100644 dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/util/Observable.java create mode 100644 dev.skidfuscator.client.standalone/src/main/resources/images/warning.png diff --git a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/SkidfuscatorMain.java b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/SkidfuscatorMain.java index 175c9a7..86d6dcd 100644 --- a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/SkidfuscatorMain.java +++ b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/SkidfuscatorMain.java @@ -1,6 +1,7 @@ package dev.skidfuscator.obfuscator; import com.formdev.flatlaf.intellijthemes.FlatDarkPurpleIJTheme; +import com.formdev.flatlaf.intellijthemes.FlatGradiantoMidnightBlueIJTheme; import dev.skidfuscator.obfuscator.command.HelpCommand; import dev.skidfuscator.obfuscator.command.MappingsCommand; import dev.skidfuscator.obfuscator.command.ObfuscateCommand; diff --git a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/ActionPanel.java b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/ActionPanel.java index 42783fe..af8af16 100644 --- a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/ActionPanel.java +++ b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/ActionPanel.java @@ -6,7 +6,7 @@ import java.awt.*; import java.io.File; -public class ActionPanel extends JPanel { +public class ActionPanel extends JPanel implements SkidPanel{ private final MainFrame mainFrame; private final JTextArea logArea; private final JButton startButton; @@ -40,6 +40,8 @@ public void startObfuscation() { return; } + + // Create session SkidfuscatorSession session = SkidfuscatorSession.builder() .input(new File(config.getInputPath())) @@ -48,10 +50,7 @@ public void startObfuscation() { ? new File[0] : new File(config.getLibsPath()).listFiles() ) - .runtime(config.getRuntimePath().isEmpty() - ? null - : new File(config.getRuntimePath()) - ) + .runtime(null) .phantom(false) .debug(config.isDebugEnabled()) .build(); diff --git a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/ConfigPanel.java b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/ConfigPanel.java index 6e8e9c7..4e789da 100644 --- a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/ConfigPanel.java +++ b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/ConfigPanel.java @@ -9,26 +9,22 @@ import dev.skidfuscator.obfuscator.gui.autosave.AutoSaveDocumentListener; import dev.skidfuscator.obfuscator.gui.config.SkidfuscatorConfig; import dev.skidfuscator.obfuscator.util.JdkDownloader; +import dev.skidfuscator.obfuscator.util.Observable; -import javax.swing.*; -import java.awt.*; -import java.io.File; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import javax.swing.border.BevelBorder; import javax.swing.border.EtchedBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import javax.swing.text.BadLocationException; -import javax.swing.text.DefaultHighlighter; -public class ConfigPanel extends JPanel { +public class ConfigPanel extends JPanel implements SkidPanel{ private final JTextField inputField; private final JTextField outputField; private final JTextField libsField; private final JTextField runtimeField; private final JCheckBox debugBox; private final SkidfuscatorConfig config; + private Observable runtimeInstalled = new Observable.SimpleObservable<>( + JdkDownloader.isJdkDownloaded() + ); public ConfigPanel() { setLayout(new GridBagLayout()); @@ -116,7 +112,9 @@ private void updateCheck() { boolean valid = new File(inputField.getText()).exists(); inputCheck.setText(valid ? "✓" : "✗"); inputCheck.setForeground(valid ? new Color(46, 204, 64) : new Color(255, 65, 54)); - + System.out.println("Input valid: " + valid); + config.getValidInput().set(valid); + if (!valid) { StringBuilder tooltip = new StringBuilder(""); tooltip.append("
⚠ Warning: Invalid Input Configuration
"); @@ -171,7 +169,10 @@ private void updateCheck() { boolean valid = parent != null && parent.exists() && validEnd && validInput; outputCheck.setText(valid ? "✓" : "✗"); - outputCheck.setForeground(valid ? new Color(46, 204, 64) : new Color(255, 65, 54)); + outputCheck.setForeground(valid + ? new Color(46, 204, 64) + : new Color(255, 65, 54) + ); // Set tooltip explaining validation failure StringBuilder tooltip = new StringBuilder(""); tooltip.append("
⚠ Warning: Invalid Output Configuration
"); @@ -186,6 +187,7 @@ private void updateCheck() { tooltip.append("
Output file cannot be the same as input file
"); } tooltip.append(""); + config.getValidOutput().set(validInput); if (!valid) { ToolTipManager.sharedInstance().setInitialDelay(0); @@ -193,7 +195,7 @@ private void updateCheck() { outputField.setToolTipText(tooltip.toString()); } else { - outputCheck.setToolTipText(null); + outputField.setToolTipText(null); } } public void insertUpdate(DocumentEvent e) { updateCheck(); } @@ -204,9 +206,15 @@ private void updateCheck() { if (config.getLastOutputPath() != null) { outputField.setText(config.getLastOutputPath()); outputListener.insertUpdate(null); - } else if (config.getLastInputPath() != null) { - outputField.setText(config.getLastInputPath().replace(".jar", "-obf.jar")); + } else if (config.getLastInputPath() != null || inputField.getText() != null) { + final String input = config.getLastInputPath() != null + ? config.getLastInputPath() + : inputField.getText(); + + outputField.setText(input.replace(".jar", "-obf.jar")); outputListener.insertUpdate(null); + } else { + config.getValidOutput().set(false); } add(outputField, gbc); gbc.gridx = 2; @@ -271,12 +279,14 @@ private void updateCheck() { String jmodPath = JdkDownloader.getCachedJmodPath(); runtimeField.setText(jmodPath); runtimeField.setEnabled(!JdkDownloader.isJdkDownloaded()); + runtimeInstalled.set(JdkDownloader.isJdkDownloaded()); } catch (IOException e) { // Fallback to config if (config.getLastRuntimePath() != null) { if (config.getLastRuntimePath().isEmpty()) { runtimeField.setText(Jvm.getLibsPath()); runtimeField.setEnabled(false); + runtimeInstalled.set(true); } else { runtimeField.setText(config.getLastRuntimePath()); } @@ -288,12 +298,19 @@ private void updateCheck() { // Add download button next to browse button gbc.gridx = 2; JPanel runtimeButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0)); - JButton downloadButton = new JButton("Download JDK"); - + JLabel downloadCheck = new JLabel("✗"); + downloadCheck.setForeground(new Color(255, 65, 54)); + + JButton downloadButton = new JButton("Install"); + runtimeButtonPanel.setPreferredSize(new Dimension(150, 30)); + // Set initial button state based on JDK download status if (JdkDownloader.isJdkDownloaded()) { - downloadButton.setText("Downloaded"); + downloadButton.setText("Installed"); downloadButton.setEnabled(false); + downloadCheck.setText("✓"); + downloadCheck.setForeground(new Color(46, 204, 64)); + runtimeInstalled.set(true); } downloadButton.addActionListener(e -> { @@ -312,8 +329,12 @@ protected void done() { String path = get(); runtimeField.setText(path); runtimeField.setEnabled(false); - downloadButton.setText("Downloaded"); + downloadButton.setText("Installed"); downloadButton.setEnabled(false); + downloadCheck.setText("✓"); + downloadCheck.setForeground(new Color(46, 204, 64)); + runtimeInstalled.set(true); + } catch (Exception ex) { JOptionPane.showMessageDialog( ConfigPanel.this, @@ -321,14 +342,19 @@ protected void done() { "Download Error", JOptionPane.ERROR_MESSAGE ); - downloadButton.setText("Download JDK"); + downloadButton.setText("Install"); downloadButton.setEnabled(true); + downloadCheck.setText("✗"); + downloadCheck.setForeground(new Color(255, 65, 54)); + runtimeInstalled.set(false); } } }; worker.execute(); }); runtimeButtonPanel.add(downloadButton); + runtimeButtonPanel.add(Box.createHorizontalGlue()); + runtimeButtonPanel.add(downloadCheck); // removing for now //runtimeButtonPanel.add(createBrowseButton(runtimeField, false)); @@ -413,5 +439,13 @@ public String getLibraryPath() { // TODO: Add a library path field to the config panel return null; } + + public Observable getRuntimeInstalled() { + return runtimeInstalled; + } + + public SkidfuscatorConfig getConfig() { + return config; + } } diff --git a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/ConsolePanel.java b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/ConsolePanel.java index 35e8e4d..c26154b 100644 --- a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/ConsolePanel.java +++ b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/ConsolePanel.java @@ -24,7 +24,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public class ConsolePanel extends JPanel { +public class ConsolePanel extends JPanel implements SkidPanel { private final JTextPane consoleOutput; private final SimpleDateFormat timeFormat; private final StyledDocument doc; diff --git a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/LibrariesPanel.java b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/LibrariesPanel.java index fa175d1..6814b24 100644 --- a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/LibrariesPanel.java +++ b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/LibrariesPanel.java @@ -28,7 +28,7 @@ import java.util.concurrent.atomic.AtomicInteger; import javax.swing.Timer; -public class LibrariesPanel extends JPanel { +public class LibrariesPanel extends JPanel implements SkidPanel { private final JList libraryList; private final DefaultListModel libraryModel; private final JList missingClassesList; @@ -179,6 +179,9 @@ public LibrariesPanel(ConfigPanel configPanel, SkidApplicationClassSource classS add(bottomPanel, BorderLayout.SOUTH); // Analyze the input jar if specified in config + } + + public void open() { SwingUtilities.invokeLater(this::analyzeConfigJar); } diff --git a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/MainFrame.java b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/MainFrame.java index 8306b99..9af54e5 100644 --- a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/MainFrame.java +++ b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/MainFrame.java @@ -4,6 +4,8 @@ import com.formdev.flatlaf.ui.FlatTabbedPaneUI; import dev.skidfuscator.obfuscator.Skidfuscator; import dev.skidfuscator.obfuscator.SkidfuscatorSession; +import dev.skidfuscator.obfuscator.util.JdkDownloader; +import dev.skidfuscator.obfuscator.util.Observable; import lombok.Getter; import javax.imageio.ImageIO; @@ -96,7 +98,7 @@ protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex) { g.drawString("Skidfuscator Community", 20, 175); g.setColor(new Color(130, 130, 130)); g.setFont(new Font("Segoe UI", Font.ITALIC, 11)); - g.drawString("Build: 2023.1", 20, 190); + g.drawString("Build: " + Skidfuscator.VERSION, 20, 190); // Draw second separator g.setColor(Color.DARK_GRAY); @@ -228,15 +230,23 @@ public void mouseClicked(MouseEvent e) { contentPanel.removeAll(); switch (tabbedPane.getSelectedIndex()) { case 0: + configPanel.open(); contentPanel.add(configPanel, BorderLayout.CENTER); break; case 1: + if (!JdkDownloader.isJdkDownloaded()) { + JOptionPane.showMessageDialog(this, "Please download the JDK first", "Error", JOptionPane.ERROR_MESSAGE); + tabbedPane.setSelectedIndex(0); + return; + } + librariesPanel.open(); contentPanel.add(librariesPanel, BorderLayout.CENTER); break; case 2: contentPanel.add(transformerPanel, BorderLayout.CENTER); break; case 3: + consolePanel.open(); contentPanel.add(consolePanel, BorderLayout.CENTER); break; } @@ -244,6 +254,13 @@ public void mouseClicked(MouseEvent e) { contentPanel.repaint(); }); + + // Observe input/output and adapt button to it + configPanel.getConfig().getValidInput().addObserver(value -> refreshStartButton()); + configPanel.getConfig().getValidOutput().addObserver(value -> refreshStartButton()); + configPanel.getRuntimeInstalled().addObserver(value -> refreshStartButton()); + refreshStartButton(); + // Final setup pack(); setLocationRelativeTo(null); @@ -309,6 +326,23 @@ public void updateTabStates(boolean configEnabled, boolean transformersEnabled) tabbedPane.setEnabledAt(1, transformersEnabled); } + private void refreshStartButton() { + System.out.println("Refreshing start button"); + + if (!configPanel.getConfig().isValid() || !configPanel.getRuntimeInstalled().get()) { + // Set warning icon + final Image warningIcon = new ImageIcon(getClass().getResource("/images/warning.png")).getImage(); + final Image warningImage = warningIcon.getScaledInstance(16, 16, Image.SCALE_SMOOTH); + final ImageIcon warningIconScaled = new ImageIcon(warningImage); + startButton.setIcon(warningIconScaled); + startButton.setEnabled(false); + } else { + startButton.setToolTipText(null); + startButton.setIcon(null); + startButton.setEnabled(true); + } + } + public void startObfuscation() { ConfigPanel config = this.getConfigPanel(); TransformerPanel transformers = this.getTransformerPanel(); @@ -347,15 +381,17 @@ public void startObfuscation() { ? libraryFolder.toFile().listFiles() : new File(config.getLibsPath()).listFiles() ) - .runtime(config.getRuntimePath().isEmpty() - ? null - : new File(config.getRuntimePath()) - ) + //.runtime(config.getRuntimePath().isEmpty() + // ? null + // : new File(config.getRuntimePath()) + //) .jmod(config.getRuntimePath().contains("jmods")) .debug(config.isDebugEnabled()) .build(); // Start obfuscation in background startButton.setEnabled(false); + + SwingWorker worker = new SwingWorker() { @Override protected Void doInBackground() { diff --git a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/SkidPanel.java b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/SkidPanel.java new file mode 100644 index 0000000..61efbba --- /dev/null +++ b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/SkidPanel.java @@ -0,0 +1,5 @@ +package dev.skidfuscator.obfuscator.gui; + +public interface SkidPanel { + default void open() {} +} diff --git a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/config/SkidfuscatorConfig.java b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/config/SkidfuscatorConfig.java index 874ee33..c44fc34 100644 --- a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/config/SkidfuscatorConfig.java +++ b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/gui/config/SkidfuscatorConfig.java @@ -2,11 +2,10 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import dev.skidfuscator.obfuscator.util.Observable; import lombok.Data; import java.io.*; -import java.nio.file.*; -import java.util.Properties; @Data public class SkidfuscatorConfig { @@ -22,6 +21,14 @@ public class SkidfuscatorConfig { private boolean phantomEnabled; private String lastDirectory; + private transient Observable + validInput = new Observable.SimpleObservable<>(false), + validOutput = new Observable.SimpleObservable<>(false); + + public boolean isValid() { + return validInput.get() && validOutput.get(); + } + public static class Builder { private final SkidfuscatorConfig config; diff --git a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/util/LogoUtil.java b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/util/LogoUtil.java index 49d033b..f597aad 100644 --- a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/util/LogoUtil.java +++ b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/util/LogoUtil.java @@ -1,5 +1,6 @@ package dev.skidfuscator.obfuscator.util; +import dev.skidfuscator.obfuscator.Skidfuscator; import lombok.experimental.UtilityClass; import java.text.DateFormat; @@ -61,7 +62,7 @@ public static void printLogo() { " │ " + topMemory + " │", " └───────────────────────────────────────────┘", "", - " Author: Ghast Version: 2.0.11 Today: " + " Author: Ghast Version: " + Skidfuscator.VERSION + " Today: " + DateFormat.getDateTimeInstance().format(new Date(Instant.now().toEpochMilli())), "" }; diff --git a/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/util/Observable.java b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/util/Observable.java new file mode 100644 index 0000000..a7b4ee5 --- /dev/null +++ b/dev.skidfuscator.client.standalone/src/main/java/dev/skidfuscator/obfuscator/util/Observable.java @@ -0,0 +1,76 @@ +package dev.skidfuscator.obfuscator.util; + +import java.util.HashSet; +import java.util.Set; + +public interface Observable { + T get(); + + void set(T value); + + void addObserver(Observer observer); + + void removeObserver(Observer observer); + + class SimpleObservable implements Observable { + private final Set> observers = new HashSet<>(); + private T value; + + public SimpleObservable(T value) { + this.value = value; + } + + public T get() { + return value; + } + + public void set(T value) { + this.value = value; + observers.forEach(observer -> observer.onChanged(value)); + } + + @Override + public void addObserver(Observer observer) { + observers.add(observer); + } + + @Override + public void removeObserver(Observer observer) { + observers.remove(observer); + } + } + + class MergedBooleanObservable implements Observable { + private final Set> observables = new HashSet<>(); + private final Set> observers = new HashSet<>(); + + public MergedBooleanObservable(Observable... observables) { + for (Observable observable : observables) { + this.observables.add(observable); + observable.addObserver(value -> observers.forEach(observer -> observer.onChanged(get()))); + } + } + + public Boolean get() { + return observables.stream().allMatch(Observable::get); + } + + public void set(Boolean value) { + observables.forEach(observable -> observable.set(value)); + } + + @Override + public void addObserver(Observer observer) { + observers.add(observer); + } + + @Override + public void removeObserver(Observer observer) { + observers.remove(observer); + } + } + + interface Observer { + void onChanged(T value); + } +} diff --git a/dev.skidfuscator.client.standalone/src/main/resources/images/warning.png b/dev.skidfuscator.client.standalone/src/main/resources/images/warning.png new file mode 100644 index 0000000000000000000000000000000000000000..4d4990a4d0d82a31c36eba824f9b4eba801bed88 GIT binary patch literal 22117 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�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 KT-G@yGywoz?&bdg literal 0 HcmV?d00001 diff --git a/dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/Skidfuscator.java b/dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/Skidfuscator.java index e57843d..d6fa0e9 100644 --- a/dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/Skidfuscator.java +++ b/dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/Skidfuscator.java @@ -109,6 +109,8 @@ public class Skidfuscator { public static final boolean FLATTENING = false; public static boolean CLOUD = false; + public static final String VERSION = "2.1.0"; + private final SkidfuscatorSession session; protected Set installedDependencies = new HashSet<>(); @@ -524,7 +526,7 @@ public Set _importJvm() { */ if (libFiles == null) { LOGGER.warn("FATAL! Library files for JDK are null"); - System.exit(2); + throw new IllegalStateException("Null JDK files! Exiting..."); } try (final ProgressWrapper wrapper = ProgressUtil.progressCheck( @@ -787,9 +789,7 @@ private void _verify() { + "-----------------------------------------------------\n" ); - if (!CLOUD) - System.exit(1); - return; + throw new IllegalStateException("Failed to compute some libraries!"); } // [failsafe] some people cancel mid download, corrupting the library diff --git a/dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/JdkDownloader.java b/dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/JdkDownloader.java index e884978..5941615 100644 --- a/dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/JdkDownloader.java +++ b/dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/JdkDownloader.java @@ -128,16 +128,11 @@ public static Path getJdkHome() throws IOException { wrapper.tick(); wrapper.succeed(); } catch (IOException e) { - Files.deleteIfExists(jdkPath); + Files.deleteIfExists(getCachedJdk()); throw e; } } - - switch (OS) { - case "mac os x": - case "mac": - return jdkPath.resolve("Contents/Home"); - } + jdkPath = getCachedJdk(); return jdkPath; }