From c3128dec0d3cb955ffbe8b8bed7eae66d4b7fd33 Mon Sep 17 00:00:00 2001 From: Luck Date: Mon, 30 Mar 2020 19:18:34 +0100 Subject: [PATCH] Generate actual classes for LP events at runtime instead of using proxies + InvocationHandlers --- bukkit/build.gradle | 1 + bungee/build.gradle | 1 + common/build.gradle | 1 + .../common/dependencies/Dependency.java | 7 + .../common/event/EventDispatcher.java | 8 +- .../common/event/gen/AbstractEvent.java | 54 +++++ .../common/event/gen/GeneratedEventClass.java | 192 ++++++++++++++++++ .../common/event/gen/GeneratedEventSpec.java | 167 --------------- .../plugin/AbstractLuckPermsPlugin.java | 1 + .../common/util/PrivateMethodHandles.java | 63 ------ nukkit/build.gradle | 1 + sponge/build.gradle | 1 + velocity/build.gradle | 1 + 13 files changed, 266 insertions(+), 232 deletions(-) create mode 100644 common/src/main/java/me/lucko/luckperms/common/event/gen/AbstractEvent.java create mode 100644 common/src/main/java/me/lucko/luckperms/common/event/gen/GeneratedEventClass.java delete mode 100644 common/src/main/java/me/lucko/luckperms/common/event/gen/GeneratedEventSpec.java delete mode 100644 common/src/main/java/me/lucko/luckperms/common/util/PrivateMethodHandles.java diff --git a/bukkit/build.gradle b/bukkit/build.gradle index 792677e99..247e3a978 100644 --- a/bukkit/build.gradle +++ b/bukkit/build.gradle @@ -55,6 +55,7 @@ shadowJar { relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine' relocate 'okio', 'me.lucko.luckperms.lib.okio' relocate 'okhttp3', 'me.lucko.luckperms.lib.okhttp3' + relocate 'net.bytebuddy', 'me.lucko.luckperms.lib.bytebuddy' relocate 'me.lucko.commodore', 'me.lucko.luckperms.lib.commodore' relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb' relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql' diff --git a/bungee/build.gradle b/bungee/build.gradle index 95e7fc0b2..9c49bbddf 100644 --- a/bungee/build.gradle +++ b/bungee/build.gradle @@ -41,6 +41,7 @@ shadowJar { relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine' relocate 'okio', 'me.lucko.luckperms.lib.okio' relocate 'okhttp3', 'me.lucko.luckperms.lib.okhttp3' + relocate 'net.bytebuddy', 'me.lucko.luckperms.lib.bytebuddy' relocate 'me.lucko.commodore', 'me.lucko.luckperms.lib.commodore' relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb' relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql' diff --git a/common/build.gradle b/common/build.gradle index 52924d44c..2366c347c 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -21,6 +21,7 @@ dependencies { compile 'com.github.ben-manes.caffeine:caffeine:2.8.0' compile 'com.squareup.okhttp3:okhttp:3.14.4' compile 'com.squareup.okio:okio:1.17.4' + compile 'net.bytebuddy:byte-buddy:1.10.9' compile('me.lucko.configurate:configurate-core:3.5') { exclude(module: 'guava') } diff --git a/common/src/main/java/me/lucko/luckperms/common/dependencies/Dependency.java b/common/src/main/java/me/lucko/luckperms/common/dependencies/Dependency.java index 930d92d49..0ec2ce0a0 100644 --- a/common/src/main/java/me/lucko/luckperms/common/dependencies/Dependency.java +++ b/common/src/main/java/me/lucko/luckperms/common/dependencies/Dependency.java @@ -127,6 +127,13 @@ public enum Dependency { Relocation.of(RelocationHelper.OKHTTP3_STRING, RelocationHelper.OKHTTP3_STRING), Relocation.of(RelocationHelper.OKIO_STRING, RelocationHelper.OKIO_STRING) ), + BYTEBUDDY( + "net{}bytebuddy", + "byte-buddy", + "1.10.9", + "B7nKbi+XDLA/SyVlHfHy/OJx1JG0TgQJgniHeG9pLU0=", + Relocation.of("bytebuddy", "net{}bytebuddy") + ), COMMODORE( "me{}lucko", "commodore", diff --git a/common/src/main/java/me/lucko/luckperms/common/event/EventDispatcher.java b/common/src/main/java/me/lucko/luckperms/common/event/EventDispatcher.java index 71ff9007a..6548307b5 100644 --- a/common/src/main/java/me/lucko/luckperms/common/event/EventDispatcher.java +++ b/common/src/main/java/me/lucko/luckperms/common/event/EventDispatcher.java @@ -32,7 +32,7 @@ import me.lucko.luckperms.common.api.implementation.ApiPermissionHolder; import me.lucko.luckperms.common.api.implementation.ApiUser; import me.lucko.luckperms.common.cacheddata.GroupCachedDataManager; import me.lucko.luckperms.common.cacheddata.UserCachedDataManager; -import me.lucko.luckperms.common.event.gen.GeneratedEventSpec; +import me.lucko.luckperms.common.event.gen.GeneratedEventClass; import me.lucko.luckperms.common.event.model.EntitySourceImpl; import me.lucko.luckperms.common.event.model.SenderPlatformEntity; import me.lucko.luckperms.common.event.model.UnknownSource; @@ -132,7 +132,11 @@ public final class EventDispatcher { @SuppressWarnings("unchecked") private T generate(Class eventClass, Object... params) { - return (T) GeneratedEventSpec.lookup(eventClass).newInstance(this.eventBus.getApiProvider(), params); + try { + return (T) GeneratedEventClass.generate(eventClass).newInstance(this.eventBus.getApiProvider(), params); + } catch (Throwable e) { + throw new RuntimeException("Exception occurred whilst generating event instance", e); + } } public void dispatchExtensionLoad(Extension extension) { diff --git a/common/src/main/java/me/lucko/luckperms/common/event/gen/AbstractEvent.java b/common/src/main/java/me/lucko/luckperms/common/event/gen/AbstractEvent.java new file mode 100644 index 000000000..890fd6a20 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/event/gen/AbstractEvent.java @@ -0,0 +1,54 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.event.gen; + +import net.luckperms.api.LuckPerms; +import net.luckperms.api.event.LuckPermsEvent; + +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.lang.invoke.MethodHandles; + +/** + * Abstract implementation of {@link LuckPermsEvent}. + */ +public abstract class AbstractEvent implements LuckPermsEvent { + private final LuckPerms api; + + protected AbstractEvent(LuckPerms api) { + this.api = api; + } + + @Override + public @NonNull LuckPerms getLuckPerms() { + return this.api; + } + + // Overridden by the subclass. Used by GeneratedEventClass to get setter method handles. + public MethodHandles.Lookup mhl() { + throw new UnsupportedOperationException(); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/event/gen/GeneratedEventClass.java b/common/src/main/java/me/lucko/luckperms/common/event/gen/GeneratedEventClass.java new file mode 100644 index 000000000..b10aa48b6 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/event/gen/GeneratedEventClass.java @@ -0,0 +1,192 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.event.gen; + +import me.lucko.luckperms.common.cache.LoadingMap; + +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.ClassFileVersion; +import net.bytebuddy.description.NamedElement; +import net.bytebuddy.description.modifier.Visibility; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy; +import net.bytebuddy.implementation.FieldAccessor; +import net.bytebuddy.implementation.FixedValue; +import net.bytebuddy.implementation.MethodCall; +import net.luckperms.api.LuckPerms; +import net.luckperms.api.event.LuckPermsEvent; +import net.luckperms.api.event.util.Param; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Map; + +import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +/** + * Holds the generated event class for a given type of {@link LuckPermsEvent}. + */ +public class GeneratedEventClass { + + /** The MethodHandles.lookup() method */ + private static final Method METHOD_HANDLES_LOOKUP; + static { + try { + METHOD_HANDLES_LOOKUP = MethodHandles.class.getMethod("lookup"); + } catch (NoSuchMethodException e) { + throw new ExceptionInInitializerError(e); + } + } + + /** + * A loading cache of event types to {@link GeneratedEventClass}es. + */ + private static final Map, GeneratedEventClass> CACHE = LoadingMap.of(clazz -> { + try { + return new GeneratedEventClass(clazz); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + }); + + /** + * Generate a {@link GeneratedEventClass} for the given {@code event} type. + * + * @param event the event type + * @return the generated class + */ + public static GeneratedEventClass generate(Class event) { + return CACHE.get(event); + } + + /** + * The constructor used to create instances of the generated class + */ + private final Constructor constructor; + + /** + * An array of {@link MethodHandle}s, which can set values for each of the properties in the event class. + */ + private final MethodHandle[] setters; + + private GeneratedEventClass(Class eventClass) throws ReflectiveOperationException { + + // get a TypeDescription for the event class + TypeDescription eventClassType = new TypeDescription.ForLoadedType(eventClass); + + // determine a generated class name of the event + String eventClassSuffix = eventClass.getName().substring(LuckPermsEvent.class.getPackage().getName().length()); + String generatedClassName = GeneratedEventClass.class.getPackage().getName() + eventClassSuffix; + + DynamicType.Builder builder = new ByteBuddy(ClassFileVersion.JAVA_V8) + // create a subclass of AbstractEvent + .subclass(AbstractEvent.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING) + // using the predetermined generated class name + .name(generatedClassName) + // implement the event interface + .implement(eventClassType) + // implement all methods annotated with Param by simply returning the value from the corresponding field with the same name + .method(isAnnotatedWith(Param.class)) + .intercept(FieldAccessor.of(NamedElement.WithRuntimeName::getInternalName)) + // implement LuckPermsEvent#getEventType by returning the event class type + .method(named("getEventType").and(returns(Class.class)).and(takesArguments(0))) + .intercept(FixedValue.value(eventClassType)) + // implement AbstractEvent#mh by calling & returning the value of MethodHandles.lookup() + .method(named("mhl").and(returns(MethodHandles.Lookup.class)).and(takesArguments(0))) + .intercept(MethodCall.invoke(METHOD_HANDLES_LOOKUP)) + // implement a toString method + .withToString(); + + // get a sorted array of all methods on the event interface annotated with @Param + Method[] properties = Arrays.stream(eventClass.getMethods()) + .filter(m -> m.isAnnotationPresent(Param.class)) + .sorted(Comparator.comparingInt(o -> o.getAnnotation(Param.class).value())) + .toArray(Method[]::new); + + // for each method on the event interface annotated with @Param + for (Method method : properties) { + if (!method.isAnnotationPresent(Param.class)) { + continue; + } + + // define a field on the generated class to hold the value + builder = builder.defineField(method.getName(), method.getReturnType(), Visibility.PRIVATE); + } + + // finish building, load the class, get a constructor + Class generatedClass = builder.make().load(GeneratedEventClass.class.getClassLoader()).getLoaded(); + this.constructor = generatedClass.getDeclaredConstructor(LuckPerms.class); + + // create a dummy instance of the generated class & get the method handle lookup instance + MethodHandles.Lookup lookup = this.constructor.newInstance(new Object[]{null}).mhl(); + + // get 'setter' MethodHandles + this.setters = new MethodHandle[properties.length]; + for (int i = 0; i < properties.length; i++) { + Method method = properties[i]; + + // obtain a setter MethodHandle for the property + this.setters[i] = lookup.findSetter(generatedClass, method.getName(), method.getReturnType()) + .asType(MethodType.methodType(void.class, new Class[]{AbstractEvent.class, Object.class})); + } + } + + /** + * Creates a new instance of the event class. + * + * @param api an instance of the LuckPerms API + * @param properties the event properties + * @return the event instance + * @throws Throwable if something goes wrong + */ + public LuckPermsEvent newInstance(LuckPerms api, Object... properties) throws Throwable { + if (properties.length != this.setters.length) { + throw new IllegalStateException("Unexpected number of properties. given: " + properties.length + ", expected: " + this.setters.length); + } + + // create a new instance of the event + final AbstractEvent event = this.constructor.newInstance(api); + + // set the properties onto the event instance + for (int i = 0; i < this.setters.length; i++) { + MethodHandle setter = this.setters[i]; + Object value = properties[i]; + setter.invokeExact(event, value); + } + + return event; + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/event/gen/GeneratedEventSpec.java b/common/src/main/java/me/lucko/luckperms/common/event/gen/GeneratedEventSpec.java deleted file mode 100644 index ba2c50911..000000000 --- a/common/src/main/java/me/lucko/luckperms/common/event/gen/GeneratedEventSpec.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * This file is part of LuckPerms, licensed under the MIT License. - * - * Copyright (c) lucko (Luck) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package me.lucko.luckperms.common.event.gen; - -import com.google.common.collect.ImmutableList; - -import me.lucko.luckperms.common.cache.LoadingMap; -import me.lucko.luckperms.common.util.ImmutableCollectors; -import me.lucko.luckperms.common.util.PrivateMethodHandles; - -import net.luckperms.api.LuckPerms; -import net.luckperms.api.event.LuckPermsEvent; -import net.luckperms.api.event.util.Param; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.Map; - -/** - * Represents the generated specification for an instance of a given {@link LuckPermsEvent}. - */ -public class GeneratedEventSpec { - - private static final Method TO_STRING_METHOD; - private static final Method EQUALS_METHOD; - private static final Method HASHCODE_METHOD; - private static final Method GET_LUCKPERMS_METHOD; - private static final Method GET_EVENT_TYPE_METHOD; - static { - try { - TO_STRING_METHOD = Object.class.getMethod("toString"); - EQUALS_METHOD = Object.class.getMethod("equals", Object.class); - HASHCODE_METHOD = Object.class.getMethod("hashCode"); - GET_LUCKPERMS_METHOD = LuckPermsEvent.class.getMethod("getLuckPerms"); - GET_EVENT_TYPE_METHOD = LuckPermsEvent.class.getMethod("getEventType"); - } catch (NoSuchMethodException e) { - throw new ExceptionInInitializerError(e); - } - } - - private static final Map, GeneratedEventSpec> CACHE = LoadingMap.of(GeneratedEventSpec::new); - - public static GeneratedEventSpec lookup(Class event) { - return CACHE.get(event); - } - - private final Class eventClass; - private final List methods; - private final List> returnTypes; - - private GeneratedEventSpec(Class eventClass) { - this.eventClass = eventClass; - - List methods = new ArrayList<>(); - for (Method method : eventClass.getMethods()) { - if (method.isDefault()) { - continue; - } - if (GET_LUCKPERMS_METHOD.equals(method) || GET_EVENT_TYPE_METHOD.equals(method)) { - continue; - } - - methods.add(method); - } - methods.sort(Comparator.comparingInt(o -> o.isAnnotationPresent(Param.class) ? o.getAnnotation(Param.class).value() : 0)); - this.methods = ImmutableList.copyOf(methods); - - this.returnTypes = this.methods.stream() - .map(Method::getReturnType) - .collect(ImmutableCollectors.toList()); - } - - public LuckPermsEvent newInstance(LuckPerms api, Object... params) { - if (params.length != this.methods.size()) { - throw new IllegalStateException("param length differs from number of methods. expected " + this.methods.size() + " - " + this.methods); - } - - for (int i = 0; i < params.length; i++) { - Object param = params[i]; - Class expectedType = this.returnTypes.get(i); - if (!expectedType.isInstance(param)) { - throw new IllegalArgumentException("Parameter at index " + i + " cannot be assigned to " + expectedType); - } - } - - EventInvocationHandler eventInvocationHandler = new EventInvocationHandler(api, params); - return (LuckPermsEvent) Proxy.newProxyInstance(GeneratedEventSpec.class.getClassLoader(), new Class[]{this.eventClass}, eventInvocationHandler); - } - - /** - * An invocation handler bound to a set of parameters, used to implement the event as a proxy. - */ - private final class EventInvocationHandler implements InvocationHandler { - private final LuckPerms api; - private final Object[] fields; - - EventInvocationHandler(LuckPerms api, Object[] fields) { - this.api = api; - this.fields = fields; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (TO_STRING_METHOD.equals(method)) { - return "GeneratedEvent(" + - "proxy=" + proxy.getClass().getName() + "@" + Integer.toHexString(proxy.hashCode()) + ", " + - "class=" + GeneratedEventSpec.this.eventClass.getName() + ", " + - "fields=" + Arrays.toString(this.fields) + ")"; - } - if (EQUALS_METHOD.equals(method)) { - return proxy == args[0]; - } - if (HASHCODE_METHOD.equals(method)) { - return System.identityHashCode(proxy); - } - if (GET_LUCKPERMS_METHOD.equals(method)) { - return this.api; - } - if (GET_EVENT_TYPE_METHOD.equals(method)) { - return GeneratedEventSpec.this.eventClass; - } - - if (method.getDeclaringClass() == Object.class || method.isDefault()) { - return PrivateMethodHandles.privateLookup(method.getDeclaringClass()) - .unreflectSpecial(method, method.getDeclaringClass()) - .bindTo(proxy) - .invokeWithArguments(args); - } - - int methodIndex = GeneratedEventSpec.this.methods.indexOf(method); - if (methodIndex == -1) { - throw new UnsupportedOperationException("Method not supported: " + method); - } - - return this.fields[methodIndex]; - } - } - -} diff --git a/common/src/main/java/me/lucko/luckperms/common/plugin/AbstractLuckPermsPlugin.java b/common/src/main/java/me/lucko/luckperms/common/plugin/AbstractLuckPermsPlugin.java index b80bc6d01..d4787491b 100644 --- a/common/src/main/java/me/lucko/luckperms/common/plugin/AbstractLuckPermsPlugin.java +++ b/common/src/main/java/me/lucko/luckperms/common/plugin/AbstractLuckPermsPlugin.java @@ -250,6 +250,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin { Dependency.CAFFEINE, Dependency.OKIO, Dependency.OKHTTP, + Dependency.BYTEBUDDY, Dependency.EVENT ); } diff --git a/common/src/main/java/me/lucko/luckperms/common/util/PrivateMethodHandles.java b/common/src/main/java/me/lucko/luckperms/common/util/PrivateMethodHandles.java deleted file mode 100644 index 1588cfa3d..000000000 --- a/common/src/main/java/me/lucko/luckperms/common/util/PrivateMethodHandles.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * This file is part of LuckPerms, licensed under the MIT License. - * - * Copyright (c) lucko (Luck) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package me.lucko.luckperms.common.util; - -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -public final class PrivateMethodHandles { - private PrivateMethodHandles() {} - - private static final Constructor LOOKUP_CONSTRUCTOR; - static { - try { - LOOKUP_CONSTRUCTOR = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class); - LOOKUP_CONSTRUCTOR.setAccessible(true); - } catch (NoSuchMethodException e) { - throw new ExceptionInInitializerError(e); - } - } - - // MethodHandles.Lookup.PUBLIC | MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED | MethodHandles.Lookup.PACKAGE - private static final int TRUSTED_FLAG = -1; - - /** - * Returns a {@link MethodHandles.Lookup lookup object} with full capabilities to emulate all - * supported bytecode behaviors, including private access, on a target class. - * - * @param targetClass the target class - * @return a lookup object for the target class, with private access - */ - public static MethodHandles.Lookup privateLookup(Class targetClass) { - try { - return LOOKUP_CONSTRUCTOR.newInstance(targetClass, TRUSTED_FLAG); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); - } - } - -} diff --git a/nukkit/build.gradle b/nukkit/build.gradle index 598f06927..f95cff210 100644 --- a/nukkit/build.gradle +++ b/nukkit/build.gradle @@ -33,6 +33,7 @@ shadowJar { relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine' relocate 'okio', 'me.lucko.luckperms.lib.okio' relocate 'okhttp3', 'me.lucko.luckperms.lib.okhttp3' + relocate 'net.bytebuddy', 'me.lucko.luckperms.lib.bytebuddy' relocate 'me.lucko.commodore', 'me.lucko.luckperms.lib.commodore' relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb' relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql' diff --git a/sponge/build.gradle b/sponge/build.gradle index 65db93bac..cad9c8487 100644 --- a/sponge/build.gradle +++ b/sponge/build.gradle @@ -46,6 +46,7 @@ shadowJar { relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine' relocate 'okio', 'me.lucko.luckperms.lib.okio' relocate 'okhttp3', 'me.lucko.luckperms.lib.okhttp3' + relocate 'net.bytebuddy', 'me.lucko.luckperms.lib.bytebuddy' relocate 'me.lucko.commodore', 'me.lucko.luckperms.lib.commodore' relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb' relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql' diff --git a/velocity/build.gradle b/velocity/build.gradle index 3c7c7f6bd..05130082f 100644 --- a/velocity/build.gradle +++ b/velocity/build.gradle @@ -32,6 +32,7 @@ shadowJar { relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine' relocate 'okio', 'me.lucko.luckperms.lib.okio' relocate 'okhttp3', 'me.lucko.luckperms.lib.okhttp3' + relocate 'net.bytebuddy', 'me.lucko.luckperms.lib.bytebuddy' relocate 'me.lucko.commodore', 'me.lucko.luckperms.lib.commodore' relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb' relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql'