Skip to content

Commit 9ba2db8

Browse files
committed
fix external compat not adding fields as properties & search in superclasses
1 parent 2df2eca commit 9ba2db8

File tree

2 files changed

+47
-15
lines changed

2 files changed

+47
-15
lines changed

src/main/java/com/cleanroommc/groovyscript/compat/mods/ExternalModContainer.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package com.cleanroommc.groovyscript.compat.mods;
22

33
import com.cleanroommc.groovyscript.api.GroovyPlugin;
4+
import com.google.common.base.Suppliers;
45
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
56
import org.jetbrains.annotations.NotNull;
67

78
import java.util.Collection;
89
import java.util.Collections;
910
import java.util.Objects;
1011
import java.util.Set;
12+
import java.util.function.Supplier;
1113

1214
/**
1315
* This is used for external mod compat. Don't use this directly. Instead, implement {@link GroovyPlugin} on any class.
@@ -16,15 +18,19 @@
1618
public class ExternalModContainer extends GroovyContainer<GroovyPropertyContainer> {
1719

1820
private final GroovyPlugin groovyContainer;
19-
private final GroovyPropertyContainer container;
21+
private final Supplier<GroovyPropertyContainer> container;
2022
private final String modId;
2123
private final String containerName;
2224
private final Collection<String> aliases;
2325
private final Priority priority;
2426

2527
ExternalModContainer(@NotNull GroovyPlugin groovyContainer, @NotNull GroovyPropertyContainer container) {
2628
this.groovyContainer = Objects.requireNonNull(groovyContainer);
27-
this.container = Objects.requireNonNull(container);
29+
Objects.requireNonNull(container);
30+
this.container = Suppliers.memoize(() -> {
31+
container.addPropertyFieldsOf(container, false);
32+
return container;
33+
});
2834
this.modId = groovyContainer.getModId();
2935
this.containerName = groovyContainer.getContainerName();
3036
Set<String> aliasSet = new ObjectOpenHashSet<>(groovyContainer.getAliases());
@@ -60,7 +66,7 @@ public void onCompatLoaded(GroovyContainer<?> container) {
6066

6167
@Override
6268
public GroovyPropertyContainer get() {
63-
return container;
69+
return container.get();
6470
}
6571

6672
@Override

src/main/java/com/cleanroommc/groovyscript/compat/mods/GroovyPropertyContainer.java

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import com.cleanroommc.groovyscript.sandbox.expand.ExpansionHelper;
88
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
99
import org.jetbrains.annotations.ApiStatus;
10+
import org.jetbrains.annotations.NotNull;
11+
import org.jetbrains.annotations.Nullable;
1012
import org.jetbrains.annotations.UnmodifiableView;
1113

1214
import java.lang.reflect.Field;
@@ -47,28 +49,52 @@ protected void addProperty(INamed property) {
4749
@ApiStatus.OverrideOnly
4850
public void initialize(GroovyContainer<?> owner) {}
4951

50-
protected void addPropertyFieldsOf(Object object, boolean privateToo) {
52+
protected void addPropertyFieldsOf(@NotNull Object object, boolean privateToo) {
53+
addPropertyFieldsOf(object, null, privateToo);
54+
}
55+
56+
/**
57+
* Searches all fields in an object and adds them with their aliases as a groovy bean property.
58+
* This method is automatically called for every external and internal compat with the property container as its first argument.
59+
*
60+
* @param object the object to search fields in. If this is a class only static fields are allowed.
61+
* @param untilSuperclass this determines how deep the class hierarchy should be searched (this class excluded). If this i null it will search up to
62+
* {@link GroovyPropertyContainer}.class if the object to search in is a subclass of {@link GroovyPropertyContainer} or
63+
* {@link Object}.class else.
64+
* @param privateToo true if non-public fields should be included too
65+
*/
66+
protected void addPropertyFieldsOf(@NotNull Object object, @Nullable Class<?> untilSuperclass, boolean privateToo) {
5167
boolean staticOnly = false;
5268
Class<?> clazz;
53-
if (object instanceof Class<?>c) {
69+
if (object instanceof Class<?> c) {
5470
clazz = c;
5571
staticOnly = true;
5672
} else {
5773
clazz = object.getClass();
5874
}
59-
for (Field field : clazz.getDeclaredFields()) {
60-
boolean isStatic = Modifier.isStatic(field.getModifiers());
61-
if (!field.isAnnotationPresent(GroovyBlacklist.class) && INamed.class.isAssignableFrom(field.getType()) && (!staticOnly || isStatic) && (privateToo || (Modifier.isPublic(field.getModifiers())))) {
62-
try {
63-
if (!field.isAccessible()) field.setAccessible(true);
64-
Object o = field.get(isStatic ? null : object);
65-
if (o != null) {
66-
addProperty((INamed) o);
75+
if (untilSuperclass == null) {
76+
if (GroovyPropertyContainer.class.isAssignableFrom(clazz)) {
77+
untilSuperclass = GroovyPropertyContainer.class;
78+
} else {
79+
untilSuperclass = Object.class;
80+
}
81+
}
82+
while (clazz != null && clazz != untilSuperclass) {
83+
for (Field field : clazz.getDeclaredFields()) {
84+
boolean isStatic = Modifier.isStatic(field.getModifiers());
85+
if (!field.isAnnotationPresent(GroovyBlacklist.class) && INamed.class.isAssignableFrom(field.getType()) && (!staticOnly || isStatic) && (privateToo || (Modifier.isPublic(field.getModifiers())))) {
86+
try {
87+
if (!field.isAccessible()) field.setAccessible(true);
88+
Object o = field.get(isStatic ? null : object);
89+
if (o != null) {
90+
addProperty((INamed) o);
91+
}
92+
} catch (IllegalAccessException e) {
93+
GroovyLog.get().errorMC("Failed to register {} as named property", field.getName());
6794
}
68-
} catch (IllegalAccessException e) {
69-
GroovyLog.get().errorMC("Failed to register {} as named property", field.getName());
7095
}
7196
}
97+
clazz = clazz.getSuperclass();
7298
}
7399
}
74100
}

0 commit comments

Comments
 (0)