Skip to content

Commit 758a38b

Browse files
committed
ModuleInstance also works with client replacements
1 parent 10c084a commit 758a38b

File tree

2 files changed

+103
-93
lines changed

2 files changed

+103
-93
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,93 @@
11
package org.violetmoon.zeta.module;
22

3+
import org.apache.commons.lang3.text.WordUtils;
4+
import org.violetmoon.zeta.util.ZetaSide;
5+
36
import java.util.Locale;
47
import java.util.Set;
58
import java.util.function.Function;
69

7-
import org.apache.commons.lang3.text.WordUtils;
8-
import org.violetmoon.zeta.util.ZetaSide;
9-
1010
/**
1111
* performs some common data-munging of the data straight off a ZetaLoadModule annotation
1212
*/
1313
public record TentativeModule(
14-
Class<? extends ZetaModule> clazz,
15-
Class<? extends ZetaModule> keyClass,
14+
Class<? extends ZetaModule> clazz,
15+
Class<? extends ZetaModule> keyClass,
1616

17-
ZetaCategory category,
18-
String displayName,
19-
String lowercaseName,
20-
String description,
21-
Set<String> antiOverlap,
22-
boolean enabledByDefault,
17+
ZetaCategory category,
18+
String displayName,
19+
String lowercaseName,
20+
String description,
21+
Set<String> antiOverlap,
22+
boolean enabledByDefault,
2323

24-
boolean clientReplacement,
25-
int loadPhase
24+
boolean clientReplacement,
25+
int loadPhase
2626
) {
27-
@SuppressWarnings("unchecked")
28-
public static TentativeModule from(ZetaLoadModuleAnnotationData data, Function<String, ZetaCategory> categoryResolver) {
29-
Class<?> clazzUnchecked = data.clazz();
30-
if(!ZetaModule.class.isAssignableFrom(clazzUnchecked))
31-
throw new RuntimeException("Class " + clazzUnchecked.getName() + " does not extend ZetaModule");
32-
Class<? extends ZetaModule> clazz = (Class<? extends ZetaModule>) clazzUnchecked;
27+
@SuppressWarnings("unchecked")
28+
public static TentativeModule from(ZetaLoadModuleAnnotationData data, Function<String, ZetaCategory> categoryResolver) {
29+
Class<?> clazzUnchecked = data.clazz();
30+
if (!ZetaModule.class.isAssignableFrom(clazzUnchecked))
31+
throw new RuntimeException("Class " + clazzUnchecked.getName() + " does not extend ZetaModule");
32+
Class<? extends ZetaModule> clazz = (Class<? extends ZetaModule>) clazzUnchecked;
3333

34-
String displayName;
35-
if(data.name().isEmpty())
36-
displayName = WordUtils.capitalizeFully(clazz.getSimpleName().replaceAll("Module$", "").replaceAll("(?<=.)([A-Z])", " $1"));
37-
else
38-
displayName = data.name();
39-
String lowercaseName = displayName.toLowerCase(Locale.ROOT).replace(" ", "_");
34+
String displayName;
35+
if (data.name().isEmpty())
36+
displayName = WordUtils.capitalizeFully(clazz.getSimpleName().replaceAll("Module$", "").replaceAll("(?<=.)([A-Z])", " $1"));
37+
else
38+
displayName = data.name();
39+
String lowercaseName = displayName.toLowerCase(Locale.ROOT).replace(" ", "_");
4040

41-
boolean clientReplacement = data.clientReplacement();
41+
boolean clientReplacement = data.clientReplacement();
4242

43-
Class<? extends ZetaModule> keyClass;
44-
if(clientReplacement) {
45-
Class<?> sup = clazz.getSuperclass();
46-
if(ZetaModule.class.isAssignableFrom(sup) && ZetaModule.class != sup)
47-
keyClass = (Class<? extends ZetaModule>) clazz.getSuperclass();
48-
else
49-
throw new RuntimeException("Client extension module " + clazz.getName() + " should `extend` the module it's an extension of");
50-
} else {
51-
keyClass = clazz;
43+
Class<? extends ZetaModule> keyClass;
44+
if (clientReplacement) {
45+
Class<?> sup = clazz.getSuperclass();
46+
if (ZetaModule.class.isAssignableFrom(sup) && ZetaModule.class != sup)
47+
keyClass = (Class<? extends ZetaModule>) clazz.getSuperclass();
48+
else
49+
throw new RuntimeException("Client extension module " + clazz.getName() + " should `extend` the module it's an extension of");
50+
} else {
51+
keyClass = clazz;
5252

53-
//Only client replacement modules are allowed to leave off a category annotation (since it uses the same category as the module it's replacing)
54-
if(data.category() == null || data.category().isEmpty())
55-
throw new RuntimeException("Module " + clazz.getName() + " should specify a category");
56-
}
53+
//Only client replacement modules are allowed to leave off a category annotation (since it uses the same category as the module it's replacing)
54+
if (data.category() == null || data.category().isEmpty())
55+
throw new RuntimeException("Module " + clazz.getName() + " should specify a category");
56+
}
5757

58-
return new TentativeModule(
59-
clazz,
60-
keyClass,
61-
categoryResolver.apply(data.category()),
62-
displayName,
63-
lowercaseName,
64-
data.description(),
65-
Set.of(data.antiOverlap()),
66-
data.enabledByDefault(),
67-
clientReplacement,
68-
data.loadPhase()
69-
);
70-
}
58+
return new TentativeModule(
59+
clazz,
60+
keyClass,
61+
categoryResolver.apply(data.category()),
62+
displayName,
63+
lowercaseName,
64+
data.description(),
65+
Set.of(data.antiOverlap()),
66+
data.enabledByDefault(),
67+
clientReplacement,
68+
data.loadPhase()
69+
);
70+
}
7171

72-
public TentativeModule replaceWith(TentativeModule replacement) {
73-
return new TentativeModule(
74-
replacement.clazz,
75-
this.keyClass,
76-
this.category,
77-
this.displayName,
78-
this.lowercaseName,
79-
this.description,
80-
this.antiOverlap,
81-
this.enabledByDefault,
82-
false,
83-
replacement.loadPhase
84-
);
85-
}
72+
public TentativeModule replaceWith(TentativeModule replacement) {
73+
return new TentativeModule(
74+
replacement.clazz,
75+
this.keyClass,
76+
this.category,
77+
this.displayName,
78+
this.lowercaseName,
79+
this.description,
80+
this.antiOverlap,
81+
this.enabledByDefault,
82+
false,
83+
replacement.loadPhase
84+
);
85+
}
8686

87-
public boolean appliesTo(ZetaSide side) {
88-
return switch(side) {
89-
case CLIENT -> true;
90-
case SERVER -> !clientReplacement;
91-
};
92-
}
87+
public boolean appliesTo(ZetaSide side) {
88+
return switch (side) {
89+
case CLIENT -> true;
90+
case SERVER -> !clientReplacement;
91+
};
92+
}
9393
}

