From 2403d32ae4473c4be44c75b998474b2e88a1db1f Mon Sep 17 00:00:00 2001 From: Skylot Date: Tue, 14 Mar 2023 15:32:08 +0000 Subject: [PATCH] feat(gui): use plain json config instead java preferences --- jadx-gui/build.gradle | 1 + .../gui/settings/JadxSettingsAdapter.java | 21 +++---- .../gui/settings/JadxSettingsStorage.java | 62 +++++++++++++++++++ 3 files changed, 72 insertions(+), 12 deletions(-) create mode 100644 jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsStorage.java diff --git a/jadx-gui/build.gradle b/jadx-gui/build.gradle index 03d41b4bd..c5a963740 100644 --- a/jadx-gui/build.gradle +++ b/jadx-gui/build.gradle @@ -24,6 +24,7 @@ dependencies { implementation 'com.beust:jcommander:1.82' implementation 'ch.qos.logback:logback-classic:1.3.5' + implementation 'dev.dirs:directories:26' implementation 'com.fifesoft:rsyntaxtextarea:3.3.2' implementation files('libs/jfontchooser-1.0.5.jar') diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsAdapter.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsAdapter.java index e9c0bcb82..45ad9f864 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsAdapter.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsAdapter.java @@ -7,7 +7,6 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Modifier; import java.nio.file.Path; -import java.util.prefs.Preferences; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,7 +18,6 @@ import com.google.gson.GsonBuilder; import com.google.gson.InstanceCreator; import com.google.gson.JsonObject; -import jadx.gui.JadxGUI; import jadx.gui.utils.PathTypeAdapter; import jadx.gui.utils.RectangleTypeAdapter; @@ -27,9 +25,7 @@ public class JadxSettingsAdapter { private static final Logger LOG = LoggerFactory.getLogger(JadxSettingsAdapter.class); - private static final String JADX_GUI_KEY = "jadx.gui.settings"; - - private static final Preferences PREFS = Preferences.userNodeForPackage(JadxGUI.class); + private static final JadxSettingsStorage STORAGE = new JadxSettingsStorage(); private static final ExclusionStrategy EXCLUDE_FIELDS = new ExclusionStrategy() { @Override @@ -49,16 +45,16 @@ public class JadxSettingsAdapter { private static final GsonBuilder GSON_BUILDER = new GsonBuilder() .setExclusionStrategies(EXCLUDE_FIELDS) .registerTypeHierarchyAdapter(Path.class, PathTypeAdapter.singleton()) - .registerTypeHierarchyAdapter(Rectangle.class, RectangleTypeAdapter.singleton()); + .registerTypeHierarchyAdapter(Rectangle.class, RectangleTypeAdapter.singleton()) + .setPrettyPrinting(); private static final Gson GSON = GSON_BUILDER.create(); private JadxSettingsAdapter() { } public static JadxSettings load() { - String jsonSettings = PREFS.get(JADX_GUI_KEY, ""); try { - JadxSettings settings = fromString(jsonSettings); + JadxSettings settings = fromString(STORAGE.load()); if (settings == null) { LOG.debug("Created new settings."); settings = JadxSettings.makeDefault(); @@ -67,22 +63,23 @@ public class JadxSettingsAdapter { } return settings; } catch (Exception e) { - LOG.error("Error load settings. Settings will reset.\n Loaded json string: {}", jsonSettings, e); + LOG.error("Error load settings. Settings will reset", e); return new JadxSettings(); } } public static void store(JadxSettings settings) { try { - String jsonSettings = makeString(settings); - PREFS.put(JADX_GUI_KEY, jsonSettings); - PREFS.sync(); + STORAGE.save(makeString(settings)); } catch (Exception e) { LOG.error("Error store settings", e); } } public static JadxSettings fromString(String jsonSettings) { + if (jsonSettings == null) { + return null; + } return GSON.fromJson(jsonSettings, JadxSettings.class); } diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsStorage.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsStorage.java new file mode 100644 index 000000000..d19813c28 --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsStorage.java @@ -0,0 +1,62 @@ +package jadx.gui.settings; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.prefs.Preferences; + +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import dev.dirs.ProjectDirectories; + +import jadx.core.utils.StringUtils; +import jadx.core.utils.files.FileUtils; +import jadx.gui.JadxGUI; + +/** + * Jadx settings storage. Select first available option: + * 1. json file in system 'config' directory (preferred) + * 2. using java preferences api: use Windows registry or xml on Linux/Mac (obsolete, load only) + */ +public class JadxSettingsStorage { + private static final Logger LOG = LoggerFactory.getLogger(JadxSettingsStorage.class); + + private final Path configFile = initConfigFile(); + + public synchronized @Nullable String load() throws IOException { + if (Files.exists(configFile)) { + return FileUtils.readFile(configFile); + } + return null; + } + + public synchronized void save(String jsonStr) throws IOException { + FileUtils.writeFile(configFile, jsonStr); + } + + private static Path initConfigFile() { + ProjectDirectories jadxDirs = ProjectDirectories.from("io.github", "skylot", "jadx"); + Path confPath = Paths.get(jadxDirs.configDir, "config.json"); + if (!Files.exists(confPath)) { + copyFromPreferences(confPath); + } + LOG.debug("Using config: {}", confPath); + return confPath; + } + + private static void copyFromPreferences(Path confPath) { + try { + Preferences prefs = Preferences.userNodeForPackage(JadxGUI.class); + String str = prefs.get("jadx.gui.settings", ""); + if (StringUtils.notEmpty(str)) { + FileUtils.writeFile(confPath, str); + LOG.warn("Settings moved from java preferences to config file: {}", confPath); + } + } catch (Exception e) { + LOG.warn("Failed to load settings from preferences", e); + } + } +}