Generate actual classes for LP events at runtime instead of using proxies + InvocationHandlers

This commit is contained in:
Luck 2020-03-30 19:18:34 +01:00
parent b65639cd76
commit c3128dec0d
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
13 changed files with 266 additions and 232 deletions

View File

@ -55,6 +55,7 @@ shadowJar {
relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine' relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine'
relocate 'okio', 'me.lucko.luckperms.lib.okio' relocate 'okio', 'me.lucko.luckperms.lib.okio'
relocate 'okhttp3', 'me.lucko.luckperms.lib.okhttp3' 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 'me.lucko.commodore', 'me.lucko.luckperms.lib.commodore'
relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb' relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb'
relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql' relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql'

View File

@ -41,6 +41,7 @@ shadowJar {
relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine' relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine'
relocate 'okio', 'me.lucko.luckperms.lib.okio' relocate 'okio', 'me.lucko.luckperms.lib.okio'
relocate 'okhttp3', 'me.lucko.luckperms.lib.okhttp3' 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 'me.lucko.commodore', 'me.lucko.luckperms.lib.commodore'
relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb' relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb'
relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql' relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql'

View File

@ -21,6 +21,7 @@ dependencies {
compile 'com.github.ben-manes.caffeine:caffeine:2.8.0' compile 'com.github.ben-manes.caffeine:caffeine:2.8.0'
compile 'com.squareup.okhttp3:okhttp:3.14.4' compile 'com.squareup.okhttp3:okhttp:3.14.4'
compile 'com.squareup.okio:okio:1.17.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') { compile('me.lucko.configurate:configurate-core:3.5') {
exclude(module: 'guava') exclude(module: 'guava')
} }

View File

@ -127,6 +127,13 @@ public enum Dependency {
Relocation.of(RelocationHelper.OKHTTP3_STRING, RelocationHelper.OKHTTP3_STRING), Relocation.of(RelocationHelper.OKHTTP3_STRING, RelocationHelper.OKHTTP3_STRING),
Relocation.of(RelocationHelper.OKIO_STRING, RelocationHelper.OKIO_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( COMMODORE(
"me{}lucko", "me{}lucko",
"commodore", "commodore",

View File

@ -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.api.implementation.ApiUser;
import me.lucko.luckperms.common.cacheddata.GroupCachedDataManager; import me.lucko.luckperms.common.cacheddata.GroupCachedDataManager;
import me.lucko.luckperms.common.cacheddata.UserCachedDataManager; 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.EntitySourceImpl;
import me.lucko.luckperms.common.event.model.SenderPlatformEntity; import me.lucko.luckperms.common.event.model.SenderPlatformEntity;
import me.lucko.luckperms.common.event.model.UnknownSource; import me.lucko.luckperms.common.event.model.UnknownSource;
@ -132,7 +132,11 @@ public final class EventDispatcher {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <T extends LuckPermsEvent> T generate(Class<T> eventClass, Object... params) { private <T extends LuckPermsEvent> T generate(Class<T> 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) { public void dispatchExtensionLoad(Extension extension) {

View File

@ -0,0 +1,54 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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();
}
}

View File

@ -0,0 +1,192 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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<Class<? extends LuckPermsEvent>, 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<? extends LuckPermsEvent> event) {
return CACHE.get(event);
}
/**
* The constructor used to create instances of the generated class
*/
private final Constructor<? extends AbstractEvent> 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<? extends LuckPermsEvent> 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<AbstractEvent> 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<? extends AbstractEvent> 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;
}
}

View File

@ -1,167 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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<Class<? extends LuckPermsEvent>, GeneratedEventSpec> CACHE = LoadingMap.of(GeneratedEventSpec::new);
public static GeneratedEventSpec lookup(Class<? extends LuckPermsEvent> event) {
return CACHE.get(event);
}
private final Class<? extends LuckPermsEvent> eventClass;
private final List<Method> methods;
private final List<Class<?>> returnTypes;
private GeneratedEventSpec(Class<? extends LuckPermsEvent> eventClass) {
this.eventClass = eventClass;
List<Method> 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];
}
}
}

View File

@ -250,6 +250,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
Dependency.CAFFEINE, Dependency.CAFFEINE,
Dependency.OKIO, Dependency.OKIO,
Dependency.OKHTTP, Dependency.OKHTTP,
Dependency.BYTEBUDDY,
Dependency.EVENT Dependency.EVENT
); );
} }

View File

@ -1,63 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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<MethodHandles.Lookup> 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);
}
}
}

View File

@ -33,6 +33,7 @@ shadowJar {
relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine' relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine'
relocate 'okio', 'me.lucko.luckperms.lib.okio' relocate 'okio', 'me.lucko.luckperms.lib.okio'
relocate 'okhttp3', 'me.lucko.luckperms.lib.okhttp3' 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 'me.lucko.commodore', 'me.lucko.luckperms.lib.commodore'
relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb' relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb'
relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql' relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql'

View File

@ -46,6 +46,7 @@ shadowJar {
relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine' relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine'
relocate 'okio', 'me.lucko.luckperms.lib.okio' relocate 'okio', 'me.lucko.luckperms.lib.okio'
relocate 'okhttp3', 'me.lucko.luckperms.lib.okhttp3' 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 'me.lucko.commodore', 'me.lucko.luckperms.lib.commodore'
relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb' relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb'
relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql' relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql'

View File

@ -32,6 +32,7 @@ shadowJar {
relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine' relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine'
relocate 'okio', 'me.lucko.luckperms.lib.okio' relocate 'okio', 'me.lucko.luckperms.lib.okio'
relocate 'okhttp3', 'me.lucko.luckperms.lib.okhttp3' 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 'me.lucko.commodore', 'me.lucko.luckperms.lib.commodore'
relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb' relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb'
relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql' relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql'