mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-19 06:42:02 +01:00
#1493: Improve reroute performance and add some tests
By: DerFrZocker <derrieple@gmail.com>
This commit is contained in:
parent
8484d46297
commit
2a98825ddf
@ -383,6 +383,7 @@ public final class CraftServer implements Server {
|
||||
minimumAPI = ApiVersion.getOrCreateVersion(configuration.getString("settings.minimum-api"));
|
||||
loadIcon();
|
||||
loadCompatibilities();
|
||||
CraftMagicNumbers.INSTANCE.getCommodore().updateReroute(activeCompatibilities::contains);
|
||||
|
||||
// Set map color cache
|
||||
if (configuration.getBoolean("settings.use-map-color-cache")) {
|
||||
@ -930,6 +931,7 @@ public final class CraftServer implements Server {
|
||||
console.autosavePeriod = configuration.getInt("ticks-per.autosave");
|
||||
loadIcon();
|
||||
loadCompatibilities();
|
||||
CraftMagicNumbers.INSTANCE.getCommodore().updateReroute(activeCompatibilities::contains);
|
||||
|
||||
try {
|
||||
playerList.getIpBans().load();
|
||||
|
@ -7,7 +7,7 @@ public record RequirePluginVersionData(ApiVersion minInclusive, ApiVersion maxIn
|
||||
public static RequirePluginVersionData create(RequirePluginVersion requirePluginVersion) {
|
||||
if (!requirePluginVersion.value().isBlank()) {
|
||||
if (!requirePluginVersion.minInclusive().isBlank() || !requirePluginVersion.maxInclusive().isBlank()) {
|
||||
throw new RuntimeException("When setting value, min inclusive and max inclusive data is not allowed.");
|
||||
throw new IllegalArgumentException("When setting value, min inclusive and max inclusive data is not allowed.");
|
||||
}
|
||||
|
||||
return new RequirePluginVersionData(ApiVersion.getOrCreateVersion(requirePluginVersion.value()), ApiVersion.getOrCreateVersion(requirePluginVersion.value()));
|
||||
@ -23,6 +23,12 @@ public record RequirePluginVersionData(ApiVersion minInclusive, ApiVersion maxIn
|
||||
maxInclusive = ApiVersion.getOrCreateVersion(requirePluginVersion.maxInclusive());
|
||||
}
|
||||
|
||||
if (minInclusive != null && maxInclusive != null) {
|
||||
if (minInclusive.isNewerThan(maxInclusive)) {
|
||||
throw new IllegalArgumentException("Min inclusive cannot be newer than max inclusive.");
|
||||
}
|
||||
}
|
||||
|
||||
return new RequirePluginVersionData(minInclusive, maxInclusive);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,120 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import org.bukkit.craftbukkit.util.ApiVersion;
|
||||
import org.bukkit.craftbukkit.util.ClassTraverser;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
public class Reroute {
|
||||
|
||||
@VisibleForTesting
|
||||
final Map<String, RerouteDataHolder> rerouteDataMap;
|
||||
|
||||
Reroute(Map<String, RerouteDataHolder> rerouteDataMap) {
|
||||
this.rerouteDataMap = rerouteDataMap;
|
||||
}
|
||||
|
||||
/*
|
||||
This method looks (and probably is) overengineered, but it gives the most flexible when it comes to remapping normal methods to static one.
|
||||
The problem with normal owner and desc replacement is that child classes have them as an owner, instead there parents for there parents methods
|
||||
|
||||
For example, if we have following two interfaces org.bukkit.BlockData and org.bukkit.Orientable extents BlockData
|
||||
and BlockData has the method org.bukkit.Material getType which we want to reroute to the static method
|
||||
org.bukkit.Material org.bukkit.craftbukkit.legacy.EnumEvil#getType(org.bukkit.BlockData)
|
||||
|
||||
If we now call BlockData#getType we get as the owner org/bukkit/BlockData and as desc ()Lorg/bukkit/Material;
|
||||
Which we can nicely reroute by checking if the owner is BlockData and the name getType
|
||||
The problem, starts if we use Orientable#getType no we get as owner org/bukkit/Orientable and as desc ()Lorg/bukkit/Material;
|
||||
Now we can now longer safely say to which getType method we need to reroute (assume there are multiple getType methods from different classes,
|
||||
which are not related to BlockData), simple using the owner class will not work, since would reroute to
|
||||
EnumEvil#getType(org.bukkit.Orientable) which is not EnumEvil#getType(org.bukkit.BlockData) and will throw a method not found error
|
||||
at runtime.
|
||||
|
||||
Meaning we would need to add checks for each subclass, which would be pur insanity.
|
||||
|
||||
To solve this, we go through each super class and interfaces (and their super class and interfaces etc.) and try to get an owner
|
||||
which matches with one of our replacement methods. Based on how inheritance works in java, this method should be safe to use.
|
||||
|
||||
As a site note: This method could also be used for the other method reroute, e.g. legacy method rerouting, where only the replacement
|
||||
method needs to be written, and this method figures out the rest, which could reduce the size and complexity of the Commodore class.
|
||||
The question then becomes one about performance (since this is not the most performance way) and convenience.
|
||||
But since it is only applied for each class and method call once when they get first loaded, it should not be that bad.
|
||||
(Although some load time testing could be done)
|
||||
*/
|
||||
public boolean apply(ApiVersion pluginVersion, String owner, String name, String desc, boolean staticCall, Consumer<RerouteMethodData> consumer) {
|
||||
RerouteDataHolder rerouteData = rerouteDataMap.get(desc + name);
|
||||
if (rerouteData == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type ownerType = Type.getObjectType(owner);
|
||||
RerouteMethodData data = rerouteData.get(ownerType);
|
||||
|
||||
if (staticCall && data == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data != null) {
|
||||
if (data.requiredPluginVersion() != null && !data.requiredPluginVersion().test(pluginVersion)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
consumer.accept(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
Class<?> ownerClass;
|
||||
try {
|
||||
ownerClass = Class.forName(ownerType.getClassName(), false, Reroute.class.getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ClassTraverser it = new ClassTraverser(ownerClass);
|
||||
while (it.hasNext()) {
|
||||
Class<?> clazz = it.next();
|
||||
|
||||
data = rerouteData.get(Type.getType(clazz));
|
||||
|
||||
if (data == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data.requiredPluginVersion() != null && !data.requiredPluginVersion().test(pluginVersion)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
consumer.accept(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static class RerouteDataHolder {
|
||||
|
||||
@VisibleForTesting
|
||||
final Map<String, RerouteMethodData> rerouteMethodDataMap = new HashMap<>();
|
||||
|
||||
public RerouteMethodData get(Class<?> clazz) {
|
||||
return rerouteMethodDataMap.get(Type.getInternalName(clazz));
|
||||
}
|
||||
|
||||
private RerouteMethodData get(Type owner) {
|
||||
return rerouteMethodDataMap.get(owner.getInternalName());
|
||||
}
|
||||
|
||||
void add(RerouteMethodData value) {
|
||||
RerouteMethodData rerouteMethodData = get(value.sourceOwner());
|
||||
|
||||
if (rerouteMethodData != null) {
|
||||
throw new IllegalStateException("Reroute method data already exists: " + rerouteMethodData);
|
||||
}
|
||||
|
||||
rerouteMethodDataMap.put(value.sourceOwner().getInternalName(), value);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,53 +1,69 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import org.bukkit.craftbukkit.util.ApiVersion;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
public class RerouteBuilder {
|
||||
|
||||
public static Map<String, RerouteMethodData> buildFromClass(Class<?> clazz) {
|
||||
Preconditions.checkArgument(!clazz.isInterface(), "Interface Classes are currently not supported");
|
||||
private final List<Class<?>> classes = new ArrayList<>();
|
||||
private final Predicate<String> compatibilityPresent;
|
||||
|
||||
Map<String, RerouteMethodData> result = new HashMap<>();
|
||||
|
||||
for (Method method : clazz.getDeclaredMethods()) {
|
||||
if (method.isBridge()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Modifier.isPublic(method.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Modifier.isStatic(method.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.isAnnotationPresent(DoNotReroute.class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
RerouteMethodData rerouteMethodData = buildFromMethod(method);
|
||||
result.put(rerouteMethodData.source(), rerouteMethodData);
|
||||
}
|
||||
|
||||
return Collections.unmodifiableMap(result);
|
||||
private RerouteBuilder(Predicate<String> compatibilityPresent) {
|
||||
this.compatibilityPresent = compatibilityPresent;
|
||||
}
|
||||
|
||||
public static RerouteMethodData buildFromMethod(Method method) {
|
||||
public static RerouteBuilder create(Predicate<String> compatibilityPresent) {
|
||||
return new RerouteBuilder(compatibilityPresent);
|
||||
}
|
||||
|
||||
public RerouteBuilder forClass(Class<?> clazz) {
|
||||
classes.add(clazz);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Reroute build() {
|
||||
Map<String, Reroute.RerouteDataHolder> rerouteDataHolderMap = new HashMap<>();
|
||||
|
||||
for (Class<?> clazz : classes) {
|
||||
List<RerouteMethodData> data = buildFromClass(clazz, compatibilityPresent);
|
||||
data.forEach(value -> rerouteDataHolderMap.computeIfAbsent(value.methodKey(), v -> new Reroute.RerouteDataHolder()).add(value));
|
||||
}
|
||||
|
||||
return new Reroute(rerouteDataHolderMap);
|
||||
}
|
||||
|
||||
private static List<RerouteMethodData> buildFromClass(Class<?> clazz, Predicate<String> compatibilityPresent) {
|
||||
Preconditions.checkArgument(!clazz.isInterface(), "Interface Classes are currently not supported");
|
||||
|
||||
List<RerouteMethodData> result = new ArrayList<>();
|
||||
boolean shouldInclude = shouldInclude(getRequireCompatibility(clazz), true, compatibilityPresent);
|
||||
|
||||
for (Method method : clazz.getDeclaredMethods()) {
|
||||
if (!isMethodValid(method)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!shouldInclude(getRequireCompatibility(method), shouldInclude, compatibilityPresent)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result.add(buildFromMethod(method));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static RerouteMethodData buildFromMethod(Method method) {
|
||||
RerouteReturn rerouteReturn = new RerouteReturn(Type.getReturnType(method));
|
||||
List<RerouteArgument> arguments = new ArrayList<>();
|
||||
List<RerouteArgument> sourceArguments = new ArrayList<>();
|
||||
@ -113,7 +129,10 @@ public class RerouteBuilder {
|
||||
if (rerouteStatic != null) {
|
||||
sourceOwner = Type.getObjectType(rerouteStatic.value());
|
||||
} else {
|
||||
RerouteArgument argument = sourceArguments.get(0);
|
||||
if (sourceArguments.isEmpty()) {
|
||||
throw new RuntimeException("Source argument list is empty, no owner class found");
|
||||
}
|
||||
RerouteArgument argument = sourceArguments.getFirst();
|
||||
sourceOwner = argument.sourceType();
|
||||
sourceArguments.remove(argument);
|
||||
}
|
||||
@ -135,23 +154,12 @@ public class RerouteBuilder {
|
||||
methodName = method.getName();
|
||||
}
|
||||
|
||||
String methodKey = sourceOwner.getInternalName()
|
||||
+ " "
|
||||
+ sourceDesc.getDescriptor()
|
||||
+ " "
|
||||
+ methodName;
|
||||
String methodKey = sourceDesc.getDescriptor() + methodName;
|
||||
|
||||
Type targetType = Type.getType(method);
|
||||
|
||||
boolean inBukkit = !method.isAnnotationPresent(NotInBukkit.class) && !method.getDeclaringClass().isAnnotationPresent(NotInBukkit.class);
|
||||
|
||||
String requiredCompatibility = null;
|
||||
if (method.isAnnotationPresent(RequireCompatibility.class)) {
|
||||
requiredCompatibility = method.getAnnotation(RequireCompatibility.class).value();
|
||||
} else if (method.getDeclaringClass().isAnnotationPresent(RequireCompatibility.class)) {
|
||||
requiredCompatibility = method.getDeclaringClass().getAnnotation(RequireCompatibility.class).value();
|
||||
}
|
||||
|
||||
RequirePluginVersionData requiredPluginVersion = null;
|
||||
if (method.isAnnotationPresent(RequirePluginVersion.class)) {
|
||||
requiredPluginVersion = RequirePluginVersionData.create(method.getAnnotation(RequirePluginVersion.class));
|
||||
@ -159,6 +167,47 @@ public class RerouteBuilder {
|
||||
requiredPluginVersion = RequirePluginVersionData.create(method.getDeclaringClass().getAnnotation(RequirePluginVersion.class));
|
||||
}
|
||||
|
||||
return new RerouteMethodData(methodKey, sourceDesc, sourceOwner, methodName, rerouteStatic != null, targetType, Type.getInternalName(method.getDeclaringClass()), method.getName(), arguments, rerouteReturn, inBukkit, requiredCompatibility, requiredPluginVersion);
|
||||
return new RerouteMethodData(methodKey, sourceDesc, sourceOwner, methodName, rerouteStatic != null, targetType, Type.getInternalName(method.getDeclaringClass()), method.getName(), arguments, rerouteReturn, inBukkit, requiredPluginVersion);
|
||||
}
|
||||
|
||||
private static boolean isMethodValid(Method method) {
|
||||
if (method.isBridge()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (method.isSynthetic()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Modifier.isPublic(method.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Modifier.isStatic(method.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (method.isAnnotationPresent(DoNotReroute.class)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String getRequireCompatibility(AnnotatedElement element) {
|
||||
RequireCompatibility annotation = element.getAnnotation(RequireCompatibility.class);
|
||||
if (annotation == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return annotation.value();
|
||||
}
|
||||
|
||||
private static boolean shouldInclude(String string, boolean parent, Predicate<String> compatibilityPresent) {
|
||||
if (string == null) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
return compatibilityPresent.test(string);
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ import java.util.List;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
public record RerouteMethodData(String source, Type sourceDesc, Type sourceOwner, String sourceName,
|
||||
public record RerouteMethodData(String methodKey, Type sourceDesc, Type sourceOwner, String sourceName,
|
||||
boolean staticReroute, Type targetType, String targetOwner, String targetName,
|
||||
List<RerouteArgument> arguments, RerouteReturn rerouteReturn, boolean isInBukkit,
|
||||
@Nullable String requiredCompatibility, @Nullable RequirePluginVersionData requiredPluginVersion) {
|
||||
@Nullable RequirePluginVersionData requiredPluginVersion) {
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.bukkit.craftbukkit.util;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.io.ByteStreams;
|
||||
@ -16,6 +17,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarOutputStream;
|
||||
@ -28,6 +30,7 @@ import org.bukkit.craftbukkit.legacy.FieldRename;
|
||||
import org.bukkit.craftbukkit.legacy.MaterialRerouting;
|
||||
import org.bukkit.craftbukkit.legacy.MethodRerouting;
|
||||
import org.bukkit.craftbukkit.legacy.enums.EnumEvil;
|
||||
import org.bukkit.craftbukkit.legacy.reroute.Reroute;
|
||||
import org.bukkit.craftbukkit.legacy.reroute.RerouteArgument;
|
||||
import org.bukkit.craftbukkit.legacy.reroute.RerouteBuilder;
|
||||
import org.bukkit.craftbukkit.legacy.reroute.RerouteMethodData;
|
||||
@ -87,18 +90,38 @@ public class Commodore {
|
||||
"org/bukkit/block/banner/PatternType", "NOP"
|
||||
);
|
||||
|
||||
private static Map<String, RerouteMethodData> createReroutes(Class<?> clazz) {
|
||||
Map<String, RerouteMethodData> reroutes = RerouteBuilder.buildFromClass(clazz);
|
||||
REROUTES.add(reroutes);
|
||||
return reroutes;
|
||||
private final List<Reroute> reroutes = new ArrayList<>(); // only for testing
|
||||
private Reroute materialReroute;
|
||||
private Reroute reroute;
|
||||
|
||||
public Commodore() {
|
||||
}
|
||||
|
||||
public Commodore(Predicate<String> compatibilityPresent) {
|
||||
updateReroute(compatibilityPresent);
|
||||
}
|
||||
|
||||
public void updateReroute(Predicate<String> compatibilityPresent) {
|
||||
materialReroute = RerouteBuilder
|
||||
.create(compatibilityPresent)
|
||||
.forClass(MaterialRerouting.class)
|
||||
.build();
|
||||
reroute = RerouteBuilder
|
||||
.create(compatibilityPresent)
|
||||
.forClass(FieldRename.class)
|
||||
.forClass(MethodRerouting.class)
|
||||
.forClass(EnumEvil.class)
|
||||
.build();
|
||||
|
||||
reroutes.clear();
|
||||
reroutes.add(materialReroute);
|
||||
reroutes.add(reroute);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static final List<Map<String, RerouteMethodData>> REROUTES = new ArrayList<>(); // Only used for testing
|
||||
private static final Map<String, RerouteMethodData> FIELD_RENAME_METHOD_REROUTE = createReroutes(FieldRename.class);
|
||||
private static final Map<String, RerouteMethodData> MATERIAL_METHOD_REROUTE = createReroutes(MaterialRerouting.class);
|
||||
private static final Map<String, RerouteMethodData> METHOD_REROUTE = createReroutes(MethodRerouting.class);
|
||||
private static final Map<String, RerouteMethodData> ENUM_METHOD_REROUTE = createReroutes(EnumEvil.class);
|
||||
public List<Reroute> getReroutes() {
|
||||
return reroutes;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
OptionParser parser = new OptionParser();
|
||||
@ -110,6 +133,8 @@ public class Commodore {
|
||||
File input = options.valueOf(inputFlag);
|
||||
File output = options.valueOf(outputFlag);
|
||||
|
||||
Commodore commodore = new Commodore(Predicates.alwaysTrue());
|
||||
|
||||
if (input.isDirectory()) {
|
||||
if (!output.isDirectory()) {
|
||||
System.err.println("If input directory specified, output directory required too");
|
||||
@ -118,15 +143,15 @@ public class Commodore {
|
||||
|
||||
for (File in : input.listFiles()) {
|
||||
if (in.getName().endsWith(".jar")) {
|
||||
convert(in, new File(output, in.getName()));
|
||||
convert(in, new File(output, in.getName()), commodore);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
convert(input, output);
|
||||
convert(input, output, commodore);
|
||||
}
|
||||
}
|
||||
|
||||
private static void convert(File in, File out) {
|
||||
private static void convert(File in, File out, Commodore commodore) {
|
||||
System.out.println("Attempting to convert " + in + " to " + out);
|
||||
|
||||
try {
|
||||
@ -144,7 +169,7 @@ public class Commodore {
|
||||
byte[] b = ByteStreams.toByteArray(is);
|
||||
|
||||
if (entry.getName().endsWith(".class")) {
|
||||
b = convert(b, "dummy", ApiVersion.NONE, Collections.emptySet());
|
||||
b = commodore.convert(b, "dummy", ApiVersion.NONE, Collections.emptySet());
|
||||
entry = new JarEntry(entry.getName());
|
||||
}
|
||||
|
||||
@ -162,7 +187,7 @@ public class Commodore {
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] convert(byte[] b, final String pluginName, final ApiVersion pluginVersion, final Set<String> activeCompatibilities) {
|
||||
public byte[] convert(byte[] b, final String pluginName, final ApiVersion pluginVersion, final Set<String> activeCompatibilities) {
|
||||
final boolean modern = pluginVersion.isNewerThanOrSameAs(ApiVersion.FLATTENING);
|
||||
final boolean enumCompatibility = pluginVersion.isOlderThanOrSameAs(ApiVersion.getOrCreateVersion("1.20.6")) && activeCompatibilities.contains("enum-compatibility-mode");
|
||||
ClassReader cr = new ClassReader(b);
|
||||
@ -329,10 +354,7 @@ public class Commodore {
|
||||
}
|
||||
|
||||
private void handleMethod(MethodPrinter visitor, int opcode, String owner, String name, String desc, boolean itf, Type samMethodType, Type instantiatedMethodType) {
|
||||
if (checkReroute(visitor, FIELD_RENAME_METHOD_REROUTE, opcode, owner, name, desc, samMethodType, instantiatedMethodType)) {
|
||||
return;
|
||||
}
|
||||
if (checkReroute(visitor, METHOD_REROUTE, opcode, owner, name, desc, samMethodType, instantiatedMethodType)) {
|
||||
if (checkReroute(visitor, reroute, opcode, owner, name, desc, samMethodType, instantiatedMethodType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -353,10 +375,6 @@ public class Commodore {
|
||||
}
|
||||
}
|
||||
|
||||
if (checkReroute(visitor, ENUM_METHOD_REROUTE, opcode, owner, name, desc, samMethodType, instantiatedMethodType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// SPIGOT-4496
|
||||
if (owner.equals("org/bukkit/map/MapView") && name.equals("getId") && desc.equals("()S")) {
|
||||
// Should be same size on stack so just call other method
|
||||
@ -448,15 +466,15 @@ public class Commodore {
|
||||
}
|
||||
|
||||
// TODO 2024-05-21: Move this up, when material gets fully replaced with ItemType and BlockType
|
||||
if (owner.startsWith("org/bukkit") && checkReroute(visitor, MATERIAL_METHOD_REROUTE, opcode, owner, name, desc, samMethodType, instantiatedMethodType)) {
|
||||
if (owner.startsWith("org/bukkit") && checkReroute(visitor, materialReroute, opcode, owner, name, desc, samMethodType, instantiatedMethodType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visitor.visit(opcode, owner, name, desc, itf, samMethodType, instantiatedMethodType);
|
||||
}
|
||||
|
||||
private boolean checkReroute(MethodPrinter visitor, Map<String, RerouteMethodData> rerouteMethodDataMap, int opcode, String owner, String name, String desc, Type samMethodType, Type instantiatedMethodType) {
|
||||
return rerouteMethods(activeCompatibilities, pluginVersion, rerouteMethodDataMap, opcode == Opcodes.INVOKESTATIC || opcode == Opcodes.H_INVOKESTATIC, owner, name, desc, data -> {
|
||||
private boolean checkReroute(MethodPrinter visitor, Reroute reroute, int opcode, String owner, String name, String desc, Type samMethodType, Type instantiatedMethodType) {
|
||||
return rerouteMethods(pluginVersion, reroute, opcode == Opcodes.INVOKESTATIC || opcode == Opcodes.H_INVOKESTATIC, owner, name, desc, data -> {
|
||||
visitor.visit(Opcodes.INVOKESTATIC, className, buildMethodName(data), buildMethodDesc(data), isInterface, samMethodType, instantiatedMethodType);
|
||||
rerouteMethodData.add(data);
|
||||
});
|
||||
@ -599,69 +617,8 @@ public class Commodore {
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
This method looks (and probably is) overengineered, but it gives the most flexible when it comes to remapping normal methods to static one.
|
||||
The problem with normal owner and desc replacement is that child classes have them as an owner, instead there parents for there parents methods
|
||||
|
||||
For example, if we have following two interfaces org.bukkit.BlockData and org.bukkit.Orientable extents BlockData
|
||||
and BlockData has the method org.bukkit.Material getType which we want to reroute to the static method
|
||||
org.bukkit.Material org.bukkit.craftbukkit.legacy.EnumEvil#getType(org.bukkit.BlockData)
|
||||
|
||||
If we now call BlockData#getType we get as the owner org/bukkit/BlockData and as desc ()Lorg/bukkit/Material;
|
||||
Which we can nicely reroute by checking if the owner is BlockData and the name getType
|
||||
The problem, starts if we use Orientable#getType no we get as owner org/bukkit/Orientable and as desc ()Lorg/bukkit/Material;
|
||||
Now we can now longer safely say to which getType method we need to reroute (assume there are multiple getType methods from different classes,
|
||||
which are not related to BlockData), simple using the owner class will not work, since would reroute to
|
||||
EnumEvil#getType(org.bukkit.Orientable) which is not EnumEvil#getType(org.bukkit.BlockData) and will throw a method not found error
|
||||
at runtime.
|
||||
|
||||
Meaning we would need to add checks for each subclass, which would be pur insanity.
|
||||
|
||||
To solve this, we go through each super class and interfaces (and their super class and interfaces etc.) and try to get an owner
|
||||
which matches with one of our replacement methods. Based on how inheritance works in java, this method should be safe to use.
|
||||
|
||||
As a site note: This method could also be used for the other method reroute, e.g. legacy method rerouting, where only the replacement
|
||||
method needs to be written, and this method figures out the rest, which could reduce the size and complexity of the Commodore class.
|
||||
The question then becomes one about performance (since this is not the most performance way) and convenience.
|
||||
But since it is only applied for each class and method call once when they get first loaded, it should not be that bad.
|
||||
(Although some load time testing could be done)
|
||||
*/
|
||||
public static boolean rerouteMethods(Set<String> activeCompatibilities, ApiVersion pluginVersion, Map<String, RerouteMethodData> rerouteMethodDataMap, boolean staticCall, String owner, String name, String desc, Consumer<RerouteMethodData> consumer) {
|
||||
Type ownerType = Type.getObjectType(owner);
|
||||
Class<?> ownerClass;
|
||||
try {
|
||||
ownerClass = Class.forName(ownerType.getClassName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ClassTraverser it = new ClassTraverser(ownerClass);
|
||||
while (it.hasNext()) {
|
||||
Class<?> clazz = it.next();
|
||||
|
||||
String methodKey = Type.getInternalName(clazz) + " " + desc + " " + name;
|
||||
|
||||
RerouteMethodData data = rerouteMethodDataMap.get(methodKey);
|
||||
if (data == null) {
|
||||
if (staticCall) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data.requiredCompatibility() != null && !activeCompatibilities.contains(data.requiredCompatibility())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.requiredPluginVersion() != null && !data.requiredPluginVersion().test(pluginVersion)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
consumer.accept(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
public static boolean rerouteMethods(ApiVersion pluginVersion, Reroute reroute, boolean staticCall, String owner, String name, String desc, Consumer<RerouteMethodData> consumer) {
|
||||
return reroute.apply(pluginVersion, owner, name, desc, staticCall, consumer);
|
||||
}
|
||||
|
||||
private static List<String> getMethodSignatures(byte[] clazz) {
|
||||
|
@ -74,7 +74,9 @@ import org.bukkit.potion.PotionType;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public final class CraftMagicNumbers implements UnsafeValues {
|
||||
public static final UnsafeValues INSTANCE = new CraftMagicNumbers();
|
||||
public static final CraftMagicNumbers INSTANCE = new CraftMagicNumbers();
|
||||
|
||||
private final Commodore commodore = new Commodore();
|
||||
|
||||
private CraftMagicNumbers() {}
|
||||
|
||||
@ -165,6 +167,10 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
return CraftLegacy.toLegacyData(data);
|
||||
}
|
||||
|
||||
public Commodore getCommodore() {
|
||||
return this.commodore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Material toLegacy(Material material) {
|
||||
return CraftLegacy.toLegacy(material);
|
||||
@ -320,7 +326,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
@Override
|
||||
public byte[] processClass(PluginDescriptionFile pdf, String path, byte[] clazz) {
|
||||
try {
|
||||
clazz = Commodore.convert(clazz, pdf.getName(), ApiVersion.getOrCreateVersion(pdf.getAPIVersion()), ((CraftServer) Bukkit.getServer()).activeCompatibilities);
|
||||
clazz = commodore.convert(clazz, pdf.getName(), ApiVersion.getOrCreateVersion(pdf.getAPIVersion()), ((CraftServer) Bukkit.getServer()).activeCompatibilities);
|
||||
} catch (Exception ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Fatal error trying to convert " + pdf.getFullName() + ":" + path, ex);
|
||||
}
|
||||
|
@ -2,20 +2,19 @@ package org.bukkit.craftbukkit.legacy;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Predicates;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Stream;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.legacy.reroute.Reroute;
|
||||
import org.bukkit.craftbukkit.legacy.reroute.RerouteBuilder;
|
||||
import org.bukkit.craftbukkit.legacy.reroute.RerouteMethodData;
|
||||
import org.bukkit.craftbukkit.util.ApiVersion;
|
||||
import org.bukkit.craftbukkit.util.Commodore;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
@ -34,7 +33,7 @@ public class MaterialReroutingTest {
|
||||
|
||||
// Needs to be a bukkit class
|
||||
private static final URI BUKKIT_CLASSES;
|
||||
private static final Map<String, RerouteMethodData> MATERIAL_METHOD_REROUTE = RerouteBuilder.buildFromClass(MaterialRerouting.class);
|
||||
private static final Reroute MATERIAL_METHOD_REROUTE = RerouteBuilder.create(Predicates.alwaysTrue()).forClass(MaterialRerouting.class).build();
|
||||
|
||||
static {
|
||||
try {
|
||||
@ -95,7 +94,7 @@ public class MaterialReroutingTest {
|
||||
}
|
||||
}
|
||||
|
||||
if (!Commodore.rerouteMethods(Collections.emptySet(), ApiVersion.CURRENT, MATERIAL_METHOD_REROUTE, (methodNode.access & Opcodes.ACC_STATIC) != 0, classNode.name, methodNode.name, methodNode.desc, a -> { })) {
|
||||
if (!Commodore.rerouteMethods(ApiVersion.CURRENT, MATERIAL_METHOD_REROUTE, (methodNode.access & Opcodes.ACC_STATIC) != 0, classNode.name, methodNode.name, methodNode.desc, a -> { })) {
|
||||
missingReroute.add(methodNode.name + " " + methodNode.desc + " " + methodNode.signature);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,76 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
public abstract class AbstractRerouteTest {
|
||||
|
||||
void test(Class<?> testClass, Map<String, RerouteMethodData> dataMap) {
|
||||
test(testClass, Predicates.alwaysTrue(), dataMap);
|
||||
}
|
||||
|
||||
void test(Class<?> testClass, Predicate<String> predicate, Map<String, RerouteMethodData> dataMap) {
|
||||
test(testClass, Predicates.and(predicate), dataMap.entrySet().stream().map(entry -> new TestDataHolder(entry.getKey(), List.of(entry.getValue()))).toList());
|
||||
}
|
||||
|
||||
void test(Class<?> testClass, Predicate<String> predicate, List<TestDataHolder> dataList) {
|
||||
Reroute reroute = RerouteBuilder
|
||||
.create(predicate)
|
||||
.forClass(testClass)
|
||||
.build();
|
||||
|
||||
assertEquals(dataList.size(), reroute.rerouteDataMap.size(), String.format("First layer reroute data amount are not the same. Expected: %s, Actual: %s", dataList, reroute.rerouteDataMap));
|
||||
|
||||
for (TestDataHolder testHolder : dataList) {
|
||||
Reroute.RerouteDataHolder holder = reroute.rerouteDataMap.get(testHolder.methodKey());
|
||||
assertEquals(testHolder.rerouteMethodDataList().size(), holder.rerouteMethodDataMap.size(), String.format("Second layer reroute data amount are not the same. Expected: %s, Actual: %s", testHolder.rerouteMethodDataList, holder.rerouteMethodDataMap));
|
||||
|
||||
for (RerouteMethodData testData : testHolder.rerouteMethodDataList()) {
|
||||
RerouteMethodData actual = holder.rerouteMethodDataMap.get(testData.sourceOwner().getInternalName());
|
||||
assertNotNull(actual, String.format("No reroute method data found for %s", testData));
|
||||
|
||||
check(actual, testData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RerouteArgument create(String type, String sourceType, boolean injectPluginName, boolean injectPluginVersion, String injectCompatibility) {
|
||||
return new RerouteArgument(Type.getType(type), Type.getType(sourceType), injectPluginName, injectPluginVersion, injectCompatibility);
|
||||
}
|
||||
|
||||
List<RerouteArgument> create(RerouteArgument... arguments) {
|
||||
return Arrays.asList(arguments);
|
||||
}
|
||||
|
||||
RerouteMethodData create(String methodKey, String sourceDesc, String sourceOwner, String sourceName,
|
||||
boolean staticReroute, String targetType, String targetOwner, String targetName,
|
||||
List<RerouteArgument> arguments, String rerouteReturn, boolean isInBukkit,
|
||||
RequirePluginVersionData requiredPluginVersion) {
|
||||
return new RerouteMethodData(methodKey, Type.getType(sourceDesc), Type.getObjectType(sourceOwner), sourceName,
|
||||
staticReroute, Type.getType(targetType), targetOwner, targetName, arguments, new RerouteReturn(Type.getType(rerouteReturn)), isInBukkit, requiredPluginVersion);
|
||||
}
|
||||
|
||||
private void check(RerouteMethodData actual, RerouteMethodData expected) {
|
||||
assertEquals(expected.methodKey(), actual.methodKey(), "Method key are not the same");
|
||||
assertEquals(expected.sourceDesc(), actual.sourceDesc(), "Source desc are not the same");
|
||||
assertEquals(expected.sourceOwner(), actual.sourceOwner(), "Source owner are not the same");
|
||||
assertEquals(expected.sourceName(), actual.sourceName(), "Source name are not the same");
|
||||
assertEquals(expected.staticReroute(), actual.staticReroute(), "Static reroute flag are not the same");
|
||||
assertEquals(expected.targetType(), actual.targetType(), "Target type are not the same");
|
||||
assertEquals(expected.targetOwner(), actual.targetOwner(), "Target owner are not the same");
|
||||
assertEquals(expected.targetName(), actual.targetName(), "Target name are not the same");
|
||||
assertEquals(expected.arguments().size(), actual.arguments().size(), "Arguments count are not the same");
|
||||
assertEquals(expected.arguments(), actual.arguments(), "Arguments are not the same");
|
||||
assertEquals(expected.rerouteReturn(), actual.rerouteReturn(), "Reroute return flag are not the same");
|
||||
assertEquals(expected.isInBukkit(), actual.isInBukkit(), "In Bukkit flag are not the same");
|
||||
assertEquals(expected.requiredPluginVersion(), actual.requiredPluginVersion(), "Required plugin version are not the same");
|
||||
}
|
||||
|
||||
public record TestDataHolder(String methodKey, List<RerouteMethodData> rerouteMethodDataList) {
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Normal
|
||||
public class DoNotRerouteTest extends AbstractRerouteTest {
|
||||
|
||||
@Test
|
||||
public void testDoNotReroute() {
|
||||
test(DoNotRerouteTestData.class, Map.of());
|
||||
}
|
||||
|
||||
public static class DoNotRerouteTestData {
|
||||
|
||||
@DoNotReroute
|
||||
public static List<String> getList(Object o) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import com.google.common.base.Predicates;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Normal
|
||||
public class InjectCompatibilityTest extends AbstractRerouteTest {
|
||||
|
||||
@Test
|
||||
public void testInjectCompatibility() {
|
||||
test(InjectCompatibilityTestData.class, Map.of(
|
||||
"()Ljava/util/List;getList", create(
|
||||
"()Ljava/util/List;getList",
|
||||
"()Ljava/util/List;",
|
||||
"java/lang/Object",
|
||||
"getList",
|
||||
false,
|
||||
"(Ljava/lang/Object;Z)Ljava/util/List;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/InjectCompatibilityTest$InjectCompatibilityTestData",
|
||||
"getList",
|
||||
create(
|
||||
create("Ljava/lang/Object;", "Ljava/lang/Object;", false, false, null),
|
||||
create("Z", "Z", false, false, "test-value")
|
||||
),
|
||||
"Ljava/util/List;",
|
||||
true,
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInjectCompatibilityIncorrectType() {
|
||||
assertThrows(RuntimeException.class, () -> RerouteBuilder.create(Predicates.alwaysTrue()).forClass(InjectCompatibilityIncorrectTypeTestData.class).build());
|
||||
}
|
||||
|
||||
public static class InjectCompatibilityTestData {
|
||||
|
||||
public static List<String> getList(Object o, @InjectCompatibility("test-value") boolean value) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class InjectCompatibilityIncorrectTypeTestData {
|
||||
|
||||
public static List<String> getList(Object o, @InjectCompatibility("test-value") String value) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import com.google.common.base.Predicates;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Normal
|
||||
public class InjectPluginNameTest extends AbstractRerouteTest {
|
||||
|
||||
@Test
|
||||
public void testInjectPluginName() {
|
||||
test(InjectPluginNameTestData.class, Map.of(
|
||||
"()Ljava/util/List;getList", create(
|
||||
"()Ljava/util/List;getList",
|
||||
"()Ljava/util/List;",
|
||||
"java/lang/Object",
|
||||
"getList",
|
||||
false,
|
||||
"(Ljava/lang/Object;Ljava/lang/String;)Ljava/util/List;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/InjectPluginNameTest$InjectPluginNameTestData",
|
||||
"getList",
|
||||
create(
|
||||
create("Ljava/lang/Object;", "Ljava/lang/Object;", false, false, null),
|
||||
create("Ljava/lang/String;", "Ljava/lang/String;", true, false, null)
|
||||
),
|
||||
"Ljava/util/List;",
|
||||
true,
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInjectPluginNameIncorrectType() {
|
||||
assertThrows(RuntimeException.class, () -> RerouteBuilder.create(Predicates.alwaysTrue()).forClass(InjectPluginNameIncorrectTypeTestData.class).build());
|
||||
}
|
||||
|
||||
public static class InjectPluginNameTestData {
|
||||
|
||||
public static List<String> getList(Object o, @InjectPluginName String value) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class InjectPluginNameIncorrectTypeTestData {
|
||||
|
||||
public static List<String> getList(Object o, @InjectPluginName Object value) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import com.google.common.base.Predicates;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.bukkit.craftbukkit.util.ApiVersion;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Normal
|
||||
public class InjectPluginVersionTest extends AbstractRerouteTest {
|
||||
|
||||
@Test
|
||||
public void testInjectPluginVersion() {
|
||||
test(InjectPluginVersionTestData.class, Map.of(
|
||||
"()Ljava/util/List;getList", create(
|
||||
"()Ljava/util/List;getList",
|
||||
"()Ljava/util/List;",
|
||||
"java/lang/Object",
|
||||
"getList",
|
||||
false,
|
||||
"(Ljava/lang/Object;Lorg/bukkit/craftbukkit/util/ApiVersion;)Ljava/util/List;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/InjectPluginVersionTest$InjectPluginVersionTestData",
|
||||
"getList",
|
||||
create(
|
||||
create("Ljava/lang/Object;", "Ljava/lang/Object;", false, false, null),
|
||||
create("Lorg/bukkit/craftbukkit/util/ApiVersion;", "Lorg/bukkit/craftbukkit/util/ApiVersion;", false, true, null)
|
||||
),
|
||||
"Ljava/util/List;",
|
||||
true,
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInjectPluginVersionIncorrectType() {
|
||||
assertThrows(RuntimeException.class, () -> RerouteBuilder.create(Predicates.alwaysTrue()).forClass(InjectPluginVersionIncorrectTypeTestData.class).build());
|
||||
}
|
||||
|
||||
public static class InjectPluginVersionTestData {
|
||||
|
||||
public static List<String> getList(Object o, @InjectPluginVersion ApiVersion value) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class InjectPluginVersionIncorrectTypeTestData {
|
||||
|
||||
public static List<String> getList(Object o, @InjectPluginVersion String value) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Normal
|
||||
public class NotInBukkitTest extends AbstractRerouteTest {
|
||||
|
||||
@Test
|
||||
public void testNotInBukkit() {
|
||||
test(NotInBukkitTestData.class, Map.of(
|
||||
"()Ljava/util/List;getList", create(
|
||||
"()Ljava/util/List;getList",
|
||||
"()Ljava/util/List;",
|
||||
"java/lang/Object",
|
||||
"getList",
|
||||
false,
|
||||
"(Ljava/lang/Object;)Ljava/util/List;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/NotInBukkitTest$NotInBukkitTestData",
|
||||
"getList",
|
||||
create(
|
||||
create("Ljava/lang/Object;", "Ljava/lang/Object;", false, false, null)
|
||||
),
|
||||
"Ljava/util/List;",
|
||||
false,
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static class NotInBukkitTestData {
|
||||
|
||||
@NotInBukkit
|
||||
public static List<String> getList(Object o) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Normal
|
||||
public class RequireCompatibilityTest extends AbstractRerouteTest {
|
||||
|
||||
@Test
|
||||
public void testRequireCompatibility() {
|
||||
test(RequireCompatibilityTestData.class, Map.of(
|
||||
"()Ljava/util/List;getList", create(
|
||||
"()Ljava/util/List;getList",
|
||||
"()Ljava/util/List;",
|
||||
"java/lang/Object",
|
||||
"getList",
|
||||
false,
|
||||
"(Ljava/lang/Object;)Ljava/util/List;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/RequireCompatibilityTest$RequireCompatibilityTestData",
|
||||
"getList",
|
||||
create(
|
||||
create("Ljava/lang/Object;", "Ljava/lang/Object;", false, false, null)
|
||||
),
|
||||
"Ljava/util/List;",
|
||||
true,
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequireCompatibilityNotPresent() {
|
||||
test(RequireCompatibilityTestData.class, Predicates.alwaysFalse(), Map.of());
|
||||
}
|
||||
|
||||
public static class RequireCompatibilityTestData {
|
||||
|
||||
@RequireCompatibility("test-value")
|
||||
public static List<String> getList(Object o) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import java.lang.annotation.Annotation;
|
||||
import org.bukkit.craftbukkit.util.ApiVersion;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Normal
|
||||
public class RequirePluginVersionDataTest {
|
||||
|
||||
@Test
|
||||
public void testSame() {
|
||||
RequirePluginVersionData data = RequirePluginVersionData.create(new RequirePluginVersionImpl("", "1.21", "1.21"));
|
||||
|
||||
assertEquals(ApiVersion.getOrCreateVersion("1.21"), data.minInclusive());
|
||||
assertEquals(ApiVersion.getOrCreateVersion("1.21"), data.maxInclusive());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferent() {
|
||||
RequirePluginVersionData data = RequirePluginVersionData.create(new RequirePluginVersionImpl("", "1.21", "1.23"));
|
||||
|
||||
assertEquals(ApiVersion.getOrCreateVersion("1.21"), data.minInclusive());
|
||||
assertEquals(ApiVersion.getOrCreateVersion("1.23"), data.maxInclusive());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValue() {
|
||||
RequirePluginVersionData data = RequirePluginVersionData.create(new RequirePluginVersionImpl("1.42", "", ""));
|
||||
|
||||
assertEquals(ApiVersion.getOrCreateVersion("1.42"), data.minInclusive());
|
||||
assertEquals(ApiVersion.getOrCreateVersion("1.42"), data.maxInclusive());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValueAndMin() {
|
||||
assertThrows(IllegalArgumentException.class, () -> RequirePluginVersionData.create(new RequirePluginVersionImpl("1.42", "1.52", "")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValueAndMax() {
|
||||
assertThrows(IllegalArgumentException.class, () -> RequirePluginVersionData.create(new RequirePluginVersionImpl("1.42", "", "1.53")));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testValueAndMinMax() {
|
||||
assertThrows(IllegalArgumentException.class, () -> RequirePluginVersionData.create(new RequirePluginVersionImpl("1.42", "1.51", "1.53")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinNewerThanMax() {
|
||||
assertThrows(IllegalArgumentException.class, () -> RequirePluginVersionData.create(new RequirePluginVersionImpl("", "1.59", "1.57")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnlyMin() {
|
||||
RequirePluginVersionData data = RequirePluginVersionData.create(new RequirePluginVersionImpl("", "1.44", ""));
|
||||
|
||||
assertEquals(ApiVersion.getOrCreateVersion("1.44"), data.minInclusive());
|
||||
assertNull(data.maxInclusive());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testOnlyMax() {
|
||||
RequirePluginVersionData data = RequirePluginVersionData.create(new RequirePluginVersionImpl("", "", "1.96"));
|
||||
|
||||
assertNull(data.minInclusive());
|
||||
assertEquals(ApiVersion.getOrCreateVersion("1.96"), data.maxInclusive());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExactData() {
|
||||
RequirePluginVersionData data = new RequirePluginVersionData(ApiVersion.getOrCreateVersion("1.12"), ApiVersion.getOrCreateVersion("1.12"));
|
||||
|
||||
assertTrue(data.test(ApiVersion.getOrCreateVersion("1.12")));
|
||||
assertFalse(data.test(ApiVersion.getOrCreateVersion("1.11")));
|
||||
assertFalse(data.test(ApiVersion.getOrCreateVersion("1.13")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeData() {
|
||||
RequirePluginVersionData data = new RequirePluginVersionData(ApiVersion.getOrCreateVersion("1.12"), ApiVersion.getOrCreateVersion("1.13"));
|
||||
|
||||
assertTrue(data.test(ApiVersion.getOrCreateVersion("1.12")));
|
||||
assertTrue(data.test(ApiVersion.getOrCreateVersion("1.12.5")));
|
||||
assertTrue(data.test(ApiVersion.getOrCreateVersion("1.13")));
|
||||
|
||||
assertFalse(data.test(ApiVersion.getOrCreateVersion("1.11")));
|
||||
assertFalse(data.test(ApiVersion.getOrCreateVersion("1.14")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOlderOpenRangeData() {
|
||||
RequirePluginVersionData data = new RequirePluginVersionData(null, ApiVersion.getOrCreateVersion("1.13"));
|
||||
|
||||
assertTrue(data.test(ApiVersion.getOrCreateVersion("1.1")));
|
||||
assertTrue(data.test(ApiVersion.getOrCreateVersion("1.13")));
|
||||
|
||||
assertFalse(data.test(ApiVersion.getOrCreateVersion("1.14")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewerOpenRangeData() {
|
||||
RequirePluginVersionData data = new RequirePluginVersionData(ApiVersion.getOrCreateVersion("1.12"), null);
|
||||
|
||||
assertTrue(data.test(ApiVersion.getOrCreateVersion("1.12")));
|
||||
assertTrue(data.test(ApiVersion.getOrCreateVersion("1.14")));
|
||||
|
||||
assertFalse(data.test(ApiVersion.getOrCreateVersion("1.11")));
|
||||
}
|
||||
|
||||
private record RequirePluginVersionImpl(String value, String minInclusive, String maxInclusive) implements RequirePluginVersion {
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.bukkit.craftbukkit.util.ApiVersion;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Normal
|
||||
public class RequirePluginVersionTest extends AbstractRerouteTest {
|
||||
|
||||
@Test
|
||||
public void testRequirePluginVersion() {
|
||||
test(RequirePluginVersionTestData.class, Map.of(
|
||||
"()Ljava/util/List;getList", create(
|
||||
"()Ljava/util/List;getList",
|
||||
"()Ljava/util/List;",
|
||||
"java/lang/Object",
|
||||
"getList",
|
||||
false,
|
||||
"(Ljava/lang/Object;)Ljava/util/List;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/RequirePluginVersionTest$RequirePluginVersionTestData",
|
||||
"getList",
|
||||
create(
|
||||
create("Ljava/lang/Object;", "Ljava/lang/Object;", false, false, null)
|
||||
),
|
||||
"Ljava/util/List;",
|
||||
true,
|
||||
new RequirePluginVersionData(ApiVersion.getOrCreateVersion("1.42"), ApiVersion.getOrCreateVersion("1.42"))
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static class RequirePluginVersionTestData {
|
||||
|
||||
@RequirePluginVersion("1.42")
|
||||
public static List<String> getList(Object o) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Normal
|
||||
public class RerouteArgumentTypeTest extends AbstractRerouteTest {
|
||||
|
||||
@Test
|
||||
public void testRerouteArgumentType() {
|
||||
test(RerouteArgumentTypeTestData.class, Map.of(
|
||||
"()Ljava/util/List;getList", create(
|
||||
"()Ljava/util/List;getList",
|
||||
"()Ljava/util/List;",
|
||||
"java/util/Map",
|
||||
"getList",
|
||||
false,
|
||||
"(Ljava/lang/Object;)Ljava/util/List;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/RerouteArgumentTypeTest$RerouteArgumentTypeTestData",
|
||||
"getList",
|
||||
create(
|
||||
create("Ljava/lang/Object;", "Ljava/util/Map;", false, false, null)
|
||||
),
|
||||
"Ljava/util/List;",
|
||||
true,
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRerouteArgumentTypeSecond() {
|
||||
test(RerouteArgumentTypeSecondTestData.class, Map.of(
|
||||
"(Ljava/lang/String;)Ljava/util/List;getList", create(
|
||||
"(Ljava/lang/String;)Ljava/util/List;getList",
|
||||
"(Ljava/lang/String;)Ljava/util/List;",
|
||||
"java/lang/Object",
|
||||
"getList",
|
||||
false,
|
||||
"(Ljava/lang/Object;Ljava/util/Map;)Ljava/util/List;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/RerouteArgumentTypeTest$RerouteArgumentTypeSecondTestData",
|
||||
"getList",
|
||||
create(
|
||||
create("Ljava/lang/Object;", "Ljava/lang/Object;", false, false, null),
|
||||
create("Ljava/util/Map;", "Ljava/lang/String;", false, false, null)
|
||||
),
|
||||
"Ljava/util/List;",
|
||||
true,
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static class RerouteArgumentTypeTestData {
|
||||
|
||||
public static List<String> getList(@RerouteArgumentType("java/util/Map") Object o) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class RerouteArgumentTypeSecondTestData {
|
||||
|
||||
public static List<String> getList(Object o, @RerouteArgumentType("java/lang/String") Map<String, Object> map) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,221 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import com.google.common.base.Predicates;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Normal
|
||||
public class RerouteBuilderTest extends AbstractRerouteTest {
|
||||
|
||||
@Test
|
||||
public void testReroute() {
|
||||
test(FirstTest.class, Map.of(
|
||||
"()VtestReroute", create(
|
||||
"()VtestReroute",
|
||||
"()V",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/RerouteBuilderTest",
|
||||
"testReroute",
|
||||
false,
|
||||
"(Lorg/bukkit/craftbukkit/legacy/reroute/RerouteBuilderTest;)V",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/RerouteBuilderTest$FirstTest",
|
||||
"testReroute",
|
||||
create(
|
||||
create("Lorg/bukkit/craftbukkit/legacy/reroute/RerouteBuilderTest;", "Lorg/bukkit/craftbukkit/legacy/reroute/RerouteBuilderTest;", false, false, null)
|
||||
),
|
||||
"V",
|
||||
true,
|
||||
null
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidMethods() {
|
||||
test(InvalidMethodTest.class, Map.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleMethods() {
|
||||
test(MultipleMethodTest.class, Map.of(
|
||||
"()Ljava/util/List;getList", create(
|
||||
"()Ljava/util/List;getList",
|
||||
"()Ljava/util/List;",
|
||||
"java/lang/Object",
|
||||
"getList",
|
||||
false,
|
||||
"(Ljava/lang/Object;)Ljava/util/List;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/RerouteBuilderTest$MultipleMethodTest",
|
||||
"getList",
|
||||
create(
|
||||
create("Ljava/lang/Object;", "Ljava/lang/Object;", false, false, null)
|
||||
),
|
||||
"Ljava/util/List;",
|
||||
true,
|
||||
null
|
||||
),
|
||||
"(Ljava/util/Map;)Ljava/util/Map;getMap", create(
|
||||
"(Ljava/util/Map;)Ljava/util/Map;getMap",
|
||||
"(Ljava/util/Map;)Ljava/util/Map;",
|
||||
"java/lang/String",
|
||||
"getMap",
|
||||
false,
|
||||
"(Ljava/lang/String;Ljava/util/Map;)Ljava/util/Map;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/RerouteBuilderTest$MultipleMethodTest",
|
||||
"getMap",
|
||||
create(
|
||||
create("Ljava/lang/String;", "Ljava/lang/String;", false, false, null),
|
||||
create("Ljava/util/Map;", "Ljava/util/Map;", false, false, null)
|
||||
),
|
||||
"Ljava/util/Map;",
|
||||
true,
|
||||
null
|
||||
),
|
||||
"(ZS)IgetInt", create(
|
||||
"(ZS)IgetInt",
|
||||
"(ZS)I",
|
||||
"java/util/logging/Logger",
|
||||
"getInt",
|
||||
false,
|
||||
"(Ljava/util/logging/Logger;ZS)I",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/RerouteBuilderTest$MultipleMethodTest",
|
||||
"getInt",
|
||||
create(
|
||||
create("Ljava/util/logging/Logger;", "Ljava/util/logging/Logger;", false, false, null),
|
||||
create("Z", "Z", false, false, null),
|
||||
create("S", "S", false, false, null)
|
||||
),
|
||||
"I",
|
||||
true,
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInterfaceRerouteClass() {
|
||||
assertThrows(IllegalArgumentException.class, () -> RerouteBuilder.create(Predicates.alwaysTrue()).forClass(InterfaceTest.class).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnnotationRerouteClass() {
|
||||
assertThrows(IllegalArgumentException.class, () -> RerouteBuilder.create(Predicates.alwaysTrue()).forClass(AnnotationTest.class).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingOwner() {
|
||||
assertThrows(RuntimeException.class, () -> RerouteBuilder.create(Predicates.alwaysTrue()).forClass(MissingOwnerTest.class).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSameKey() {
|
||||
test(SameKeyTest.class, Predicates.alwaysTrue(), List.of(
|
||||
new TestDataHolder("()Ljava/util/List;getList", List.of(create(
|
||||
"()Ljava/util/List;getList",
|
||||
"()Ljava/util/List;",
|
||||
"java/lang/Object",
|
||||
"getList",
|
||||
false,
|
||||
"(Ljava/lang/Object;)Ljava/util/List;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/RerouteBuilderTest$SameKeyTest",
|
||||
"getList",
|
||||
create(
|
||||
create("Ljava/lang/Object;", "Ljava/lang/Object;", false, false, null)
|
||||
),
|
||||
"Ljava/util/List;",
|
||||
true,
|
||||
null
|
||||
),
|
||||
create(
|
||||
"()Ljava/util/List;getList",
|
||||
"()Ljava/util/List;",
|
||||
"java/lang/String",
|
||||
"getList",
|
||||
false,
|
||||
"(Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/RerouteBuilderTest$SameKeyTest",
|
||||
"getList",
|
||||
create(
|
||||
create("Ljava/lang/String;", "Ljava/lang/String;", false, false, null),
|
||||
create("Ljava/lang/String;", "Ljava/lang/String;", true, false, null)
|
||||
),
|
||||
"Ljava/util/List;",
|
||||
true,
|
||||
null
|
||||
)
|
||||
))
|
||||
));
|
||||
}
|
||||
|
||||
public static class FirstTest {
|
||||
|
||||
public static void testReroute(RerouteBuilderTest rerouteBuilderTest) {
|
||||
}
|
||||
}
|
||||
|
||||
public static class InvalidMethodTest {
|
||||
|
||||
public void testReroute(RerouteBuilderTest rerouteBuilderTest) {
|
||||
}
|
||||
|
||||
static void testReroute2(RerouteBuilderTest rerouteBuilderTest) {
|
||||
}
|
||||
|
||||
void testReroute3(RerouteBuilderTest rerouteBuilderTest) {
|
||||
}
|
||||
|
||||
private static void testReroute4(RerouteBuilderTest rerouteBuilderTest) {
|
||||
}
|
||||
|
||||
protected static void testReroute5(RerouteBuilderTest rerouteBuilderTest) {
|
||||
}
|
||||
}
|
||||
|
||||
public static class MultipleMethodTest {
|
||||
|
||||
public static List<String> getList(Object o) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Map<String, String> getMap(String value, Map<String, String> map) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int getInt(Logger logger, boolean bool, short s) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public interface InterfaceTest {
|
||||
|
||||
static List<String> getList(Object o) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public @interface AnnotationTest {
|
||||
|
||||
}
|
||||
|
||||
public static class MissingOwnerTest {
|
||||
|
||||
public static List<String> getList() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class SameKeyTest {
|
||||
|
||||
public static List<String> getList(Object o) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<String> getList(String s, @InjectPluginName String name) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Normal
|
||||
public class RerouteMethodNameTest extends AbstractRerouteTest {
|
||||
|
||||
@Test
|
||||
public void testRerouteMethodName() {
|
||||
test(RerouteMethodNameTestData.class, Map.of(
|
||||
"()Ljava/util/List;getMap", create(
|
||||
"()Ljava/util/List;getMap",
|
||||
"()Ljava/util/List;",
|
||||
"java/lang/Object",
|
||||
"getMap",
|
||||
false,
|
||||
"(Ljava/lang/Object;)Ljava/util/List;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/RerouteMethodNameTest$RerouteMethodNameTestData",
|
||||
"getList",
|
||||
create(
|
||||
create("Ljava/lang/Object;", "Ljava/lang/Object;", false, false, null)
|
||||
),
|
||||
"Ljava/util/List;",
|
||||
true,
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static class RerouteMethodNameTestData {
|
||||
|
||||
@RerouteMethodName("getMap")
|
||||
public static List<String> getList(Object o) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Normal
|
||||
public class RerouteReturnTypeTest extends AbstractRerouteTest {
|
||||
|
||||
@Test
|
||||
public void testRerouteReturnType() {
|
||||
test(RerouteReturnTypeTestData.class, Map.of(
|
||||
"()Ljava/util/Map;getList", create(
|
||||
"()Ljava/util/Map;getList",
|
||||
"()Ljava/util/Map;",
|
||||
"java/lang/Object",
|
||||
"getList",
|
||||
false,
|
||||
"(Ljava/lang/Object;)Ljava/util/List;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/RerouteReturnTypeTest$RerouteReturnTypeTestData",
|
||||
"getList",
|
||||
create(
|
||||
create("Ljava/lang/Object;", "Ljava/lang/Object;", false, false, null)
|
||||
),
|
||||
"Ljava/util/List;",
|
||||
true,
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static class RerouteReturnTypeTestData {
|
||||
|
||||
@RerouteReturnType("java/util/Map")
|
||||
public static List<String> getList(Object o) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Normal
|
||||
public class RerouteStaticTest extends AbstractRerouteTest {
|
||||
|
||||
@Test
|
||||
public void testStaticReroute() {
|
||||
test(RerouteStaticTestData.class, Map.of(
|
||||
"(Ljava/lang/Object;)Ljava/util/List;getList", create(
|
||||
"(Ljava/lang/Object;)Ljava/util/List;getList",
|
||||
"(Ljava/lang/Object;)Ljava/util/List;",
|
||||
"java/util/Map",
|
||||
"getList",
|
||||
true,
|
||||
"(Ljava/lang/Object;)Ljava/util/List;",
|
||||
"org/bukkit/craftbukkit/legacy/reroute/RerouteStaticTest$RerouteStaticTestData",
|
||||
"getList",
|
||||
create(
|
||||
create("Ljava/lang/Object;", "Ljava/lang/Object;", false, false, null)
|
||||
),
|
||||
"Ljava/util/List;",
|
||||
true,
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static class RerouteStaticTestData {
|
||||
|
||||
@RerouteStatic("java/util/Map")
|
||||
public static List<String> getList(Object o) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
package org.bukkit.craftbukkit.legacy;
|
||||
package org.bukkit.craftbukkit.legacy.reroute;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Predicates;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import org.bukkit.craftbukkit.legacy.reroute.RerouteMethodData;
|
||||
import org.bukkit.craftbukkit.util.Commodore;
|
||||
import org.bukkit.support.environment.Normal;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
@ -19,25 +19,28 @@ import org.objectweb.asm.Type;
|
||||
public class RerouteValidationTest {
|
||||
|
||||
public static Stream<Arguments> data() {
|
||||
return Commodore.REROUTES.stream().map(Arguments::of);
|
||||
Commodore commodore = new Commodore(Predicates.alwaysTrue());
|
||||
return commodore.getReroutes().stream().map(Arguments::of);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("data")
|
||||
public void testReroutes(Map<String, RerouteMethodData> reroutes) {
|
||||
public void testReroutes(Reroute reroute) {
|
||||
Map<String, String> wrongReroutes = new HashMap<>();
|
||||
String owner = null;
|
||||
|
||||
for (Map.Entry<String, RerouteMethodData> entry : reroutes.entrySet()) {
|
||||
owner = entry.getValue().targetOwner();
|
||||
if (!entry.getValue().isInBukkit()) {
|
||||
continue;
|
||||
}
|
||||
for (Map.Entry<String, Reroute.RerouteDataHolder> value : reroute.rerouteDataMap.entrySet()) {
|
||||
for (Map.Entry<String, RerouteMethodData> entry : value.getValue().rerouteMethodDataMap.entrySet()) {
|
||||
owner = entry.getValue().targetOwner();
|
||||
if (!entry.getValue().isInBukkit()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String error = isValid(entry.getKey(), entry.getValue());
|
||||
String error = isValid(entry.getKey(), entry.getValue());
|
||||
|
||||
if (error != null) {
|
||||
wrongReroutes.put(entry.getKey(), error);
|
||||
if (error != null) {
|
||||
wrongReroutes.put(entry.getKey(), error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user