mirror of
https://github.com/IntellectualSites/PlotSquared.git
synced 2025-10-24 23:23:44 +02:00
chore: improve readability of method retrieval
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package com.plotsquared.bukkit.schematic;
|
||||
|
||||
import com.plotsquared.core.util.ReflectionHelper;
|
||||
import com.plotsquared.core.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
@@ -236,13 +237,11 @@ final class StateWrapperSpigot implements StateWrapper {
|
||||
|
||||
private static MethodHandle findCraftBlockEntityStateUpdateMethodHandle(Class<?> craftBlockEntityStateClass) throws
|
||||
NoSuchMethodException, IllegalAccessException {
|
||||
for (final Method method : craftBlockEntityStateClass.getMethods()) {
|
||||
if (method.getReturnType().equals(Boolean.TYPE) && method.getParameterCount() == 2 &&
|
||||
method.getParameterTypes()[0] == Boolean.TYPE && method.getParameterTypes()[1] == Boolean.TYPE) {
|
||||
return LOOKUP.unreflect(method);
|
||||
}
|
||||
}
|
||||
throw new NoSuchMethodException("Couldn't find method for #update(boolean, boolean) in " + craftBlockEntityStateClass.getName());
|
||||
return LOOKUP.unreflect(ReflectionHelper.findMethod(
|
||||
craftBlockEntityStateClass,
|
||||
MethodType.methodType(Boolean.TYPE, Boolean.TYPE, Boolean.TYPE),
|
||||
Modifier.PUBLIC
|
||||
).orElseThrow(() -> new NoSuchMethodException("Couldn't lookup CraftBlockEntityState#update(boolean, boolean) boolean")));
|
||||
}
|
||||
|
||||
private static MethodHandle findCraftBlockEntityStateSnapshotMethodHandle(Class<?> craftBlockEntityStateClass) throws
|
||||
@@ -254,13 +253,11 @@ final class StateWrapperSpigot implements StateWrapper {
|
||||
|
||||
private static MethodHandle findSignBlockEntitySetTextMethodHandle(Class<?> signBlockEntity, Class<?> signText) throws
|
||||
NoSuchMethodException, IllegalAccessException {
|
||||
for (final Method method : signBlockEntity.getMethods()) {
|
||||
if (method.getReturnType() == Boolean.TYPE && method.getParameterCount() == 2
|
||||
&& method.getParameterTypes()[0] == signText && method.getParameterTypes()[1] == Boolean.TYPE) {
|
||||
return LOOKUP.unreflect(method);
|
||||
}
|
||||
}
|
||||
throw new NoSuchMethodException("Couldn't lookup SignBlockEntity#setText(SignText, boolean) boolean");
|
||||
return LOOKUP.unreflect(ReflectionHelper.findMethod(
|
||||
signBlockEntity,
|
||||
MethodType.methodType(Boolean.TYPE, signText, Boolean.TYPE),
|
||||
Modifier.PUBLIC
|
||||
).orElseThrow(() -> new NoSuchMethodException("Couldn't lookup SignBlockEntity#setText(SignText, boolean) boolean")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* PlotSquared, a land and world management plugin for Minecraft.
|
||||
* Copyright (C) IntellectualSites <https://intellectualsites.com>
|
||||
* Copyright (C) IntellectualSites team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.plotsquared.core.util;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public final class ReflectionHelper {
|
||||
|
||||
/**
|
||||
* Find a (declared) method with an unknown or potentially obfuscated name by its signature and optional modifiers.
|
||||
* <br>
|
||||
* The method - if private - is not made accessible. Either call {@link Method#setAccessible(boolean)} or
|
||||
* use a {@link java.lang.invoke.MethodHandles.Lookup#privateLookupIn(Class, MethodHandles.Lookup) private lookup}.
|
||||
*
|
||||
* @param holder The class providing the method.
|
||||
* @param signature The signature of the method, identified by parameter types and the return type.
|
||||
* @param modifiers All possible modifiers of the method that should be validated.
|
||||
* @return The method, if one has been found. Otherwise, an empty Optional.
|
||||
* @throws RuntimeException if multiple matching methods have been found.
|
||||
* @see java.lang.reflect.Modifier
|
||||
*/
|
||||
public static Optional<Method> findMethod(Class<?> holder, MethodType signature, int... modifiers) {
|
||||
Method found = null;
|
||||
outer:
|
||||
for (final Method method : holder.getDeclaredMethods()) {
|
||||
if (method.getParameterCount() != signature.parameterCount()) {
|
||||
continue;
|
||||
}
|
||||
if (!signature.returnType().isAssignableFrom(method.getReturnType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (final int modifier : modifiers) {
|
||||
if ((method.getModifiers() & modifier) == 0) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
|
||||
Class<?>[] parameterTypes = signature.parameterArray();
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
// validate expected parameter is either the same type or subtype of actual parameter
|
||||
if (!parameterTypes[i].isAssignableFrom(method.getParameterTypes()[i])) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
if (found != null) {
|
||||
throw new RuntimeException("Found ambiguous method by selector: " + method + " vs " + found);
|
||||
}
|
||||
found = method;
|
||||
}
|
||||
return Optional.ofNullable(found);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* PlotSquared, a land and world management plugin for Minecraft.
|
||||
* Copyright (C) IntellectualSites <https://intellectualsites.com>
|
||||
* Copyright (C) IntellectualSites team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.plotsquared.core.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
class ReflectionHelperTest {
|
||||
|
||||
@Test
|
||||
void findMethod() throws NoSuchMethodException {
|
||||
assertThrows(
|
||||
RuntimeException.class, () ->
|
||||
ReflectionHelper.findMethod(MethodTesterClass.class, MethodType.methodType(String.class))
|
||||
);
|
||||
assertEquals(
|
||||
MethodTesterClass.class.getMethod("methodThree"),
|
||||
ReflectionHelper.findMethod(MethodTesterClass.class, MethodType.methodType(String.class), Modifier.PUBLIC)
|
||||
.orElse(null)
|
||||
);
|
||||
assertEquals(
|
||||
MethodTesterClass.class.getDeclaredMethod("methodFour", String.class, Collection.class),
|
||||
ReflectionHelper.findMethod(MethodTesterClass.class, MethodType.methodType(
|
||||
String.class, String.class, Collection.class
|
||||
)).orElse(null)
|
||||
);
|
||||
// check that helper allows super classes of parameters when searching
|
||||
assertEquals(
|
||||
MethodTesterClass.class.getDeclaredMethod("methodFour", String.class, Collection.class),
|
||||
ReflectionHelper.findMethod(MethodTesterClass.class, MethodType.methodType(
|
||||
String.class, String.class, Object.class
|
||||
)).orElse(null)
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class MethodTesterClass {
|
||||
|
||||
private static String methodOne() {
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String methodTwo() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String methodThree() {
|
||||
return "";
|
||||
}
|
||||
|
||||
protected static String methodFour(String param, Collection<String> paramList) {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user