You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ma...@apache.org on 2022/03/23 03:43:31 UTC

[logging-log4j2] 02/02: Revert MethodHandle usage back to reflection

This is an automated email from the ASF dual-hosted git repository.

mattsicker pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit fdd78e9a50b7566c6a4e1b70be1e62708dd517ad
Author: Matt Sicker <ma...@apache.org>
AuthorDate: Tue Mar 22 22:42:47 2022 -0500

    Revert MethodHandle usage back to reflection
    
    The access rules seem a bit too difficult to work around in Java 17.
    
    Signed-off-by: Matt Sicker <ma...@apache.org>
---
 .../log4j/core/config/LoggersPluginTest.java       |   2 +-
 .../logging/log4j/core/impl/DefaultCallback.java   |   3 +-
 .../log4j/plugin/processor/PluginProcessor.java    |   9 -
 .../logging/log4j/plugins/di/InjectorTest.java     |   3 +-
 .../logging/log4j/plugins/di/DefaultInjector.java  | 189 +++++++++++----------
 .../logging/log4j/plugins/di/InjectException.java  |  30 ++++
 .../apache/logging/log4j/plugins/di/Injector.java  |  11 +-
 .../log4j/plugins/di/ReflectionAccessor.java       |  25 +++
 .../log4j/plugins/processor/PluginService.java     |   5 +-
 .../logging/log4j/plugins/util/PluginRegistry.java |   3 +-
 .../logging/log4j/plugins/util/PluginType.java     |  27 +--
 11 files changed, 164 insertions(+), 143 deletions(-)

diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/LoggersPluginTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/LoggersPluginTest.java
index 4a2df35..5108210 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/LoggersPluginTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/LoggersPluginTest.java
@@ -43,6 +43,6 @@ public class LoggersPluginTest {
         //System.out.println(data.getFormattedStatus());
 
         assertThat(data.getLevel()).isEqualTo(Level.ERROR);
-        assertThat(data.getMessage().getFormattedMessage()).contains("multiple root loggers");
+        assertThat(data.getMessage().getFormattedMessage()).startsWith("Could not configure plugin element Loggers");
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultCallback.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultCallback.java
index 5940303..1233ab9 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultCallback.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultCallback.java
@@ -45,7 +45,6 @@ import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.PropertiesUtil;
 
-import java.lang.invoke.MethodHandles;
 import java.util.Map;
 import java.util.function.Supplier;
 
@@ -81,7 +80,7 @@ public class DefaultCallback implements InjectorCallback {
     public void configure(final Injector injector) {
         final PropertiesUtil properties = PropertiesUtil.getProperties();
         final var loader = new PropertyLoader(injector, properties, Loader.getClassLoader());
-        injector.setLookup(MethodHandles.lookup());
+        injector.setReflectionAccessor(object -> object.setAccessible(true));
         injector.registerBindingIfAbsent(ContextSelector.KEY,
                         () -> loader.getInstance(Constants.LOG4J_CONTEXT_SELECTOR, ContextSelector.class,
                                 () -> ClassLoaderContextSelector.class))
diff --git a/log4j-plugin-processor/src/main/java/org/apache/logging/log4j/plugin/processor/PluginProcessor.java b/log4j-plugin-processor/src/main/java/org/apache/logging/log4j/plugin/processor/PluginProcessor.java
index f0e1911..cf6a7a6 100644
--- a/log4j-plugin-processor/src/main/java/org/apache/logging/log4j/plugin/processor/PluginProcessor.java
+++ b/log4j-plugin-processor/src/main/java/org/apache/logging/log4j/plugin/processor/PluginProcessor.java
@@ -156,18 +156,11 @@ public class PluginProcessor extends AbstractProcessor {
         try (final PrintWriter writer = createSourceFile(fqcn)) {
             writer.println("package " + pkg + ".plugins;");
             writer.println("");
-            writer.println("import org.apache.logging.log4j.plugins.di.LookupSelector;");
             writer.println("import org.apache.logging.log4j.plugins.processor.PluginEntry;");
             writer.println("import org.apache.logging.log4j.plugins.processor.PluginService;");
             writer.println("");
-            writer.println("import java.lang.invoke.MethodHandles.Lookup;");
-            writer.println("");
-            writer.println("import static java.lang.invoke.MethodHandles.lookup;");
-            writer.println("import static java.lang.invoke.MethodHandles.privateLookupIn;");
-            writer.println("");
             writer.println("public class Log4jPlugins extends PluginService {");
             writer.println("");
-            writer.println("    private static final Lookup LOOKUP = lookup();");
             writer.println("    private static final PluginEntry[] ENTRIES = new PluginEntry[] {");
             StringBuilder sb = new StringBuilder();
             int max = list.size() - 1;
@@ -189,8 +182,6 @@ public class PluginProcessor extends AbstractProcessor {
             writer.println("    };");
             writer.println("    @Override");
             writer.println("    public PluginEntry[] getEntries() { return ENTRIES; }");
-            writer.println("    @Override");
-            writer.println("    protected LookupSelector getLookupSelector() { return clazz -> privateLookupIn(clazz, LOOKUP); }");
             writer.println("}");
         }
     }
diff --git a/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/di/InjectorTest.java b/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/di/InjectorTest.java
index 654439b..8f93480 100644
--- a/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/di/InjectorTest.java
+++ b/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/di/InjectorTest.java
@@ -41,7 +41,6 @@ import org.junit.jupiter.api.parallel.Resources;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.lang.invoke.MethodHandles;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -589,7 +588,7 @@ class InjectorTest {
         final Plugin plugin = clazz.getAnnotation(Plugin.class);
         final PluginEntry entry = new PluginEntry(plugin.name().toLowerCase(Locale.ROOT), clazz.getName(), plugin.name(),
                 plugin.printObject(), plugin.deferChildren(), plugin.category());
-        return new PluginType<>(entry, clazz, MethodHandles.lookup().in(clazz), plugin.elementType());
+        return new PluginType<>(entry, clazz, plugin.elementType());
     }
 
     @Test
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java
index 51bf172..d7050d2 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java
@@ -22,7 +22,6 @@ import org.apache.logging.log4j.plugins.FactoryType;
 import org.apache.logging.log4j.plugins.Inject;
 import org.apache.logging.log4j.plugins.Named;
 import org.apache.logging.log4j.plugins.Node;
-import org.apache.logging.log4j.plugins.PluginException;
 import org.apache.logging.log4j.plugins.QualifierType;
 import org.apache.logging.log4j.plugins.ScopeType;
 import org.apache.logging.log4j.plugins.Singleton;
@@ -42,14 +41,13 @@ import org.apache.logging.log4j.util.ServiceRegistry;
 import org.apache.logging.log4j.util.StringBuilders;
 
 import java.lang.annotation.Annotation;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodHandles.Lookup;
-import java.lang.invoke.VarHandle;
+import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Executable;
 import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Parameter;
@@ -75,7 +73,7 @@ class DefaultInjector implements Injector {
 
     private final BindingMap bindingMap;
     private final Map<Class<? extends Annotation>, Scope> scopes = new ConcurrentHashMap<>();
-    private Lookup lookup = MethodHandles.lookup();
+    private ReflectionAccessor accessor = object -> object.setAccessible(true);
 
     DefaultInjector() {
         bindingMap = new BindingMap();
@@ -86,7 +84,7 @@ class DefaultInjector implements Injector {
     DefaultInjector(final DefaultInjector original) {
         bindingMap = new BindingMap(original.bindingMap);
         scopes.putAll(original.scopes);
-        lookup = original.lookup;
+        accessor = original.accessor;
     }
 
     @Override
@@ -170,8 +168,15 @@ class DefaultInjector implements Injector {
     }
 
     @Override
-    public void setLookup(final Lookup lookup) {
-        this.lookup = lookup;
+    public void setReflectionAccessor(final ReflectionAccessor accessor) {
+        this.accessor = accessor;
+    }
+
+    private <M extends AccessibleObject & Member> void makeAccessible(final M member, final Object instance) {
+        final boolean isStatic = Modifier.isStatic(member.getModifiers());
+        if (!member.canAccess(isStatic ? null : instance)) {
+            accessor.makeAccessible(member);
+        }
     }
 
     private <T> Supplier<T> getFactory(
@@ -219,10 +224,10 @@ class DefaultInjector implements Injector {
         final Class<?> rawType = key.getRawType();
         validate(rawType, key.getName(), rawType);
         final Constructor<?> constructor = getInjectableConstructor(key, chain);
+        makeAccessible(constructor, null);
         final List<InjectionPoint<?>> points = InjectionPoint.fromExecutable(constructor);
-        final MethodHandle handle = getConstructorHandle(constructor, lookup);
         final var args = getArguments(key, node, points, chain, debugLog);
-        return rethrow(() -> handle.invokeWithArguments(args));
+        return newInstance(constructor, args);
     }
 
     private void validate(final AnnotatedElement element, final String name, final Object value) {
@@ -260,17 +265,16 @@ class DefaultInjector implements Injector {
     }
 
     private <T> void injectField(final Field field, final Node node, final Object instance, final StringBuilder debugLog) {
-        final Lookup fieldLookup = node != null ? node.getType().getPluginLookup() : lookup.in(instance.getClass());
-        final VarHandle handle = getFieldHandle(field, fieldLookup);
+        makeAccessible(field, instance);
         final InjectionPoint<T> point = InjectionPoint.forField(field);
         final Supplier<T> factory = getFactory(point, node, Set.of(), debugLog);
         final Key<T> key = point.getKey();
         final Object value = key.getRawType() == Supplier.class ? factory : factory.get();
         if (value != null) {
-            handle.set(instance, value);
+            setField(field, instance, value);
         }
         if (AnnotationUtil.isMetaAnnotationPresent(field, Constraint.class)) {
-            final Object fieldValue = handle.get(instance);
+            final Object fieldValue = getField(field, instance);
             validate(field, key.getName(), fieldValue);
         }
     }
@@ -278,23 +282,22 @@ class DefaultInjector implements Injector {
     private void injectMethods(
             final Key<?> key, final Node node, final Object instance, final Set<Key<?>> chain, final StringBuilder debugLog) {
         final Class<?> rawType = key.getRawType();
-        final Lookup methodLookup = node != null ? node.getType().getPluginLookup() : lookup.in(instance.getClass());
-        final List<MethodHandle> injectMethodsWithNoArgs = new ArrayList<>();
+        final List<Method> injectMethodsWithNoArgs = new ArrayList<>();
         for (Class<?> clazz = rawType; clazz != Object.class; clazz = clazz.getSuperclass()) {
             for (final Method method : clazz.getDeclaredMethods()) {
                 if (isInjectable(method)) {
-                    final MethodHandle handle = getMethodHandle(method, methodLookup).bindTo(instance);
+                    makeAccessible(method, instance);
                     if (method.getParameterCount() == 0) {
-                        injectMethodsWithNoArgs.add(handle);
+                        injectMethodsWithNoArgs.add(method);
                     } else {
                         final List<InjectionPoint<?>> injectionPoints = InjectionPoint.fromExecutable(method);
-                        final List<?> args = getArguments(key, node, injectionPoints, chain, debugLog);
-                        rethrow(() -> handle.invokeWithArguments(args));
+                        final var args = getArguments(key, node, injectionPoints, chain, debugLog);
+                        invokeMethod(method, instance, args);
                     }
                 }
             }
         }
-        injectMethodsWithNoArgs.forEach(handle -> rethrow(handle::invoke));
+        injectMethodsWithNoArgs.forEach(method -> invokeMethod(method, instance));
     }
 
     private void inject(final Node node) {
@@ -354,15 +357,15 @@ class DefaultInjector implements Injector {
                 .map(Executable.class::cast)
                 .orElseGet(() -> getInjectableConstructor(key, Set.of()));
         final List<InjectionPoint<?>> points = InjectionPoint.fromExecutable(factory);
-        final Lookup pluginLookup = type.getPluginLookup();
-        final MethodHandle handle;
+        if (!factory.canAccess(null)) {
+            accessor.makeAccessible(factory);
+        }
+        final var args = getArguments(key, node, points, Set.of(), debugLog);
         if (factory instanceof Method) {
-            handle = getMethodHandle((Method) factory, pluginLookup);
+            return invokeMethod((Method) factory, null, args);
         } else {
-            handle = getConstructorHandle((Constructor<?>) factory, pluginLookup);
+            return newInstance((Constructor<?>) factory, args);
         }
-        final var args = getArguments(key, node, points, Set.of(), debugLog);
-        return rethrow(() -> handle.invokeWithArguments(args));
     }
 
     private void registerModuleInstance(final Object module) {
@@ -379,7 +382,7 @@ class DefaultInjector implements Injector {
                         createMethodBindings(module, method).forEach(binding -> {
                             final var key = binding.getKey();
                             if (!bindingMap.putIfAbsent(key, binding.getSupplier())) {
-                                throw new PluginException(String.format(
+                                throw new InjectException(String.format(
                                         "Duplicate @Factory method (%s: %s) found for %s", moduleClass, method, key));
                             }
                         });
@@ -388,20 +391,22 @@ class DefaultInjector implements Injector {
     }
 
     private <T> List<Binding<T>> createMethodBindings(final Object instance, final Method method) {
+        makeAccessible(method, instance);
         final Key<T> primaryKey = Key.forMethod(method);
         final List<InjectionPoint<?>> points = InjectionPoint.fromExecutable(method);
-        final MethodHandle handle = getMethodHandle(method, lookup);
-        final MethodHandle boundHandle = Modifier.isStatic(method.getModifiers()) ? handle : handle.bindTo(instance);
         final var argumentFactories = getArgumentFactories(primaryKey, null, points, Set.of(primaryKey), null);
         final Supplier<T> unscoped = () -> {
-            final List<Object> args = argumentFactories.entrySet()
+            final var args = argumentFactories.entrySet()
                     .stream()
-                    .flatMap(e -> {
+                    .map(e -> {
+                        final Parameter parameter = e.getKey();
+                        final String name = AnnotatedElementNameProvider.getName(parameter);
                         final Object value = e.getValue().get();
-                        return e.getKey().isVarArgs() ? Stream.of((Object[]) value) : Stream.of(value);
+                        validate(parameter, name, value);
+                        return value;
                     })
-                    .collect(Collectors.toList());
-            return TypeUtil.cast(rethrow(() -> boundHandle.invokeWithArguments(args)));
+                    .toArray();
+            return rethrow(() -> TypeUtil.cast(invokeMethod(method, instance, args)));
         };
         final Supplier<T> factory = getScopeForMethod(method).get(primaryKey, unscoped);
         final Collection<String> aliases = AnnotatedElementAliasesProvider.getAliases(method);
@@ -413,20 +418,20 @@ class DefaultInjector implements Injector {
         return bindings;
     }
 
-    private List<Object> getArguments(
+    private Object[] getArguments(
             final Key<?> key, final Node node, final List<InjectionPoint<?>> points, final Set<Key<?>> chain,
             final StringBuilder debugLog) {
         return getArgumentFactories(key, node, points, chain, debugLog)
                 .entrySet()
                 .stream()
-                .flatMap(e -> {
+                .map(e -> {
                     final Parameter parameter = e.getKey();
                     final String name = AnnotatedElementNameProvider.getName(parameter);
                     final Object value = e.getValue().get();
                     validate(parameter, name, value);
-                    return parameter.isVarArgs() ? Stream.of((Object[]) value) : Stream.of(value);
+                    return value;
                 })
-                .collect(Collectors.toList());
+                .toArray();
     }
 
     private Map<Parameter, Supplier<?>> getArgumentFactories(
@@ -446,7 +451,7 @@ class DefaultInjector implements Injector {
                         sb.append(chainKey).append(" -> ");
                     }
                     sb.append(parameterKey);
-                    throw new PluginException(sb.toString());
+                    throw new InjectException(sb.toString());
                 }
                 argFactories.put(parameter, () -> getFactory(point, node, newChain, debugLog).get());
             }
@@ -464,7 +469,8 @@ class DefaultInjector implements Injector {
         return scope != null ? scopes.get(scope.annotationType()) : DefaultScope.INSTANCE;
     }
 
-    private static boolean isCompatibleValidator(final Constraint constraint, final Class<? extends Annotation> annotationType) {
+    private static boolean isCompatibleValidator(
+            final Constraint constraint, final Class<? extends Annotation> annotationType) {
         for (final Type type : constraint.value().getGenericInterfaces()) {
             if (type instanceof ParameterizedType) {
                 ParameterizedType parameterizedType = (ParameterizedType) type;
@@ -478,7 +484,8 @@ class DefaultInjector implements Injector {
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    private static void initializeConstraintValidator(final ConstraintValidator<? extends Annotation> validator, final Annotation annotation) {
+    private static void initializeConstraintValidator(
+            final ConstraintValidator<? extends Annotation> validator, final Annotation annotation) {
         // runtime type checking ensures this raw type usage is correct
         ((ConstraintValidator) validator).initialize(annotation);
     }
@@ -525,61 +532,13 @@ class DefaultInjector implements Injector {
         return newChain;
     }
 
-    private static VarHandle getFieldHandle(final Field field, final Lookup lookup) {
-        final Class<?> declaringClass = field.getDeclaringClass();
-        try {
-            return lookup.unreflectVarHandle(field);
-        } catch (final IllegalAccessException outer) {
-            try {
-                return MethodHandles.privateLookupIn(declaringClass, lookup).unreflectVarHandle(field);
-            } catch (final IllegalAccessException inner) {
-                final var error = new IllegalAccessError("Cannot access field " + field);
-                error.addSuppressed(inner);
-                error.addSuppressed(outer);
-                throw error;
-            }
-        }
-    }
-
-    private static MethodHandle getMethodHandle(final Method method, final Lookup lookup) {
-        final Class<?> declaringClass = method.getDeclaringClass();
-        try {
-            return lookup.unreflect(method);
-        } catch (final IllegalAccessException outer) {
-            try {
-                return MethodHandles.privateLookupIn(declaringClass, lookup).unreflect(method);
-            } catch (final IllegalAccessException inner) {
-                final var error = new IllegalAccessError("Cannot access method " + method);
-                error.addSuppressed(inner);
-                error.addSuppressed(outer);
-                throw error;
-            }
-        }
-    }
-
-    private static MethodHandle getConstructorHandle(final Constructor<?> constructor, final Lookup lookup) {
-        final Class<?> declaringClass = constructor.getDeclaringClass();
-        try {
-            return lookup.unreflectConstructor(constructor);
-        } catch (final IllegalAccessException outer) {
-            try {
-                return MethodHandles.privateLookupIn(declaringClass, lookup).unreflectConstructor(constructor);
-            } catch (final IllegalAccessException inner) {
-                final var error = new IllegalAccessError("Cannot access constructor " + constructor);
-                error.addSuppressed(inner);
-                error.addSuppressed(outer);
-                throw error;
-            }
-        }
-    }
-
     private static <T> Constructor<T> getInjectableConstructor(final Key<T> key, final Set<Key<?>> chain) {
         final Class<T> rawType = key.getRawType();
         final List<Constructor<?>> injectConstructors = Stream.of(rawType.getDeclaredConstructors())
                 .filter(constructor -> constructor.isAnnotationPresent(Inject.class))
                 .collect(Collectors.toList());
         if (injectConstructors.size() > 1) {
-            throw new PluginException("Multiple @Inject constructors found in " + rawType);
+            throw new InjectException("Multiple @Inject constructors found in " + rawType);
         }
         if (injectConstructors.size() == 1) {
             return TypeUtil.cast(injectConstructors.get(0));
@@ -597,7 +556,7 @@ class DefaultInjector implements Injector {
         final String prefix = chain.isEmpty() ? "" : "chain ";
         final String keysToString =
                 prefix + keys.stream().map(Key::toString).collect(Collectors.joining(" -> "));
-        throw new PluginException(
+        throw new InjectException(
                 "No @Inject constructors or no-arg constructor found for " + keysToString);
     }
 
@@ -612,6 +571,50 @@ class DefaultInjector implements Injector {
                                 parameter -> AnnotationUtil.isMetaAnnotationPresent(parameter, QualifierType.class));
     }
 
+    private static Object getField(final Field field, final Object instance) {
+        try {
+            return field.get(instance);
+        } catch (final IllegalAccessException e) {
+            throw errorFrom(e);
+        }
+    }
+
+    private static void setField(final Field field, final Object instance, final Object value) {
+        try {
+            field.set(instance, value);
+        } catch (final IllegalAccessException e) {
+            throw errorFrom(e);
+        }
+    }
+
+    private static Object invokeMethod(final Method method, final Object instance, final Object... args) {
+        try {
+            return method.invoke(instance, args);
+        } catch (final InvocationTargetException e) {
+            throw new InjectException(e.getMessage(), e.getCause());
+        } catch (final IllegalAccessException e) {
+            throw errorFrom(e);
+        }
+    }
+
+    private static <T> T newInstance(final Constructor<T> constructor, final Object[] args) {
+        try {
+            return constructor.newInstance(args);
+        } catch (final InvocationTargetException e) {
+            throw new InjectException(e.getMessage(), e.getCause());
+        } catch (final IllegalAccessException e) {
+            throw errorFrom(e);
+        } catch (final InstantiationException e) {
+            throw new InjectException(e.getMessage(), e);
+        }
+    }
+
+    private static IllegalAccessError errorFrom(final IllegalAccessException e) {
+        final IllegalAccessError error = new IllegalAccessError(e.getMessage());
+        error.initCause(e);
+        return error;
+    }
+
     private static <T> T rethrow(final CheckedSupplier<T> supplier) {
         try {
             return supplier.get();
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/InjectException.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/InjectException.java
new file mode 100644
index 0000000..7913745
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/InjectException.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.plugins.di;
+
+import org.apache.logging.log4j.plugins.PluginException;
+
+public class InjectException extends PluginException {
+    public InjectException(final String message) {
+        super(message);
+    }
+
+    public InjectException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java
index e5ad184..8420c92 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java
@@ -21,7 +21,6 @@ import org.apache.logging.log4j.plugins.FactoryType;
 import org.apache.logging.log4j.plugins.Node;
 
 import java.lang.annotation.Annotation;
-import java.lang.invoke.MethodHandles.Lookup;
 import java.util.function.Supplier;
 
 /**
@@ -149,12 +148,12 @@ public interface Injector {
      */
     <T> Injector registerBindingIfAbsent(final Key<T> key, final Supplier<? extends T> factory);
 
-
     /**
-     * Sets the {@link Lookup} used for obtaining MethodHandle and VarHandle instances. A custom caller class
-     * can invoke {@code setLookup(MethodHandles.lookup())} as a typical use case.
+     * Sets the {@link ReflectionAccessor} used for invoking {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)}
+     * from an appropriate caller class. Customizing this allows for changing the base module that other modules should
+     * open themselves to.
      *
-     * @param lookup handle lookup object for access checks
+     * @param accessor accessor to use
      */
-    void setLookup(final Lookup lookup);
+    void setReflectionAccessor(final ReflectionAccessor accessor);
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/ReflectionAccessor.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/ReflectionAccessor.java
new file mode 100644
index 0000000..22508ce
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/ReflectionAccessor.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.plugins.di;
+
+import java.lang.reflect.AccessibleObject;
+
+@FunctionalInterface
+public interface ReflectionAccessor {
+    void makeAccessible(final AccessibleObject object);
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
index aa1392d..00d8a7c 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
@@ -16,7 +16,6 @@
  */
 package org.apache.logging.log4j.plugins.processor;
 
-import org.apache.logging.log4j.plugins.di.LookupSelector;
 import org.apache.logging.log4j.plugins.util.PluginType;
 
 import java.util.ArrayList;
@@ -41,15 +40,13 @@ public abstract class PluginService {
         for (PluginEntry entry : entries) {
             String category = entry.getCategory().toLowerCase();
             List<PluginType<?>> list = categories.computeIfAbsent(category, ignored -> new ArrayList<>());
-            PluginType<?> type = new PluginType<>(entry, classLoader, getLookupSelector());
+            PluginType<?> type = new PluginType<>(entry, classLoader);
             list.add(type);
         }
     }
 
     public abstract PluginEntry[] getEntries();
 
-    protected abstract LookupSelector getLookupSelector();
-
     public Map<String, List<PluginType<?>>> getCategories() {
         return Collections.unmodifiableMap(categories);
     }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
index dd3a4ce..413f9e1 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
@@ -253,8 +253,7 @@ public class PluginRegistry {
             newPluginsByCategory.put(categoryLowerCase, types);
             for (final Map.Entry<String, PluginEntry> inner : outer.getValue().entrySet()) {
                 final PluginEntry entry = inner.getValue();
-                final PluginType<?> type = new PluginType<>(entry, context.getClassLoader(),
-                        clazz -> MethodHandles.privateLookupIn(clazz, context.getLookup()));
+                final PluginType<?> type = new PluginType<>(entry, context.getClassLoader());
                 types.add(type);
                 ++pluginCount;
             }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
index 55adbc5..f1ab067 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
@@ -16,12 +16,9 @@
  */
 package org.apache.logging.log4j.plugins.util;
 
-import org.apache.logging.log4j.plugins.di.LookupSelector;
 import org.apache.logging.log4j.plugins.processor.PluginEntry;
 import org.apache.logging.log4j.util.LazyValue;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodHandles.Lookup;
 import java.util.function.Supplier;
 
 /**
@@ -34,7 +31,6 @@ public class PluginType<T> {
 
     private final PluginEntry pluginEntry;
     private final Supplier<Class<T>> pluginClass;
-    private final Supplier<Lookup> pluginLookup;
     private final String elementName;
 
     /**
@@ -44,15 +40,10 @@ public class PluginType<T> {
      * @param elementName The name of the element.
      * @since 2.1
      */
-    public PluginType(final PluginEntry pluginEntry, final Class<T> pluginClass, final String elementName) {
-        this(pluginEntry, pluginClass, MethodHandles.lookup().in(pluginClass), elementName);
-    }
-
     public PluginType(
-            final PluginEntry pluginEntry, final Class<T> pluginClass, final Lookup pluginLookup, final String elementName) {
+            final PluginEntry pluginEntry, final Class<T> pluginClass, final String elementName) {
         this.pluginEntry = pluginEntry;
         this.pluginClass = () -> pluginClass;
-        this.pluginLookup = () -> pluginLookup;
         this.elementName = elementName;
     }
 
@@ -61,9 +52,9 @@ public class PluginType<T> {
      * @since 3.0
      * @param pluginEntry The PluginEntry.
      */
-    public PluginType(final PluginEntry pluginEntry, final ClassLoader classLoader, final LookupSelector lookupSelector) {
+    public PluginType(final PluginEntry pluginEntry, final ClassLoader classLoader) {
         this.pluginEntry = pluginEntry;
-        final LazyValue<Class<T>> pluginClass = new LazyValue<>(() -> {
+        this.pluginClass = new LazyValue<>(() -> {
             try {
                 return TypeUtil.cast(classLoader.loadClass(pluginEntry.getClassName()));
             } catch (final ClassNotFoundException e) {
@@ -71,14 +62,6 @@ public class PluginType<T> {
                         " located for element " + pluginEntry.getName(), e);
             }
         });
-        this.pluginClass = pluginClass;
-        this.pluginLookup = pluginClass.map(clazz -> {
-            try {
-                return lookupSelector.in(clazz);
-            } catch (final IllegalAccessException e) {
-                throw new IllegalAccessError(e.getMessage());
-            }
-        });
         this.elementName = pluginEntry.getName();
     }
 
@@ -91,10 +74,6 @@ public class PluginType<T> {
         return pluginClass.get();
     }
 
-    public Lookup getPluginLookup() {
-        return pluginLookup.get();
-    }
-
     public String getElementName() {
         return this.elementName;
     }