diff --git a/src/main/java/com/denizenscript/denizencore/objects/ObjectTag.java b/src/main/java/com/denizenscript/denizencore/objects/ObjectTag.java index 9a14186f..58bdad41 100644 --- a/src/main/java/com/denizenscript/denizencore/objects/ObjectTag.java +++ b/src/main/java/com/denizenscript/denizencore/objects/ObjectTag.java @@ -309,4 +309,11 @@ default boolean tryAdvancedMatcher(String matcher) { default ObjectTag refreshState() { return this; } + + /** + * Return the appropriate Java object for this Denizen object, if any. + */ + default Object getJavaObject() { + return CoreUtilities.objectTagToJavaForm(this, false, false); + } } diff --git a/src/main/java/com/denizenscript/denizencore/objects/core/BinaryTag.java b/src/main/java/com/denizenscript/denizencore/objects/core/BinaryTag.java index da03c883..62ae2bf5 100644 --- a/src/main/java/com/denizenscript/denizencore/objects/core/BinaryTag.java +++ b/src/main/java/com/denizenscript/denizencore/objects/core/BinaryTag.java @@ -149,6 +149,11 @@ public String toString() { return identify(); } + @Override + public Object getJavaObject() { + return data; + } + public static void registerTags() { // <--[tag] diff --git a/src/main/java/com/denizenscript/denizencore/objects/core/DurationTag.java b/src/main/java/com/denizenscript/denizencore/objects/core/DurationTag.java index ba5c3f67..67f0c98d 100644 --- a/src/main/java/com/denizenscript/denizencore/objects/core/DurationTag.java +++ b/src/main/java/com/denizenscript/denizencore/objects/core/DurationTag.java @@ -313,6 +313,11 @@ public ObjectTag setPrefix(String prefix) { return this; } + @Override + public Object getJavaObject() { + return getSeconds(); + } + public static void registerTags() { ///////////////////// diff --git a/src/main/java/com/denizenscript/denizencore/objects/core/ElementTag.java b/src/main/java/com/denizenscript/denizencore/objects/core/ElementTag.java index 7cb2d182..04259f46 100644 --- a/src/main/java/com/denizenscript/denizencore/objects/core/ElementTag.java +++ b/src/main/java/com/denizenscript/denizencore/objects/core/ElementTag.java @@ -397,6 +397,11 @@ public String toString() { return identify(); } + @Override + public Object getJavaObject() { + return element; + } + @Override public boolean isUnique() { return false; diff --git a/src/main/java/com/denizenscript/denizencore/objects/core/JavaReflectedObjectTag.java b/src/main/java/com/denizenscript/denizencore/objects/core/JavaReflectedObjectTag.java index 3449eacf..7f1f8c93 100644 --- a/src/main/java/com/denizenscript/denizencore/objects/core/JavaReflectedObjectTag.java +++ b/src/main/java/com/denizenscript/denizencore/objects/core/JavaReflectedObjectTag.java @@ -5,10 +5,7 @@ import com.denizenscript.denizencore.tags.Attribute; import com.denizenscript.denizencore.tags.ObjectTagProcessor; import com.denizenscript.denizencore.tags.TagContext; -import com.denizenscript.denizencore.utilities.AsciiMatcher; -import com.denizenscript.denizencore.utilities.CoreConfiguration; -import com.denizenscript.denizencore.utilities.CoreUtilities; -import com.denizenscript.denizencore.utilities.ReflectionHelper; +import com.denizenscript.denizencore.utilities.*; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -93,6 +90,12 @@ public static void clearOldRefs() { public long lastIdentified; public JavaReflectedObjectTag(Object object) { + if (object == null) { + throw new NullPointerException(); + } + if (object.getClass().isAnnotationPresent(ReflectionRefuse.class)) { + throw new RuntimeException("Cannot reflect into object of class " + object.getClass().getName() + " as it has a reflection refusal marked."); + } this.object = object; id = UUID.randomUUID(); } @@ -147,6 +150,11 @@ public String toString() { return identify(); } + @Override + public Object getJavaObject() { + return object; + } + public static void registerTags() { // <--[tag] @@ -467,6 +475,10 @@ public Object readFieldForTag(Attribute attribute, String fieldName) { if (field == null) { return null; } + if (field.isAnnotationPresent(ReflectionRefuse.class) || field.getType().isAnnotationPresent(ReflectionRefuse.class)) { + attribute.echoError("Cannot read field '" + field.getName() + "' in class '" + field.getDeclaringClass().getName() + "' because it is marked for reflection refusal."); + return null; + } if (object instanceof Class && !Modifier.isStatic(field.getModifiers())) { attribute.echoError("Cannot read field '" + field.getName() + "' in class '" + field.getDeclaringClass().getName() + "' because the field is not static."); return null; diff --git a/src/main/java/com/denizenscript/denizencore/objects/core/ListTag.java b/src/main/java/com/denizenscript/denizencore/objects/core/ListTag.java index b97e9a25..7c74a103 100644 --- a/src/main/java/com/denizenscript/denizencore/objects/core/ListTag.java +++ b/src/main/java/com/denizenscript/denizencore/objects/core/ListTag.java @@ -613,6 +613,15 @@ public String toString() { return identify(); } + @Override + public Object getJavaObject() { + ArrayList result = new ArrayList<>(); + for (ObjectTag obj : objectForms) { + result.add(obj.getJavaObject()); + } + return result; + } + ////////////////////////////// // DSCRIPT ARGUMENT METHODS ///////////////////////// diff --git a/src/main/java/com/denizenscript/denizencore/objects/core/MapTag.java b/src/main/java/com/denizenscript/denizencore/objects/core/MapTag.java index 3bde6f25..594aa4d5 100644 --- a/src/main/java/com/denizenscript/denizencore/objects/core/MapTag.java +++ b/src/main/java/com/denizenscript/denizencore/objects/core/MapTag.java @@ -215,6 +215,15 @@ public String toString() { return identify(); } + @Override + public Object getJavaObject() { + LinkedHashMap result = new LinkedHashMap<>(); + for (Map.Entry pair : map.entrySet()) { + result.put(pair.getKey().str, pair.getValue().getJavaObject()); + } + return result; + } + public ObjectTag getDeepObject(String key) { if (!CoreUtilities.contains(key, '.')) { return getObject(key); diff --git a/src/main/java/com/denizenscript/denizencore/objects/core/SecretTag.java b/src/main/java/com/denizenscript/denizencore/objects/core/SecretTag.java index 5e1a57b1..9dbfd380 100644 --- a/src/main/java/com/denizenscript/denizencore/objects/core/SecretTag.java +++ b/src/main/java/com/denizenscript/denizencore/objects/core/SecretTag.java @@ -7,13 +7,16 @@ import com.denizenscript.denizencore.tags.ObjectTagProcessor; import com.denizenscript.denizencore.tags.TagContext; import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.ReflectionRefuse; import com.denizenscript.denizencore.utilities.YamlConfiguration; import com.denizenscript.denizencore.utilities.debugging.Debug; import java.io.File; +@ReflectionRefuse public class SecretTag implements ObjectTag { + @ReflectionRefuse public static YamlConfiguration secretsFile; public static void load() { @@ -104,6 +107,7 @@ public boolean isValid() { return getValue() != null; } + @ReflectionRefuse public String getValue() { if (secretsFile == null) { return null; diff --git a/src/main/java/com/denizenscript/denizencore/objects/core/TimeTag.java b/src/main/java/com/denizenscript/denizencore/objects/core/TimeTag.java index fba2992d..987250d1 100644 --- a/src/main/java/com/denizenscript/denizencore/objects/core/TimeTag.java +++ b/src/main/java/com/denizenscript/denizencore/objects/core/TimeTag.java @@ -202,6 +202,11 @@ public String toString() { return identify(); } + @Override + public Object getJavaObject() { + return instant; + } + public int year() { return instant.get(ChronoField.YEAR); } diff --git a/src/main/java/com/denizenscript/denizencore/tags/ObjectTagProcessor.java b/src/main/java/com/denizenscript/denizencore/tags/ObjectTagProcessor.java index c97a228d..f1a8c4bc 100644 --- a/src/main/java/com/denizenscript/denizencore/tags/ObjectTagProcessor.java +++ b/src/main/java/com/denizenscript/denizencore/tags/ObjectTagProcessor.java @@ -4,6 +4,7 @@ import com.denizenscript.denizencore.objects.ObjectFetcher; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; +import com.denizenscript.denizencore.objects.core.JavaReflectedObjectTag; import com.denizenscript.denizencore.objects.core.ListTag; import com.denizenscript.denizencore.objects.core.ScriptTag; import com.denizenscript.denizencore.scripts.commands.Comparable; @@ -11,6 +12,7 @@ import com.denizenscript.denizencore.scripts.queues.ScriptQueue; import com.denizenscript.denizencore.utilities.CoreConfiguration; import com.denizenscript.denizencore.utilities.CoreUtilities; +import com.denizenscript.denizencore.utilities.ReflectionRefuse; import com.denizenscript.denizencore.utilities.ScriptUtilities; import com.denizenscript.denizencore.utilities.codegen.TagNamer; import com.denizenscript.denizencore.utilities.debugging.Debug; @@ -330,6 +332,27 @@ public void generateCoreTags() { } return new ElementTag(object.tryAdvancedMatcher(attribute.getParam())); }, "advanced_matches_text"); + + // <--[tag] + // @attribute + // @returns JavaReflectedObjectTag + // @description + // Returns the reflected internal Java object for a given ObjectTag. + // --> + registerTag(JavaReflectedObjectTag.class, "reflected_internal_object", (attribute, object) -> { + Object obj = object.getJavaObject(); + if (!CoreConfiguration.allowReflectionFieldReads) { + return null; + } + if (obj == null) { + return null; + } + if (obj.getClass().isAnnotationPresent(ReflectionRefuse.class)) { + attribute.echoError("Cannot reflect object " + object + " as its type '" + obj.getClass().getName() + "' is marked as refused for reflection."); + return null; + } + return new JavaReflectedObjectTag(obj); + }); } public void registerFutureTagDeprecation(String name, String... deprecatedVariants) { diff --git a/src/main/java/com/denizenscript/denizencore/utilities/CoreUtilities.java b/src/main/java/com/denizenscript/denizencore/utilities/CoreUtilities.java index 1d8dee02..8fa1ee1b 100644 --- a/src/main/java/com/denizenscript/denizencore/utilities/CoreUtilities.java +++ b/src/main/java/com/denizenscript/denizencore/utilities/CoreUtilities.java @@ -118,7 +118,10 @@ else if (obj instanceof Map) { } } - + /** + * Gets a Java form of an object, for serialization API usage. + * For raw object forms, use {@link ObjectTag#getJavaObject} + */ public static Object objectTagToJavaForm(ObjectTag obj, boolean stringHolder, boolean nativeTypes) { if (obj == null) { return null; diff --git a/src/main/java/com/denizenscript/denizencore/utilities/ReflectionRefuse.java b/src/main/java/com/denizenscript/denizencore/utilities/ReflectionRefuse.java new file mode 100644 index 00000000..38306de9 --- /dev/null +++ b/src/main/java/com/denizenscript/denizencore/utilities/ReflectionRefuse.java @@ -0,0 +1,11 @@ +package com.denizenscript.denizencore.utilities; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Annotates that a field/method/class should not be reflected into with Denizen scripting reflection tools like {@link com.denizenscript.denizencore.objects.core.JavaReflectedObjectTag} + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface ReflectionRefuse { +}