From 6111dece6178fa233c26a34b5b350c3a23df3d4b Mon Sep 17 00:00:00 2001
From: altrisi
Date: Thu, 17 Mar 2022 21:21:44 +0100
Subject: [PATCH] Ease concrete restrictions on Annotated Scarpet API and make
instantiating lazy
Prevents instantiating classes with all annotated methods static, making it also more flexible in that you can put annotated functions near to other API that may be initialized
---
.../script/annotation/AnnotationParser.java | 52 ++++++++++---------
.../script/annotation/ScarpetFunction.java | 7 ++-
2 files changed, 31 insertions(+), 28 deletions(-)
diff --git a/src/main/java/carpet/script/annotation/AnnotationParser.java b/src/main/java/carpet/script/annotation/AnnotationParser.java
index 711a4bb2..891c64a3 100644
--- a/src/main/java/carpet/script/annotation/AnnotationParser.java
+++ b/src/main/java/carpet/script/annotation/AnnotationParser.java
@@ -12,11 +12,14 @@ import java.util.List;
import java.util.ListIterator;
import java.util.Objects;
import java.util.Optional;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ClassUtils;
+import com.google.common.base.Suppliers;
+
import carpet.CarpetExtension;
import carpet.script.Context;
import carpet.script.Expression;
@@ -26,6 +29,7 @@ import carpet.script.Fluff.UsageProvider;
import carpet.script.exception.InternalExpressionException;
import carpet.script.LazyValue;
import carpet.script.value.Value;
+import net.fabricmc.api.ModInitializer;
/**
*
This class parses methods annotated with the {@link ScarpetFunction} annotation in a given {@link Class}, generating
@@ -81,13 +85,11 @@ public final class AnnotationParser
*
Parses a given {@link Class} and registers its annotated methods, the ones with the {@link ScarpetFunction} annotation,
* to be used in the Scarpet language.
*
- *
Only call this method once per class per lifetime of the JVM! (for example, at {@link CarpetExtension#onGameStarted()})
+ *
Only call this method once per class per lifetime of the JVM! (for example, at {@link CarpetExtension#onGameStarted()} or
+ * {@link ModInitializer#onInitialize()}).
*
*
There is a set of requirements for the class and its methods:
*
- *
Class must be concrete. That is, no interfaces or abstract classes should be passed
- *
Class must have the default constructor (or an equivalent) available. That is done in order to not need the {@code static} modifier in every
- * method, making them faster to code and simpler to look at.
*
Annotated methods must not throw checked exceptions. They can throw regular {@link RuntimeException}s (including but not limited to
* {@link InternalExpressionException}).
* Basically, it's fine as long as you don't add a {@code throws} declaration to your methods.
@@ -97,26 +99,28 @@ public final class AnnotationParser
*
Annotated methods must not have a parameter with generics as the varargs parameter. This is just because it was painful for me (altrisi) and
* didn't want to support it. Those will crash with a {@code ClassCastException}
*
+ *
Additionally, if the class contains annotated instance (non-static) methods, the class must be concrete and provide a no-arg constructor
+ * to instantiate it.
*
* @see ScarpetFunction
- * @param The generic type of the class to parse.
* @param clazz The class to parse
*/
- public static void parseFunctionClass(Class clazz)
+ public static void parseFunctionClass(Class> clazz)
{
- if (Modifier.isAbstract(clazz.getModifiers()))
- throw new IllegalArgumentException("Function class must be concrete! Class: " + clazz.getSimpleName());
- T instance;
- try
- {
- instance = clazz.getConstructor().newInstance();
- }
- catch (ReflectiveOperationException e)
- {
- throw new IllegalArgumentException(
- "Couldn't create instance of given " + clazz + ". Make sure default constructor is available", e);
- }
-
+ // Only try to instantiate or require concrete classes if there are non-static annotated methods
+ Supplier
*
*
Methods annotated with this annotation must not declare throwing any checked exceptions.