From 053a54190a6d6f82e4e962b422cec0df104e1d4f Mon Sep 17 00:00:00 2001 From: Olof Larsson Date: Sat, 14 May 2016 10:37:43 +0200 Subject: [PATCH] Reflection Util improvements. A bug fix. Dirt code from messing around. --- .../massivecraft/massivecore/MassiveCore.java | 7 + .../massivecore/item/WriterAbstract.java | 3 +- .../massivecore/picker/Picker.java | 158 ++++++++++++++++++ .../massivecore/picker/PickerTest.java | 49 ++++++ .../picker/PickerTestImpossible.java | 32 ++++ .../picker/PickerTestPossible.java | 22 +++ .../massivecore/util/ReflectionUtil.java | 12 +- 7 files changed, 275 insertions(+), 8 deletions(-) create mode 100644 src/com/massivecraft/massivecore/picker/Picker.java create mode 100644 src/com/massivecraft/massivecore/picker/PickerTest.java create mode 100644 src/com/massivecraft/massivecore/picker/PickerTestImpossible.java create mode 100644 src/com/massivecraft/massivecore/picker/PickerTestPossible.java diff --git a/src/com/massivecraft/massivecore/MassiveCore.java b/src/com/massivecraft/massivecore/MassiveCore.java index a2db3e4a..7fbc2b68 100644 --- a/src/com/massivecraft/massivecore/MassiveCore.java +++ b/src/com/massivecraft/massivecore/MassiveCore.java @@ -308,6 +308,13 @@ public class MassiveCore extends MassivePlugin // Delete Files (at once and additionally after all plugins loaded) MassiveCoreTaskDeleteFiles.get().run(); Bukkit.getScheduler().scheduleSyncDelayedTask(this, MassiveCoreTaskDeleteFiles.get()); + + // TEST + //PickerTest.get().action(); + //this.activate( + // PickerTest.class + //); + //PickerTest.get().action(); } @Override diff --git a/src/com/massivecraft/massivecore/item/WriterAbstract.java b/src/com/massivecraft/massivecore/item/WriterAbstract.java index cd443fd7..39a1f4b5 100644 --- a/src/com/massivecraft/massivecore/item/WriterAbstract.java +++ b/src/com/massivecraft/massivecore/item/WriterAbstract.java @@ -81,8 +81,7 @@ public abstract class WriterAbstract extends Engine { try { - Class> writerClassInner = (Class>) writerClass; - WriterAbstract writer = ReflectionUtil.getSingletonInstance(writerClassInner); + WriterAbstract writer = ReflectionUtil.getSingletonInstance(writerClass); if ( ! writer.isActive()) writer.setActive(this.getActivePlugin()); diff --git a/src/com/massivecraft/massivecore/picker/Picker.java b/src/com/massivecraft/massivecore/picker/Picker.java new file mode 100644 index 00000000..4c96b8f9 --- /dev/null +++ b/src/com/massivecraft/massivecore/picker/Picker.java @@ -0,0 +1,158 @@ +package com.massivecraft.massivecore.picker; + +import java.util.Arrays; +import java.util.List; + +import com.massivecraft.massivecore.Engine; +import com.massivecraft.massivecore.collections.MassiveList; +import com.massivecraft.massivecore.util.ReflectionUtil; + +// TODO: Rename to Mixin... because that's what we are trying to replace. +@SuppressWarnings("unchecked") +public class Picker extends Engine +{ + // -------------------------------------------- // + // DEFAULT + // -------------------------------------------- // + // The default class contains the static fields. + // It should never be abstract and should always be compatible. + // A default class instance is set as the default value. This avoids null. + // It is detected by the required static field d. + + private final Class defaultClass = ReflectionUtil.getSuperclassDeclaringField(this.getClass(), true, "d"); + public Class getDefaultClass() { return this.defaultClass; } + + public Picker getDefault() { return ReflectionUtil.getField(this.getDefaultClass(), "d", null); } + public boolean isDefault() { return this == this.getDefault(); } + + // -------------------------------------------- // + // INSTANCE + // -------------------------------------------- // + // Access the active static instance using instance methods. + // This looks a bit strange but will save us a lot of repetitive source code down the road. + // These are not meant to be used for selection or activation. + // The standard active interface methods are used for that. + + public Picker getInstance() { return ReflectionUtil.getField(this.getDefaultClass(), "i", null); } + public void setInstance(Picker i) { ReflectionUtil.setField(this.getDefaultClass(), "i", null, i); } + + // -------------------------------------------- // + // FIELDS + // -------------------------------------------- // + + // This is the base name. + // It should describe the function supplied. + // It should be set in the base class constructor. + private String baseName = this.getDefaultClass().getClass().getSimpleName(); + public String getBaseName() { return this.baseName; } + public void setBaseName(String baseName) { this.baseName = baseName; } + + // This is the instance specific name. + // It should describe the circumstances for compatibility. + // It could for example contain a version number. + private String name = this.getClass().getSimpleName(); + public String getName() { return this.name; } + public void setName(String name) { this.name = name; } + + // This is the list of alternatives to choose from. + // The first compatible alternative will be chosen for activation. + // The list should thus start with the most provoking and detailed alternative. + // If the list is empty we simply offer ourselves. + private List> alternatives = new MassiveList<>(); + public List> getAlternatives() { return this.alternatives; } + public T setAlternatives(List> alternatives) { this.alternatives = alternatives; return (T) this; } + public T setAlternatives(Class... alternatives) { return this.setAlternatives(Arrays.asList(alternatives)); } + + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + public Picker() + { + // Provoke! + try + { + this.provoke(); + } + catch (Throwable t) + { + throw ReflectionUtil.asRuntimeException(t); + } + } + + // -------------------------------------------- // + // PROVOKE + // -------------------------------------------- // + // Provoke your exceptions and errors here. + // If a throwable is thrown here the instance is not compatible with the circumstances. + + public Object provoke() throws Throwable + { + return null; + } + + // -------------------------------------------- // + // ACTIVE + // -------------------------------------------- // + // We need to modify the active logic sightly. + // + // We make use of the standard engine isActive. + // That one looks at the engine registry and does not care about the instance. + // That behavior tends to work out well for us in this case. + // + // The reason for this is that the default will be set as the instance from the start. + // That does however not mean that it's active. + // It means it will be used to set the active which may or may not be itself. + + @Override + public void setActive(boolean active) + { + // NoChange + if (this.isActive() == active) return; + + // Before + Picker before = this.getInstance(); + + // After + Picker after; + if (active) + { + // This + after = this; + + // Alternatives + for (Class alternative : this.getAlternatives()) + { + try + { + Picker alternativeInstance = ReflectionUtil.getSingletonInstance(alternative); + after = alternativeInstance; + break; + } + catch (Throwable t) + { + // Not Compatible + } + } + } + else + { + // Default + after = this.getDefault(); + } + + // Deactivate Before + if (before != this) before.setActive(false); + + // Set Instance + this.setInstance(after); + + // Activate After + if (after != this) after.setActive(true); + + // Super + if (after == this) super.setActive(active); + } + + +} diff --git a/src/com/massivecraft/massivecore/picker/PickerTest.java b/src/com/massivecraft/massivecore/picker/PickerTest.java new file mode 100644 index 00000000..afd797a5 --- /dev/null +++ b/src/com/massivecraft/massivecore/picker/PickerTest.java @@ -0,0 +1,49 @@ +package com.massivecraft.massivecore.picker; + +import com.massivecraft.massivecore.MassiveCore; +import com.massivecraft.massivecore.util.Txt; + +public class PickerTest extends Picker +{ + // -------------------------------------------- // + // DEFAULT + // -------------------------------------------- // + + private static final PickerTest d = new PickerTest().setAlternatives( + PickerTestImpossible.class, + PickerTestPossible.class + ); + + // -------------------------------------------- // + // INSTANCE + // -------------------------------------------- // + + private static final PickerTest i = d; + public static PickerTest get() { return i; } + + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + public PickerTest() + { + + } + + // -------------------------------------------- // + // METHODS + // -------------------------------------------- // + + public void action() + { + String msg = this.getMsg(); + String message = Txt.parse(msg); + MassiveCore.get().log(message); + } + + public String getMsg() + { + return "Default..."; + } + +} diff --git a/src/com/massivecraft/massivecore/picker/PickerTestImpossible.java b/src/com/massivecraft/massivecore/picker/PickerTestImpossible.java new file mode 100644 index 00000000..ef59ca90 --- /dev/null +++ b/src/com/massivecraft/massivecore/picker/PickerTestImpossible.java @@ -0,0 +1,32 @@ +package com.massivecraft.massivecore.picker; + +public class PickerTestImpossible extends PickerTest +{ + // -------------------------------------------- // + // INSTANCE & CONSTRUCT + // -------------------------------------------- // + + private static final PickerTestImpossible i = new PickerTestImpossible(); + public static PickerTestImpossible get() { return i; } + + // -------------------------------------------- // + // PROVOKE + // -------------------------------------------- // + + @Override + public Object provoke() throws Throwable + { + throw new RuntimeException("so provokative!"); + } + + // -------------------------------------------- // + // METHODS + // -------------------------------------------- // + + @Override + public String getMsg() + { + return "Impossible and Unexpected"; + } + +} diff --git a/src/com/massivecraft/massivecore/picker/PickerTestPossible.java b/src/com/massivecraft/massivecore/picker/PickerTestPossible.java new file mode 100644 index 00000000..caac9b63 --- /dev/null +++ b/src/com/massivecraft/massivecore/picker/PickerTestPossible.java @@ -0,0 +1,22 @@ +package com.massivecraft.massivecore.picker; + +public class PickerTestPossible extends PickerTest +{ + // -------------------------------------------- // + // INSTANCE & CONSTRUCT + // -------------------------------------------- // + + private static final PickerTestPossible i = new PickerTestPossible(); + public static PickerTestPossible get() { return i; } + + // -------------------------------------------- // + // METHODS + // -------------------------------------------- // + + @Override + public String getMsg() + { + return "Possible and Expected"; + } + +} diff --git a/src/com/massivecraft/massivecore/util/ReflectionUtil.java b/src/com/massivecraft/massivecore/util/ReflectionUtil.java index 74713308..cbe64447 100644 --- a/src/com/massivecraft/massivecore/util/ReflectionUtil.java +++ b/src/com/massivecraft/massivecore/util/ReflectionUtil.java @@ -89,7 +89,7 @@ public class ReflectionUtil { try { - Method ret = clazz.getMethod(name, parameterTypes); + Method ret = clazz.getDeclaredMethod(name, parameterTypes); makeAccessible(ret); return ret; } @@ -198,7 +198,7 @@ public class ReflectionUtil // SINGLETON INSTANCE // -------------------------------------------- // - public static T getSingletonInstance(Class clazz) + public static T getSingletonInstance(Class clazz) { Method get = getMethod(clazz, "get"); T ret = invokeMethod(get, null); @@ -369,16 +369,16 @@ public class ReflectionUtil // AS RUNTIME EXCEPTION // -------------------------------------------- // - public static RuntimeException asRuntimeException(Throwable e) + public static RuntimeException asRuntimeException(Throwable t) { // Runtime - if (e instanceof RuntimeException) return (RuntimeException) e; + if (t instanceof RuntimeException) return (RuntimeException) t; // Invocation - if (e instanceof InvocationTargetException) return asRuntimeException(((InvocationTargetException)e).getCause()); + if (t instanceof InvocationTargetException) return asRuntimeException(((InvocationTargetException)t).getCause()); // Rest - return new IllegalStateException(e.getClass().getSimpleName() + ": " + e.getMessage()); + return new IllegalStateException(t.getClass().getSimpleName() + ": " + t.getMessage()); } }