src/main/java/org/violetmoon/zeta/module/ZetaModuleManager.java

+31-21
Original file line numberDiff line numberDiff line change
@@ -167,31 +167,41 @@ private ZetaModule constructAndSetup(TentativeModule t) {
167167

168168
// feel free to refactor
169169
private static void populateModuleInstanceField(ZetaModule module) {
170-
try {
171-
var clazz = module.getClass();
172-
Field[] fields = clazz.getDeclaredFields();
173-
Field targetField = null;
174-
175-
for (Field field : fields) {
176-
if (field.isAnnotationPresent(ModuleInstance.class)) {
177-
if (targetField != null) {
178-
throw new IllegalStateException("Can't have more than one @ModuleInstance field per module class");
179-
}
180-
if (!Modifier.isStatic(field.getModifiers())) {
181-
throw new IllegalStateException("@ModuleInstance annotated field must be static");
182-
}
183-
if (field.getType() != module.getClass()) {
184-
throw new IllegalStateException("@ModuleInstance annotated field must be of the same type as the module class. Expected: " + module.getClass() + ", got: " + field.getType());
185-
}
186-
targetField = field;
170+
var clazz = module.getClass();
171+
172+
173+
List<Field> fields = new ArrayList<>();
174+
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
175+
176+
//if module is a client one, look at superclasstoo
177+
if (module.getClass().isAnnotationPresent(ZetaLoadModule.class)) {
178+
ZetaLoadModule annotation = module.getClass().getAnnotation(ZetaLoadModule.class);
179+
if (annotation.clientReplacement()) {
180+
fields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
181+
}
182+
}
183+
184+
List<Field> targetFields = new ArrayList<>();
185+
186+
for (Field field : fields) {
187+
if (field.isAnnotationPresent(ModuleInstance.class)) {
188+
if (!Modifier.isStatic(field.getModifiers())) {
189+
throw new IllegalStateException("@ModuleInstance annotated field must be static");
190+
}
191+
//make sure the module class can be assigned to the fields
192+
if (!field.getType().isAssignableFrom(clazz)) {
193+
throw new IllegalStateException("@ModuleInstance annotated field must be assignable from the module class. Expected: " + field.getType() + ", got: " + clazz);
187194
}
195+
targetFields.add(field);
188196
}
189-
if (targetField != null) {
190-
targetField.setAccessible(true);
197+
}
198+
for (Field targetField : targetFields) {
199+
targetField.setAccessible(true);
200+
try {
191201
targetField.set(null, module);
202+
} catch (IllegalAccessException e) {
203+
throw new RuntimeException(e);
192204
}
193-
} catch (Exception e) {
194-
throw new RuntimeException(e);
195205
}
196206
}
197207

0 commit comments

Comments
 (0)