From 8a3cde52fd9dc4da95d190888e81bbe8d44ea615 Mon Sep 17 00:00:00 2001 From: tueem Date: Sat, 29 Mar 2025 18:49:26 +0100 Subject: [PATCH] refactor(interaction): implement Factory pattern for all Interaction- and ReflectedMethods --- .../net/tomatentum/marinara/Marinara.java | 18 ++++-- .../methods/ButtonInteractionMethod.java | 36 ++++++++--- .../AutoCompleteInteractionMethod.java | 36 ++++++++--- .../methods/InteractionMethod.java | 45 +++++++------ .../SlashCommandInteractionMethod.java | 38 ++++++++--- .../{util => reflection}/ReflectedMethod.java | 15 +---- .../reflection/ReflectedMethodFactory.java | 19 ++++++ .../ReflectedMethodFactoryImpl.java | 63 +++++++++++++++++++ .../registry/InteractionRegistry.java | 16 ++++- 9 files changed, 219 insertions(+), 67 deletions(-) rename lib/src/main/java/net/tomatentum/marinara/{util => reflection}/ReflectedMethod.java (82%) create mode 100644 lib/src/main/java/net/tomatentum/marinara/reflection/ReflectedMethodFactory.java create mode 100644 lib/src/main/java/net/tomatentum/marinara/reflection/ReflectedMethodFactoryImpl.java diff --git a/lib/src/main/java/net/tomatentum/marinara/Marinara.java b/lib/src/main/java/net/tomatentum/marinara/Marinara.java index f53a7ae..31b0786 100644 --- a/lib/src/main/java/net/tomatentum/marinara/Marinara.java +++ b/lib/src/main/java/net/tomatentum/marinara/Marinara.java @@ -2,6 +2,8 @@ package net.tomatentum.marinara; import org.slf4j.Logger; +import net.tomatentum.marinara.reflection.ReflectedMethodFactory; +import net.tomatentum.marinara.reflection.ReflectedMethodFactoryImpl; import net.tomatentum.marinara.registry.InteractionCheckRegistry; import net.tomatentum.marinara.registry.InteractionRegistry; import net.tomatentum.marinara.util.LoggerUtil; @@ -15,26 +17,32 @@ public class Marinara { return new Marinara(wrapper); } + private LibraryWrapper wrapper; + private ReflectedMethodFactory reflectedMethodFactory; private InteractionRegistry registry; private InteractionCheckRegistry checkRegistry; - private LibraryWrapper wrapper; private Marinara(LibraryWrapper wrapper) { this.wrapper = wrapper; + this.reflectedMethodFactory = new ReflectedMethodFactoryImpl(this); this.registry = new InteractionRegistry(this); this.checkRegistry = new InteractionCheckRegistry(); logger.info("Marinara loaded successfully!"); } + public LibraryWrapper getWrapper() { + return this.wrapper; + } + public InteractionRegistry getRegistry() { - return registry; + return this.registry; } public InteractionCheckRegistry getCheckRegistry() { - return checkRegistry; + return this.checkRegistry; } - public LibraryWrapper getWrapper() { - return wrapper; + public ReflectedMethodFactory getReflectedMethodFactory() { + return this.reflectedMethodFactory; } } diff --git a/lib/src/main/java/net/tomatentum/marinara/interaction/components/methods/ButtonInteractionMethod.java b/lib/src/main/java/net/tomatentum/marinara/interaction/components/methods/ButtonInteractionMethod.java index 08cfaa8..82e25a6 100644 --- a/lib/src/main/java/net/tomatentum/marinara/interaction/components/methods/ButtonInteractionMethod.java +++ b/lib/src/main/java/net/tomatentum/marinara/interaction/components/methods/ButtonInteractionMethod.java @@ -1,30 +1,26 @@ package net.tomatentum.marinara.interaction.components.methods; import java.lang.reflect.Method; +import java.util.List; import net.tomatentum.marinara.Marinara; import net.tomatentum.marinara.interaction.InteractionHandler; import net.tomatentum.marinara.interaction.InteractionType; +import net.tomatentum.marinara.interaction.annotation.Button; import net.tomatentum.marinara.interaction.ident.InteractionIdentifier; import net.tomatentum.marinara.interaction.methods.InteractionMethod; import net.tomatentum.marinara.parser.AnnotationParser; import net.tomatentum.marinara.parser.ButtonParser; +import net.tomatentum.marinara.reflection.ReflectedMethod; public class ButtonInteractionMethod extends InteractionMethod { private String customId; - public ButtonInteractionMethod(Method method, InteractionHandler handler, Marinara marinara) { + private ButtonInteractionMethod(Method method, InteractionHandler handler, Marinara marinara) { super(method, handler, marinara); } - @Override - public AnnotationParser[] provideParsers() { - return new AnnotationParser[] { - new ButtonParser(method(), (x) -> { this.customId = x; } ) - }; - } - @Override public Object getParameter(Object context, int index) { Class type = method().getParameterTypes()[index+1]; @@ -40,4 +36,28 @@ public class ButtonInteractionMethod extends InteractionMethod { .build(); } + public static class Factory extends InteractionMethod.Factory { + + @Override + public ReflectedMethod produce(Marinara marinara, Method method, Object containingObject) { + if (!method.isAnnotationPresent(Button.class) || + !(containingObject instanceof InteractionHandler) + ) + return null; + + return new ButtonInteractionMethod(method, (InteractionHandler) containingObject, marinara); + } + + @Override + public void addParser(ReflectedMethod method, List parser) { + super.addParser(method, parser); + + ButtonInteractionMethod imethod = (ButtonInteractionMethod) method; + parser.add( + new ButtonParser(method.method(), x -> imethod.customId = x) + ); + } + + } + } diff --git a/lib/src/main/java/net/tomatentum/marinara/interaction/methods/AutoCompleteInteractionMethod.java b/lib/src/main/java/net/tomatentum/marinara/interaction/methods/AutoCompleteInteractionMethod.java index 356d9b5..c1b6477 100644 --- a/lib/src/main/java/net/tomatentum/marinara/interaction/methods/AutoCompleteInteractionMethod.java +++ b/lib/src/main/java/net/tomatentum/marinara/interaction/methods/AutoCompleteInteractionMethod.java @@ -1,31 +1,27 @@ package net.tomatentum.marinara.interaction.methods; import java.lang.reflect.Method; +import java.util.List; import net.tomatentum.marinara.Marinara; import net.tomatentum.marinara.interaction.InteractionHandler; +import net.tomatentum.marinara.interaction.annotation.AutoComplete; import net.tomatentum.marinara.interaction.ident.InteractionIdentifier; import net.tomatentum.marinara.parser.AnnotationParser; import net.tomatentum.marinara.parser.SlashCommandParser; +import net.tomatentum.marinara.reflection.ReflectedMethod; public class AutoCompleteInteractionMethod extends InteractionMethod { private InteractionIdentifier interactionIdentifier; - public AutoCompleteInteractionMethod(Method method, + private AutoCompleteInteractionMethod(Method method, InteractionHandler handler, Marinara marinara ) { super(method, handler, marinara); } - @Override - public AnnotationParser[] provideParsers() { - return new AnnotationParser[] { - new SlashCommandParser(method(), true, (x) -> { this.interactionIdentifier = x; } ) - }; - } - @Override public Object getParameter(Object context, int index) { Class type = method().getParameterTypes()[index+1]; @@ -40,5 +36,29 @@ public class AutoCompleteInteractionMethod extends InteractionMethod { public InteractionIdentifier identifier() { return interactionIdentifier; } + + public static class Factory extends InteractionMethod.Factory { + + @Override + public ReflectedMethod produce(Marinara marinara, Method method, Object containingObject) { + if (!method.isAnnotationPresent(AutoComplete.class) || + !(containingObject instanceof InteractionHandler) + ) + return null; + + return new AutoCompleteInteractionMethod(method, (InteractionHandler) containingObject, marinara); + } + + @Override + public void addParser(ReflectedMethod method, List parser) { + super.addParser(method, parser); + + AutoCompleteInteractionMethod imethod = (AutoCompleteInteractionMethod) method; + parser.add( + new SlashCommandParser(method.method(), true, x -> imethod.interactionIdentifier = x) + ); + } + + } } diff --git a/lib/src/main/java/net/tomatentum/marinara/interaction/methods/InteractionMethod.java b/lib/src/main/java/net/tomatentum/marinara/interaction/methods/InteractionMethod.java index d68d513..2e56a7e 100644 --- a/lib/src/main/java/net/tomatentum/marinara/interaction/methods/InteractionMethod.java +++ b/lib/src/main/java/net/tomatentum/marinara/interaction/methods/InteractionMethod.java @@ -7,28 +7,14 @@ import java.util.List; import net.tomatentum.marinara.Marinara; import net.tomatentum.marinara.checks.AppliedCheck; import net.tomatentum.marinara.interaction.InteractionHandler; -import net.tomatentum.marinara.interaction.annotation.AutoComplete; -import net.tomatentum.marinara.interaction.annotation.Button; -import net.tomatentum.marinara.interaction.commands.annotation.SlashCommand; -import net.tomatentum.marinara.interaction.commands.annotation.SubCommand; -import net.tomatentum.marinara.interaction.components.methods.ButtonInteractionMethod; import net.tomatentum.marinara.interaction.ident.InteractionIdentifier; import net.tomatentum.marinara.parser.AnnotationParser; import net.tomatentum.marinara.parser.InteractionCheckParser; -import net.tomatentum.marinara.util.ReflectedMethod; +import net.tomatentum.marinara.reflection.ReflectedMethod; +import net.tomatentum.marinara.reflection.ReflectedMethodFactory; public abstract class InteractionMethod extends ReflectedMethod { - public static InteractionMethod create(Method method, InteractionHandler handler, Marinara marinara) { - if (method.isAnnotationPresent(AutoComplete.class)) - return new AutoCompleteInteractionMethod(method, handler, marinara); - if (method.isAnnotationPresent(SlashCommand.class) || method.isAnnotationPresent(SubCommand.class)) - return new SlashCommandInteractionMethod(method, handler, marinara); - if (method.isAnnotationPresent(Button.class)) - return new ButtonInteractionMethod(method, handler, marinara); - return null; - } - protected Marinara marinara; protected List appliedChecks; @@ -41,13 +27,6 @@ public abstract class InteractionMethod extends ReflectedMethod { this.marinara = marinara; this.appliedChecks = new ArrayList<>(); } - - @Override - public AnnotationParser[] provideParsers() { - return new AnnotationParser[] { - new InteractionCheckParser(method(), appliedChecks::add, marinara.getCheckRegistry()) - }; - } @Override public Object run(Object context) { @@ -64,4 +43,24 @@ public abstract class InteractionMethod extends ReflectedMethod { public abstract InteractionIdentifier identifier(); + public Marinara marinara() { + return this.marinara; + } + + public List appliedChecks() { + return this.appliedChecks; + } + + public static abstract class Factory implements ReflectedMethodFactory.Factory { + + @Override + public void addParser(ReflectedMethod method, List parser) { + InteractionMethod imethod = (InteractionMethod) method; + parser.add( + new InteractionCheckParser(method.method(), imethod.appliedChecks::add, imethod.marinara().getCheckRegistry()) + ); + } + + } + } diff --git a/lib/src/main/java/net/tomatentum/marinara/interaction/methods/SlashCommandInteractionMethod.java b/lib/src/main/java/net/tomatentum/marinara/interaction/methods/SlashCommandInteractionMethod.java index c7edd47..a0adb74 100644 --- a/lib/src/main/java/net/tomatentum/marinara/interaction/methods/SlashCommandInteractionMethod.java +++ b/lib/src/main/java/net/tomatentum/marinara/interaction/methods/SlashCommandInteractionMethod.java @@ -1,29 +1,26 @@ package net.tomatentum.marinara.interaction.methods; import java.lang.reflect.Method; +import java.util.List; import net.tomatentum.marinara.Marinara; import net.tomatentum.marinara.interaction.InteractionHandler; +import net.tomatentum.marinara.interaction.commands.annotation.SlashCommand; +import net.tomatentum.marinara.interaction.commands.annotation.SubCommand; import net.tomatentum.marinara.interaction.ident.InteractionIdentifier; import net.tomatentum.marinara.interaction.ident.SlashCommandIdentifier; import net.tomatentum.marinara.parser.AnnotationParser; import net.tomatentum.marinara.parser.SlashCommandParser; +import net.tomatentum.marinara.reflection.ReflectedMethod; public class SlashCommandInteractionMethod extends InteractionMethod { private SlashCommandIdentifier interactionIdentifier; - SlashCommandInteractionMethod(Method method, InteractionHandler handler, Marinara marinara) { + private SlashCommandInteractionMethod(Method method, InteractionHandler handler, Marinara marinara) { super(method, handler, marinara); } - @Override - public AnnotationParser[] provideParsers() { - return new AnnotationParser[] { - new SlashCommandParser(method(), false, (x) -> { this.interactionIdentifier = x; } ) - }; - } - @Override public Object getParameter(Object context, int index) { return marinara.getWrapper().getContextObjectProvider().convertCommandOption(context, interactionIdentifier.options()[index].name()); @@ -34,4 +31,29 @@ public class SlashCommandInteractionMethod extends InteractionMethod { return interactionIdentifier; } + public static class Factory extends InteractionMethod.Factory { + + @Override + public ReflectedMethod produce(Marinara marinara, Method method, Object containingObject) { + if (!(method.isAnnotationPresent(SlashCommand.class) || + method.isAnnotationPresent(SubCommand.class)) || + !(containingObject instanceof InteractionHandler) + ) + return null; + + return new SlashCommandInteractionMethod(method, (InteractionHandler) containingObject, marinara); + } + + @Override + public void addParser(ReflectedMethod method, List parser) { + super.addParser(method, parser); + + SlashCommandInteractionMethod imethod = (SlashCommandInteractionMethod) method; + parser.add( + new SlashCommandParser(method.method(), false, x -> imethod.interactionIdentifier = x) + ); + } + + } + } diff --git a/lib/src/main/java/net/tomatentum/marinara/util/ReflectedMethod.java b/lib/src/main/java/net/tomatentum/marinara/reflection/ReflectedMethod.java similarity index 82% rename from lib/src/main/java/net/tomatentum/marinara/util/ReflectedMethod.java rename to lib/src/main/java/net/tomatentum/marinara/reflection/ReflectedMethod.java index af5df50..fa0a1fd 100644 --- a/lib/src/main/java/net/tomatentum/marinara/util/ReflectedMethod.java +++ b/lib/src/main/java/net/tomatentum/marinara/reflection/ReflectedMethod.java @@ -1,4 +1,4 @@ -package net.tomatentum.marinara.util; +package net.tomatentum.marinara.reflection; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -9,7 +9,8 @@ import java.util.List; import org.slf4j.Logger; -import net.tomatentum.marinara.parser.AnnotationParser; +import net.tomatentum.marinara.util.LoggerUtil; +import net.tomatentum.marinara.util.ReflectionUtil; public abstract class ReflectedMethod { @@ -17,22 +18,16 @@ public abstract class ReflectedMethod { private Method method; private Object containingObject; - protected List parsers; public ReflectedMethod(Method method, Object containingObject) { if (!Arrays.asList(containingObject.getClass().getMethods()).contains(method)) throw new InvalidParameterException("Method does not apply to specified handler"); this.method = method; this.containingObject = containingObject; - this.parsers = new ArrayList<>(Arrays.asList(provideParsers())); - - this.parsers.stream().forEach(AnnotationParser::parse); } public abstract Object getParameter(Object context, int index); - public abstract AnnotationParser[] provideParsers(); - public Object run(Object context) { method.setAccessible(true); try { @@ -51,10 +46,6 @@ public abstract class ReflectedMethod { return this.containingObject; } - public List parsers() { - return this.parsers; - } - private Object[] getParameters(Object context) { int parameterCount = method.getParameterCount(); List parameters = new ArrayList<>(); diff --git a/lib/src/main/java/net/tomatentum/marinara/reflection/ReflectedMethodFactory.java b/lib/src/main/java/net/tomatentum/marinara/reflection/ReflectedMethodFactory.java new file mode 100644 index 0000000..134a975 --- /dev/null +++ b/lib/src/main/java/net/tomatentum/marinara/reflection/ReflectedMethodFactory.java @@ -0,0 +1,19 @@ +package net.tomatentum.marinara.reflection; + +import java.lang.reflect.Method; +import java.util.List; + +import net.tomatentum.marinara.Marinara; +import net.tomatentum.marinara.parser.AnnotationParser; + +public interface ReflectedMethodFactory { + ReflectedMethod produce(Method method, Object containingClass); + ReflectedMethodFactory addFactory(Factory factory); + + public interface Factory { + + ReflectedMethod produce(Marinara marinara, Method method, Object containingObject); + void addParser(ReflectedMethod method, List parser); + + } +} \ No newline at end of file diff --git a/lib/src/main/java/net/tomatentum/marinara/reflection/ReflectedMethodFactoryImpl.java b/lib/src/main/java/net/tomatentum/marinara/reflection/ReflectedMethodFactoryImpl.java new file mode 100644 index 0000000..d04c59e --- /dev/null +++ b/lib/src/main/java/net/tomatentum/marinara/reflection/ReflectedMethodFactoryImpl.java @@ -0,0 +1,63 @@ +package net.tomatentum.marinara.reflection; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import org.slf4j.Logger; + +import net.tomatentum.marinara.Marinara; +import net.tomatentum.marinara.parser.AnnotationParser; +import net.tomatentum.marinara.util.LoggerUtil; +import net.tomatentum.marinara.util.ReflectionUtil; + +public class ReflectedMethodFactoryImpl implements ReflectedMethodFactory { + + private Logger logger = LoggerUtil.getLogger(getClass()); + + private Marinara marinara; + private List factories; + + public ReflectedMethodFactoryImpl(Marinara marinara) { + this(marinara, new ArrayList<>()); + } + + public ReflectedMethodFactoryImpl(Marinara marinara, List factories) { + this.marinara = marinara; + this.factories = factories; + } + + @Override + public ReflectedMethod produce(Method method, Object containingClass) { + Optional imethod = this.factories.stream() + .map(f -> factoryProduce(f, method, containingClass)) + .filter(Objects::nonNull) + .findFirst(); + + if (imethod.isEmpty()) { + logger.debug("Could not produce a ReflectedMethod for Method {}", ReflectionUtil.getFullMethodName(method)); + return null; + } + + return imethod.get(); + } + + @Override + public ReflectedMethodFactory addFactory(Factory factory) { + this.factories.add(factory); + return this; + } + + private ReflectedMethod factoryProduce(Factory factory, Method method, Object containingClass) { + List parser = new ArrayList<>(); + ReflectedMethod m = factory.produce(this.marinara, method, containingClass); + if (m != null) { + factory.addParser(m, parser); + parser.forEach(AnnotationParser::parse); + } + return m; + } + +} diff --git a/lib/src/main/java/net/tomatentum/marinara/registry/InteractionRegistry.java b/lib/src/main/java/net/tomatentum/marinara/registry/InteractionRegistry.java index d1791dc..5eae605 100644 --- a/lib/src/main/java/net/tomatentum/marinara/registry/InteractionRegistry.java +++ b/lib/src/main/java/net/tomatentum/marinara/registry/InteractionRegistry.java @@ -12,12 +12,16 @@ import net.tomatentum.marinara.Marinara; import net.tomatentum.marinara.interaction.InteractionHandler; import net.tomatentum.marinara.interaction.InteractionType; import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition; +import net.tomatentum.marinara.interaction.components.methods.ButtonInteractionMethod; import net.tomatentum.marinara.interaction.ident.InteractionIdentifier; import net.tomatentum.marinara.interaction.ident.RootCommandIdentifier; import net.tomatentum.marinara.util.LoggerUtil; import net.tomatentum.marinara.util.ObjectAggregator; import net.tomatentum.marinara.wrapper.IdentifierProvider; +import net.tomatentum.marinara.interaction.methods.AutoCompleteInteractionMethod; import net.tomatentum.marinara.interaction.methods.InteractionMethod; +import net.tomatentum.marinara.interaction.methods.SlashCommandInteractionMethod; +import net.tomatentum.marinara.reflection.ReflectedMethod; public class InteractionRegistry { private Logger logger = LoggerUtil.getLogger(getClass()); @@ -30,12 +34,18 @@ public class InteractionRegistry { this.marinara = marinara; this.identifierProvider = marinara.getWrapper().createIdentifierProvider(); marinara.getWrapper().subscribeInteractions(this::handle); + marinara.getReflectedMethodFactory() + .addFactory(new AutoCompleteInteractionMethod.Factory()) + .addFactory(new SlashCommandInteractionMethod.Factory()) + .addFactory(new ButtonInteractionMethod.Factory()); + } public void addInteractions(InteractionHandler interactionHandler) { - for (Method method : interactionHandler.getClass().getMethods()) { - InteractionMethod iMethod = InteractionMethod.create(method, interactionHandler, marinara); - if (iMethod != null) { + for (Method method : interactionHandler.getClass().getDeclaredMethods()) { + ReflectedMethod rMethod = this.marinara.getReflectedMethodFactory().produce(method, interactionHandler); + if (rMethod != null && rMethod instanceof InteractionMethod) { + InteractionMethod iMethod = (InteractionMethod) rMethod; InteractionEntry.findEntry(interactions, iMethod.identifier()).addMethod(iMethod); logger.debug("Added {} method from {}", iMethod.method().getName(), interactionHandler.getClass().getSimpleName()); }