From 64329ad7ccedba53c47ccd3a08b9eb97e756122c Mon Sep 17 00:00:00 2001
From: nextdaydelivery <79922345+nxtdaydelivery@users.noreply.github.com>
Date: Mon, 25 Jul 2022 11:39:45 +0100
Subject: Config Checker (#67)

---
 .../oneconfig/config/core/ConfigUtils.java         | 21 ++++++++++++++++-
 .../core/exceptions/InvalidTypeException.java      | 26 ++++++++++++++++++++++
 .../gson/NonProfileSpecificExclusionStrategy.java  |  1 +
 .../config/gson/ProfileExclusionStrategy.java      |  1 +
 .../polyfrost/oneconfig/events/EventManager.java   | 19 +++++++++++++++-
 5 files changed, 66 insertions(+), 2 deletions(-)
 create mode 100644 src/main/java/cc/polyfrost/oneconfig/config/core/exceptions/InvalidTypeException.java

(limited to 'src')

diff --git a/src/main/java/cc/polyfrost/oneconfig/config/core/ConfigUtils.java b/src/main/java/cc/polyfrost/oneconfig/config/core/ConfigUtils.java
index 2b3c90b..bacfe8b 100644
--- a/src/main/java/cc/polyfrost/oneconfig/config/core/ConfigUtils.java
+++ b/src/main/java/cc/polyfrost/oneconfig/config/core/ConfigUtils.java
@@ -1,6 +1,7 @@
 package cc.polyfrost.oneconfig.config.core;
 
-import cc.polyfrost.oneconfig.config.annotations.Exclude;
+import cc.polyfrost.oneconfig.config.core.exceptions.InvalidTypeException;
+import cc.polyfrost.oneconfig.config.data.OptionType;
 import cc.polyfrost.oneconfig.config.elements.BasicOption;
 import cc.polyfrost.oneconfig.config.elements.OptionCategory;
 import cc.polyfrost.oneconfig.config.elements.OptionPage;
@@ -20,31 +21,49 @@ public class ConfigUtils {
     public static BasicOption getOption(Option option, Field field, Object instance) {
         switch (option.type()) {
             case SWITCH:
+                check(OptionType.SWITCH, field, boolean.class, Boolean.class);
                 return ConfigSwitch.create(field, instance);
             case CHECKBOX:
+                check(OptionType.CHECKBOX, field, boolean.class, Boolean.class);
                 return ConfigCheckbox.create(field, instance);
             case INFO:
                 return ConfigInfo.create(field, instance);
             case HEADER:
                 return ConfigHeader.create(field, instance);
             case COLOR:
+                check(OptionType.COLOR, field, OneColor.class);
                 return ConfigColorElement.create(field, instance);
             case DROPDOWN:
+                check(OptionType.DROPDOWN, field, int.class, Integer.class);
                 return ConfigDropdown.create(field, instance);
             case TEXT:
+                check(OptionType.TEXT, field, String.class);
                 return ConfigTextBox.create(field, instance);
             case BUTTON:
+                check(OptionType.BUTTON, field, Runnable.class);
                 return ConfigButton.create(field, instance);
             case SLIDER:
+                check(OptionType.SLIDER, field, int.class, float.class, Integer.class, Float.class);
                 return ConfigSlider.create(field, instance);
             case KEYBIND:
+                check(OptionType.KEYBIND, field, OneKeyBind.class);
                 return ConfigKeyBind.create(field, instance);
             case DUAL_OPTION:
+                check(OptionType.DUAL_OPTION, field, boolean.class, Boolean.class);
                 return ConfigDualOption.create(field, instance);
         }
         return null;
     }
 
+    private static void check(OptionType type, Field field, Class<?>... expectedType) {
+        // I have tried to check for supertype classes like Boolean other ways.
+        // but they actually don't extend their primitive types (because that is impossible) so isAssignableFrom doesn't work.
+        for (Class<?> clazz : expectedType) {
+            if(field.getType().equals(clazz)) return;
+        }
+        throw new InvalidTypeException("Field " + field.getName() + " in config " + field.getDeclaringClass().getName() + " is annotated as a " + type.toString() + ", but is not of valid type, expected " + Arrays.toString(expectedType) + " (found " + field.getType() + ")");
+    }
+
     public static ArrayList<BasicOption> getClassOptions(Object object) {
         ArrayList<BasicOption> options = new ArrayList<>();
         ArrayList<Field> fields = getClassFields(object.getClass());
diff --git a/src/main/java/cc/polyfrost/oneconfig/config/core/exceptions/InvalidTypeException.java b/src/main/java/cc/polyfrost/oneconfig/config/core/exceptions/InvalidTypeException.java
new file mode 100644
index 0000000..4ccaaf8
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/config/core/exceptions/InvalidTypeException.java
@@ -0,0 +1,26 @@
+package cc.polyfrost.oneconfig.config.core.exceptions;
+
+public class InvalidTypeException extends RuntimeException {
+
+    public InvalidTypeException() {
+        super();
+    }
+
+    public InvalidTypeException(String message) {
+        super(message);
+    }
+
+    public InvalidTypeException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public InvalidTypeException(Throwable cause) {
+        super(cause);
+    }
+
+    protected InvalidTypeException(String message, Throwable cause,
+                                   boolean enableSuppression,
+                                   boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/config/gson/NonProfileSpecificExclusionStrategy.java b/src/main/java/cc/polyfrost/oneconfig/config/gson/NonProfileSpecificExclusionStrategy.java
index e773295..b737d70 100644
--- a/src/main/java/cc/polyfrost/oneconfig/config/gson/NonProfileSpecificExclusionStrategy.java
+++ b/src/main/java/cc/polyfrost/oneconfig/config/gson/NonProfileSpecificExclusionStrategy.java
@@ -14,6 +14,7 @@ public class NonProfileSpecificExclusionStrategy extends ExclusionUtils implemen
     @Override
     public boolean shouldSkipField(FieldAttributes f) {
         if (isSuperClassOf(f.getDeclaredClass(), Config.class)) return true;
+        if (f.getDeclaredClass().isAssignableFrom(Runnable.class)) return true;
         if (f.getAnnotation(NonProfileSpecific.class) == null) return true;
         Exclude exclude = f.getAnnotation(Exclude.class);
         return exclude != null;
diff --git a/src/main/java/cc/polyfrost/oneconfig/config/gson/ProfileExclusionStrategy.java b/src/main/java/cc/polyfrost/oneconfig/config/gson/ProfileExclusionStrategy.java
index ad9722b..0df63b0 100644
--- a/src/main/java/cc/polyfrost/oneconfig/config/gson/ProfileExclusionStrategy.java
+++ b/src/main/java/cc/polyfrost/oneconfig/config/gson/ProfileExclusionStrategy.java
@@ -14,6 +14,7 @@ public class ProfileExclusionStrategy extends ExclusionUtils implements Exclusio
     @Override
     public boolean shouldSkipField(FieldAttributes f) {
         if (isSuperClassOf(f.getDeclaredClass(), Config.class)) return true;
+        if (f.getDeclaredClass().isAssignableFrom(Runnable.class)) return true;
         if (f.getAnnotation(NonProfileSpecific.class) != null) return true;
         Exclude exclude = f.getAnnotation(Exclude.class);
         return exclude != null;
diff --git a/src/main/java/cc/polyfrost/oneconfig/events/EventManager.java b/src/main/java/cc/polyfrost/oneconfig/events/EventManager.java
index 8492806..4e43410 100644
--- a/src/main/java/cc/polyfrost/oneconfig/events/EventManager.java
+++ b/src/main/java/cc/polyfrost/oneconfig/events/EventManager.java
@@ -1,7 +1,10 @@
 package cc.polyfrost.oneconfig.events;
 
+import cc.polyfrost.oneconfig.config.core.exceptions.InvalidTypeException;
 import cc.polyfrost.oneconfig.libs.eventbus.EventBus;
+import cc.polyfrost.oneconfig.libs.eventbus.exception.ExceptionHandler;
 import cc.polyfrost.oneconfig.libs.eventbus.invokers.LMFInvoker;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Manages all events from OneConfig.
@@ -11,7 +14,7 @@ public final class EventManager {
      * The instance of the {@link EventManager}.
      */
     public static final EventManager INSTANCE = new EventManager();
-    private final EventBus eventBus = new EventBus(new LMFInvoker(), Throwable::printStackTrace);
+    private final EventBus eventBus = new EventBus(new LMFInvoker(), new OneConfigExceptionHandler());
 
     private EventManager() {
 
@@ -55,4 +58,18 @@ public final class EventManager {
     public void post(Object event) {
         eventBus.post(event);
     }
+
+
+    /**
+     * Bypass to allow special exceptions to actually crash
+     */
+    private static class OneConfigExceptionHandler implements ExceptionHandler {
+        @Override
+        public void handle(@NotNull Exception e) {
+            if(e instanceof InvalidTypeException) {
+                throw (InvalidTypeException) e;
+            }
+            else e.printStackTrace();
+        }
+    }
 }
-- 
cgit