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 2021/07/11 20:44:22 UTC

[logging-log4j2] branch mean-bean-machine updated (9efae8a -> 7ff8c9c)

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

mattsicker pushed a change to branch mean-bean-machine
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git.


    from 9efae8a  Merge branch 'master' into mean-bean-machine
     new 64f8151  Fix compile warning
     new 8000a00  Improve docs
     new 7ff8c9c  Add foundation for bean annotation processing and plugin metadata

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 log4j-core/pom.xml                                 |   1 +
 .../apache/logging/log4j/core/config/di/Bean.java  |  68 ++--
 .../logging/log4j/core/config/di/BeanManager.java  |  70 +++--
 .../core/config/di/impl/DefaultBeanManager.java    |  10 +-
 .../config/di/impl/DefaultInjectionTarget.java     |   6 +-
 .../di/impl/DefaultInjectionTargetFactory.java     |  10 +-
 .../log4j/core/config/di/impl/Injector.java        |   3 +-
 .../log4j/core/config/plugins/PluginAttribute.java |   2 +
 .../config/plugins/PluginBuilderAttribute.java     |   2 +
 .../core/config/plugins/PluginBuilderFactory.java  |   9 +-
 .../core/config/plugins/PluginConfiguration.java   |   2 +
 .../log4j/core/config/plugins/PluginElement.java   |   2 +
 .../log4j/core/config/plugins/PluginFactory.java   |   9 +-
 .../log4j/core/config/plugins/PluginNode.java      |   2 +
 .../log4j/core/config/plugins/PluginValue.java     |   2 +
 log4j-plugins/pom.xml                              |  14 +-
 .../org/apache/logging/log4j/plugins/Plugin.java   |   3 +
 .../logging/log4j/plugins/PluginAliases.java       |   2 +
 .../logging/log4j/plugins/PluginAttribute.java     |   2 +
 .../log4j/plugins/PluginBuilderAttribute.java      |   2 +
 .../logging/log4j/plugins/PluginElement.java       |   2 +
 .../logging/log4j/plugins/PluginFactory.java       |   3 +
 .../apache/logging/log4j/plugins/PluginNode.java   |   2 +
 .../apache/logging/log4j/plugins/PluginValue.java  |   2 +
 .../logging/log4j/plugins/di/AnnotationAlias.java  |  38 ---
 .../org/apache/logging/log4j/plugins/di/Named.java |   1 +
 .../logging/log4j/plugins/di/NamedAliases.java     |   1 +
 .../di/{SingletonScoped.java => Producer.java}     |   7 +-
 .../apache/logging/log4j/plugins/di/Produces.java  |   3 +-
 .../di/{SingletonScoped.java => Qualifier.java}    |   7 +-
 .../log4j/plugins/di/spi/BeanInfoService.java      |  52 ++++
 .../plugins/name/AnnotatedElementNameProvider.java |   2 +-
 .../log4j/plugins/name/NamedAliasesProvider.java   |   2 +-
 ...erNameProvider.java => PluginNameProvider.java} |   9 +-
 .../log4j/plugins/processor/BeanProcessor.java     | 342 +++++++++++++++++++++
 .../log4j/plugins/processor/PluginProcessor.java   |  14 +-
 .../log4j/plugins/processor/PluginService.java     |   4 +-
 .../logging/log4j/plugins/util/AnnotationUtil.java |  10 +-
 log4j-plugins/src/main/java9/module-info.java      |   9 +-
 .../services/javax.annotation.processing.Processor |  18 ++
 .../log4j/plugins/test/validation/ExampleBean.java |  36 ++-
 .../plugins/test/validation/ImplicitBean.java}     |  30 +-
 .../test/validation/ImplicitMethodBean.java}       |  39 ++-
 .../plugins/test/validation/ProductionBean.java    |  56 ++++
 .../log4j/plugins/processor/BeanProcessorTest.java |  54 ++++
 log4j-plugins/src/test/java9/module-info.java      |  20 +-
 46 files changed, 800 insertions(+), 184 deletions(-)
 delete mode 100644 log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/AnnotationAlias.java
 copy log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/{SingletonScoped.java => Producer.java} (87%)
 copy log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/{SingletonScoped.java => Qualifier.java} (87%)
 create mode 100644 log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/spi/BeanInfoService.java
 copy log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/{NamedQualifierNameProvider.java => PluginNameProvider.java} (74%)
 create mode 100644 log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/BeanProcessor.java
 copy log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataProvider.java => log4j-plugins/src/test/java-test/org/apache/logging/log4j/plugins/test/validation/ExampleBean.java (58%)
 copy log4j-plugins/src/{main/java/org/apache/logging/log4j/plugins/name/NamedQualifierNameProvider.java => test/java-test/org/apache/logging/log4j/plugins/test/validation/ImplicitBean.java} (59%)
 copy log4j-plugins/src/{main/java/org/apache/logging/log4j/plugins/name/NamedQualifierNameProvider.java => test/java-test/org/apache/logging/log4j/plugins/test/validation/ImplicitMethodBean.java} (53%)
 create mode 100644 log4j-plugins/src/test/java-test/org/apache/logging/log4j/plugins/test/validation/ProductionBean.java
 create mode 100644 log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/BeanProcessorTest.java

[logging-log4j2] 02/03: Improve docs

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 8000a004787b28f2c86fa7b3e1ad7479a836076b
Author: Matt Sicker <bo...@gmail.com>
AuthorDate: Sat Jul 10 18:59:19 2021 -0500

    Improve docs
---
 .../apache/logging/log4j/core/config/di/Bean.java  | 68 +++++++++++++++-------
 1 file changed, 48 insertions(+), 20 deletions(-)

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/Bean.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/Bean.java
index 4b718ca..37c8795 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/Bean.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/Bean.java
@@ -24,31 +24,29 @@ import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 import java.util.Collection;
 
+/**
+ * Provides lifecycle and dependency injection functionality to managed classes. A bean represents an injectable class
+ * via {@link org.apache.logging.log4j.plugins.di.Inject} or a producer field or method via
+ * {@link org.apache.logging.log4j.plugins.di.Produces} along with their annotation aliases. A bean has a
+ * {@linkplain #getName() name} which can be the empty string to indicate a default bean. Beans provide a
+ * {@linkplain #getTypes() type closure} of matching generic types to allow for injecting more complex types. The
+ * {@linkplain #getScopeType() scope} of a bean controls the lifecycle of instances
+ * {@linkplain #create(InitializationContext) created} and {@linkplain #destroy(Object, InitializationContext) destroyed}
+ * by this bean. Dependencies are injected based on metadata exposed through
+ * {@linkplain #getInjectionPoints() injection points}.
+ *
+ * @param <T> type of instance being managed by this bean
+ */
 public interface Bean<T> {
+
     /**
-     * Creates a new instance of this bean. The given {@link InitializationContext} should be used by implementations
-     * to track dependent objects.
-     *
-     * @param context the context in which the instance is being managed
-     * @return a managed, initialized instance
+     * Returns the name of this bean or an empty string to indicate a default bean.
      */
-    T create(final InitializationContext<T> context);
+    String getName();
 
     /**
-     * Destroys a managed instance in the given context. Implementations should call {@link InitializationContext#close()} to
-     * allow dependent objects to be destroyed.
-     *
-     * @param instance the managed instance to destroy
-     * @param context  the context in which the instance is being managed
+     * Returns the type closure of this bean.
      */
-    void destroy(final T instance, final InitializationContext<T> context);
-
-    Collection<InjectionPoint> getInjectionPoints();
-
-    // for a managed bean: that class
-    // for a producer field or producer method: the declaring class
-    Class<?> getDeclaringClass();
-
     Collection<Type> getTypes();
 
     default boolean hasMatchingType(final Type requiredType) {
@@ -60,11 +58,41 @@ public interface Bean<T> {
         return false;
     }
 
-    String getName();
+    /**
+     * Returns the declaring class that creates this bean. For injectable classes, this returns that class. For producing
+     * methods and fields, this returns their declaring class.
+     */
+    Class<?> getDeclaringClass();
 
+    /**
+     * Returns the scope type of this bean.
+     */
     Class<? extends Annotation> getScopeType();
 
     default boolean isDependentScoped() {
         return getScopeType() == DependentScoped.class;
     }
+
+    /**
+     * Creates a new instance of this bean. The given {@link InitializationContext} should be used by implementations
+     * to track dependent objects.
+     *
+     * @param context the context in which the instance is being managed
+     * @return a managed, initialized instance
+     */
+    T create(final InitializationContext<T> context);
+
+    /**
+     * Destroys a managed instance in the given context. Implementations should call {@link InitializationContext#close()} to
+     * allow dependent objects to be destroyed.
+     *
+     * @param instance the managed instance to destroy
+     * @param context  the context in which the instance is being managed
+     */
+    void destroy(final T instance, final InitializationContext<T> context);
+
+    /**
+     * Returns the collection of injection points to inject dependencies when constructing instances of this bean.
+     */
+    Collection<InjectionPoint> getInjectionPoints();
 }

[logging-log4j2] 03/03: Add foundation for bean annotation processing and plugin metadata

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 7ff8c9cd05413ed4ac54bd4f2e79481aa29070f4
Author: Matt Sicker <bo...@gmail.com>
AuthorDate: Sat Jul 10 19:54:19 2021 -0500

    Add foundation for bean annotation processing and plugin metadata
---
 log4j-core/pom.xml                                 |   1 +
 .../logging/log4j/core/config/di/BeanManager.java  |  70 +++--
 .../core/config/di/impl/DefaultBeanManager.java    |  10 +-
 .../config/di/impl/DefaultInjectionTarget.java     |   6 +-
 .../di/impl/DefaultInjectionTargetFactory.java     |  10 +-
 .../log4j/core/config/di/impl/Injector.java        |   3 +-
 .../log4j/core/config/plugins/PluginAttribute.java |   2 +
 .../config/plugins/PluginBuilderAttribute.java     |   2 +
 .../core/config/plugins/PluginBuilderFactory.java  |   9 +-
 .../core/config/plugins/PluginConfiguration.java   |   2 +
 .../log4j/core/config/plugins/PluginElement.java   |   2 +
 .../log4j/core/config/plugins/PluginFactory.java   |   9 +-
 .../log4j/core/config/plugins/PluginNode.java      |   2 +
 .../log4j/core/config/plugins/PluginValue.java     |   2 +
 log4j-plugins/pom.xml                              |  14 +-
 .../org/apache/logging/log4j/plugins/Plugin.java   |   3 +
 .../logging/log4j/plugins/PluginAliases.java       |   2 +
 .../logging/log4j/plugins/PluginAttribute.java     |   2 +
 .../log4j/plugins/PluginBuilderAttribute.java      |   2 +
 .../logging/log4j/plugins/PluginElement.java       |   2 +
 .../logging/log4j/plugins/PluginFactory.java       |   3 +
 .../apache/logging/log4j/plugins/PluginNode.java   |   2 +
 .../apache/logging/log4j/plugins/PluginValue.java  |   2 +
 .../org/apache/logging/log4j/plugins/di/Named.java |   1 +
 .../logging/log4j/plugins/di/NamedAliases.java     |   1 +
 .../di/{AnnotationAlias.java => Producer.java}     |  12 +-
 .../apache/logging/log4j/plugins/di/Produces.java  |   3 +-
 .../plugins/di/{Named.java => Qualifier.java}      |  13 +-
 .../log4j/plugins/di/spi/BeanInfoService.java      |  52 ++++
 .../log4j/plugins/name/NamedAliasesProvider.java   |   2 +-
 .../log4j/plugins/name/PluginNameProvider.java     |  20 +-
 .../log4j/plugins/processor/BeanProcessor.java     | 342 +++++++++++++++++++++
 .../log4j/plugins/processor/PluginProcessor.java   |  14 +-
 .../log4j/plugins/processor/PluginService.java     |   4 +-
 .../logging/log4j/plugins/util/AnnotationUtil.java |  10 +-
 log4j-plugins/src/main/java9/module-info.java      |   9 +-
 .../services/javax.annotation.processing.Processor |  18 ++
 .../plugins/test/validation/ExampleBean.java}      |  38 ++-
 .../plugins/test/validation/ImplicitBean.java}     |  37 ++-
 .../test/validation/ImplicitMethodBean.java}       |  45 ++-
 .../plugins/test/validation/ProductionBean.java    |  56 ++++
 .../log4j/plugins/processor/BeanProcessorTest.java |  54 ++++
 log4j-plugins/src/test/java9/module-info.java      |  20 +-
 43 files changed, 759 insertions(+), 154 deletions(-)

diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml
index 0d5c9c9..8402405 100644
--- a/log4j-core/pom.xml
+++ b/log4j-core/pom.xml
@@ -330,6 +330,7 @@
                   <includes>
                     <include>module-info.class</include>
                     <include>**/Log4jPlugins.class</include>
+                    <include>**/Log4jBeanInfo.class</include>
                   </includes>
                 </fileset>
                 <fileset>
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/BeanManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/BeanManager.java
index 4e35ae6..3168e1b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/BeanManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/BeanManager.java
@@ -18,9 +18,9 @@
 package org.apache.logging.log4j.core.config.di;
 
 import org.apache.logging.log4j.plugins.di.Inject;
-import org.apache.logging.log4j.plugins.di.Produces;
+import org.apache.logging.log4j.plugins.di.Producer;
+import org.apache.logging.log4j.plugins.di.Qualifier;
 import org.apache.logging.log4j.plugins.name.AnnotatedElementNameProvider;
-import org.apache.logging.log4j.plugins.name.NameProvider;
 import org.apache.logging.log4j.plugins.util.AnnotationUtil;
 import org.apache.logging.log4j.util.Strings;
 
@@ -106,7 +106,7 @@ public interface BeanManager extends AutoCloseable {
      * Checks if a class has exactly one injectable constructor. A constructor is <i>injectable</i> if:
      * <ol>
      *     <li>it is annotated with {@link Inject}; or</li>
-     *     <li>it has as least one parameter annotated with {@link Inject} or a {@linkplain NameProvider name provider annotation}; or</li>
+     *     <li>it has as least one parameter annotated with a {@linkplain Qualifier qualifier annotation}; or</li>
      *     <li>it is the lone no-arg constructor.</li>
      * </ol>
      *
@@ -114,60 +114,60 @@ public interface BeanManager extends AutoCloseable {
      * @return true if the class has exactly one injectable constructor or false otherwise
      */
     default boolean isInjectable(final Class<?> type) {
+        boolean result = false;
         int injectConstructors = 0;
         final Constructor<?>[] constructors = type.getDeclaredConstructors();
         for (final Constructor<?> constructor : constructors) {
-            if (AnnotationUtil.isAnnotationPresent(constructor, Inject.class)) {
+            if (constructor.isAnnotationPresent(Inject.class)) {
                 injectConstructors++;
             }
         }
-        if (injectConstructors > 1) {
-            return false;
-        }
-        if (injectConstructors == 1) {
-            return true;
-        }
-
-        int implicitConstructors = 0;
-        for (final Constructor<?> constructor : constructors) {
-            for (final Parameter parameter : constructor.getParameters()) {
-                if (isInjectable(parameter)) {
-                    implicitConstructors++;
-                    break;
+        if (injectConstructors <= 1) {
+            if (injectConstructors == 1) {
+                result = true;
+            } else {
+                int implicitConstructors = 0;
+                for (final Constructor<?> constructor : constructors) {
+                    for (final Parameter parameter : constructor.getParameters()) {
+                        if (AnnotatedElementNameProvider.hasName(parameter)) {
+                            implicitConstructors++;
+                            break;
+                        }
+                    }
+                }
+                if (implicitConstructors <= 1) {
+                    if (implicitConstructors == 1) {
+                        result = true;
+                    } else {
+                        try {
+                            type.getDeclaredConstructor();
+                            result = true;
+                        } catch (final NoSuchMethodException ignored) {
+                        }
+                    }
                 }
             }
         }
-        if (implicitConstructors > 1) {
-            return false;
-        }
-        if (implicitConstructors == 1) {
-            return true;
-        }
 
-        try {
-            type.getDeclaredConstructor();
-            return true;
-        } catch (final NoSuchMethodException ignored) {
-            return false;
-        }
+        return result;
     }
 
     /**
      * Checks if an element is injectable. An element is <i>injectable</i> if:
      * <ol>
      *     <li>it is annotated with {@link Inject}; or</li>
-     *     <li>it is annotated with a {@linkplain NameProvider name provider annotation} and is not annotated
-     *     with {@link Produces}.</li>
+     *     <li>it is annotated with a {@linkplain Qualifier qualifier annotation}
+     *     and is not annotated with a {@link Producer} annotation.</li>
      * </ol>
      *
      * @param element field, method, or parameter to check
      * @return true if the element is injectable or false otherwise
      */
     default boolean isInjectable(final AnnotatedElement element) {
-        if (AnnotationUtil.isAnnotationPresent(element, Inject.class)) {
+        if (element.isAnnotationPresent(Inject.class)) {
             return true;
         }
-        if (AnnotationUtil.isAnnotationPresent(element, Produces.class)) {
+        if (AnnotationUtil.isMetaAnnotationPresent(element, Producer.class)) {
             return false;
         }
         return AnnotatedElementNameProvider.hasName(element);
@@ -258,4 +258,8 @@ public interface BeanManager extends AutoCloseable {
     // TODO: integrate with TypeConverters
     // TODO: need some sort of default value strategy to bridge over @PluginAttribute and optional injected values
     // TODO: add support for injecting collections and arrays
+    // TODO: begin integrating with singleton beans in log4j-core
+    // TODO: LoggerContext scope (sort of like a singleton/application scope with each LoggerContext)
+    // TODO: configuration scope? should be similar to LoggerContext scope but can be restarted/reconfigured at runtime
+    // TODO: update annotation processor to output bean descriptors for lazy loading (attempt to provide partial type closures?)
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/DefaultBeanManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/DefaultBeanManager.java
index a835ae0..7dc6921 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/DefaultBeanManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/DefaultBeanManager.java
@@ -32,7 +32,7 @@ import org.apache.logging.log4j.core.config.di.UnsatisfiedBeanException;
 import org.apache.logging.log4j.core.config.di.ValidationException;
 import org.apache.logging.log4j.plugins.di.DependentScoped;
 import org.apache.logging.log4j.plugins.di.Disposes;
-import org.apache.logging.log4j.plugins.di.Produces;
+import org.apache.logging.log4j.plugins.di.Producer;
 import org.apache.logging.log4j.plugins.di.Provider;
 import org.apache.logging.log4j.plugins.di.ScopeType;
 import org.apache.logging.log4j.plugins.di.SingletonScoped;
@@ -88,7 +88,7 @@ public class DefaultBeanManager implements BeanManager {
             loadDisposerMethods(beanClass, bean);
             for (Class<?> clazz = beanClass; clazz != null; clazz = clazz.getSuperclass()) {
                 for (final Method method : clazz.getDeclaredMethods()) {
-                    if (AnnotationUtil.isAnnotationPresent(method, Produces.class)) {
+                    if (AnnotationUtil.isMetaAnnotationPresent(method, Producer.class)) {
                         method.setAccessible(true);
                         loadedBeans.add(createBean(method, bean));
                     }
@@ -96,7 +96,7 @@ public class DefaultBeanManager implements BeanManager {
             }
             for (Class<?> clazz = beanClass; clazz != null; clazz = clazz.getSuperclass()) {
                 for (final Field field : clazz.getDeclaredFields()) {
-                    if (AnnotationUtil.isAnnotationPresent(field, Produces.class)) {
+                    if (AnnotationUtil.isMetaAnnotationPresent(field, Producer.class)) {
                         field.setAccessible(true);
                         loadedBeans.add(createBean(field, bean));
                     }
@@ -173,7 +173,7 @@ public class DefaultBeanManager implements BeanManager {
     private void loadDisposerMethods(final Class<?> beanClass, final Bean<?> bean) {
         for (final Method method : beanClass.getDeclaredMethods()) {
             for (final Parameter parameter : method.getParameters()) {
-                if (AnnotationUtil.isAnnotationPresent(parameter, Disposes.class)) {
+                if (parameter.isAnnotationPresent(Disposes.class)) {
                     final String name = AnnotatedElementNameProvider.getName(parameter);
                     final Collection<String> aliases = AnnotatedElementAliasesProvider.getAliases(parameter);
                     method.setAccessible(true);
@@ -217,7 +217,7 @@ public class DefaultBeanManager implements BeanManager {
     @Override
     public void validateInjectionPoint(final InjectionPoint point) {
         final AnnotatedElement element = point.getElement();
-        if (AnnotationUtil.isAnnotationPresent(element, Produces.class)) {
+        if (AnnotationUtil.isMetaAnnotationPresent(element, Producer.class)) {
             throw new DefinitionException("Cannot inject into a @Produces element: " + element);
         }
         final Type type = point.getType();
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/DefaultInjectionTarget.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/DefaultInjectionTarget.java
index a6ebed9..46eaad9 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/DefaultInjectionTarget.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/DefaultInjectionTarget.java
@@ -23,7 +23,7 @@ import org.apache.logging.log4j.core.config.di.InjectionPoint;
 import org.apache.logging.log4j.core.config.di.InjectionTarget;
 import org.apache.logging.log4j.plugins.di.Disposes;
 import org.apache.logging.log4j.plugins.di.Inject;
-import org.apache.logging.log4j.plugins.di.Produces;
+import org.apache.logging.log4j.plugins.di.Producer;
 import org.apache.logging.log4j.plugins.util.AnnotationUtil;
 import org.apache.logging.log4j.plugins.util.TypeUtil;
 
@@ -86,8 +86,8 @@ class DefaultInjectionTarget<T> implements InjectionTarget<T> {
             final Member member = point.getMember();
             final AnnotatedElement element = point.getElement();
             if (member instanceof Method && !injectedMethods.contains(member) &&
-                    !AnnotationUtil.isAnnotationPresent(element, Produces.class) &&
-                    !AnnotationUtil.isAnnotationPresent(element, Disposes.class)) {
+                    !AnnotationUtil.isMetaAnnotationPresent(element, Producer.class) &&
+                    !element.isAnnotationPresent(Disposes.class)) {
                 final Method method = TypeUtil.cast(member);
                 final Set<InjectionPoint> methodInjectionPoints = injectionPoints.stream()
                         .filter(p -> method.equals(p.getMember()))
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/DefaultInjectionTargetFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/DefaultInjectionTargetFactory.java
index 4d99fd7..d3ed010 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/DefaultInjectionTargetFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/DefaultInjectionTargetFactory.java
@@ -26,7 +26,7 @@ import org.apache.logging.log4j.core.config.di.InjectionTargetFactory;
 import org.apache.logging.log4j.plugins.di.Inject;
 import org.apache.logging.log4j.plugins.di.PostConstruct;
 import org.apache.logging.log4j.plugins.di.PreDestroy;
-import org.apache.logging.log4j.plugins.util.AnnotationUtil;
+import org.apache.logging.log4j.plugins.name.AnnotatedElementNameProvider;
 import org.apache.logging.log4j.plugins.util.TypeUtil;
 
 import java.lang.reflect.AccessibleObject;
@@ -67,7 +67,7 @@ class DefaultInjectionTargetFactory<T> implements InjectionTargetFactory<T> {
     private Constructor<T> getInjectableConstructor() {
         final Constructor<?>[] allConstructors = type.getDeclaredConstructors();
         final List<Constructor<?>> injectConstructors = Arrays.stream(allConstructors)
-                .filter(constructor -> AnnotationUtil.isAnnotationPresent(constructor, Inject.class))
+                .filter(constructor -> constructor.isAnnotationPresent(Inject.class))
                 .collect(Collectors.toList());
         if (injectConstructors.size() > 1) {
             throw new DefinitionException("Found more than one constructor with @Inject for " + type);
@@ -78,7 +78,7 @@ class DefaultInjectionTargetFactory<T> implements InjectionTargetFactory<T> {
             return TypeUtil.cast(constructor);
         }
         final List<Constructor<?>> injectParameterConstructors = Arrays.stream(allConstructors)
-                .filter(constructor -> Arrays.stream(constructor.getParameters()).anyMatch(beanManager::isInjectable))
+                .filter(constructor -> Arrays.stream(constructor.getParameters()).anyMatch(AnnotatedElementNameProvider::hasName))
                 .collect(Collectors.toList());
         if (injectParameterConstructors.size() > 1) {
             throw new DefinitionException("No @Inject constructors found and remaining constructors ambiguous for " + type);
@@ -134,7 +134,7 @@ class DefaultInjectionTargetFactory<T> implements InjectionTargetFactory<T> {
         final List<Method> postConstructMethods = new ArrayList<>();
         for (Class<?> clazz = type; clazz != null; clazz = clazz.getSuperclass()) {
             for (final Method method : clazz.getDeclaredMethods()) {
-                if (AnnotationUtil.isAnnotationPresent(method, PostConstruct.class)) {
+                if (method.isAnnotationPresent(PostConstruct.class)) {
                     postConstructMethods.add(0, method);
                 }
             }
@@ -148,7 +148,7 @@ class DefaultInjectionTargetFactory<T> implements InjectionTargetFactory<T> {
         final List<Method> preDestroyMethods = new ArrayList<>();
         for (Class<?> clazz = type; clazz != null; clazz = clazz.getSuperclass()) {
             for (final Method method : clazz.getDeclaredMethods()) {
-                if (AnnotationUtil.isAnnotationPresent(method, PreDestroy.class)) {
+                if (method.isAnnotationPresent(PreDestroy.class)) {
                     preDestroyMethods.add(method);
                 }
             }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/Injector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/Injector.java
index e29b6ad..eff10f4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/Injector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/di/impl/Injector.java
@@ -22,7 +22,6 @@ import org.apache.logging.log4j.core.config.di.InitializationContext;
 import org.apache.logging.log4j.core.config.di.InitializationException;
 import org.apache.logging.log4j.core.config.di.InjectionPoint;
 import org.apache.logging.log4j.plugins.di.Disposes;
-import org.apache.logging.log4j.plugins.util.AnnotationUtil;
 import org.apache.logging.log4j.plugins.util.TypeUtil;
 
 import java.lang.reflect.Constructor;
@@ -96,7 +95,7 @@ public class Injector {
         final Object[] arguments = new Object[parameters.length];
         for (int i = 0; i < parameters.length; i++) {
             final Parameter parameter = parameters[i];
-            if (AnnotationUtil.isAnnotationPresent(parameter, Disposes.class)) {
+            if (parameter.isAnnotationPresent(Disposes.class)) {
                 arguments[i] = producedInstance;
             } else {
                 final InjectionPoint injectionPoint = injectionPoints.stream()
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
index a4d62d3..843564f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.config.plugins;
 
 import org.apache.logging.log4j.core.config.plugins.util.PluginAttributeNameProvider;
 import org.apache.logging.log4j.core.config.plugins.visitors.PluginAttributeVisitor;
+import org.apache.logging.log4j.plugins.di.Qualifier;
 import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 import org.apache.logging.log4j.plugins.name.NameProvider;
 import org.apache.logging.log4j.util.Strings;
@@ -41,6 +42,7 @@ import java.lang.annotation.Target;
 @Target({ElementType.PARAMETER, ElementType.FIELD})
 @InjectorStrategy(PluginAttributeVisitor.class)
 @NameProvider(PluginAttributeNameProvider.class)
+@Qualifier
 public @interface PluginAttribute {
 
     /**
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
index a7b4a8b..97b4f1b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.config.plugins;
 
 import org.apache.logging.log4j.core.config.plugins.util.PluginBuilderAttributeNameProvider;
 import org.apache.logging.log4j.core.config.plugins.visitors.PluginBuilderAttributeVisitor;
+import org.apache.logging.log4j.plugins.di.Qualifier;
 import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 import org.apache.logging.log4j.plugins.name.NameProvider;
 import org.apache.logging.log4j.util.Strings;
@@ -38,6 +39,7 @@ import java.lang.annotation.Target;
 @Target({ElementType.PARAMETER, ElementType.FIELD})
 @InjectorStrategy(PluginBuilderAttributeVisitor.class)
 @NameProvider(PluginBuilderAttributeNameProvider.class)
+@Qualifier
 public @interface PluginBuilderAttribute {
 
     /**
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
index 0ea7221..11b2955 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
@@ -17,7 +17,13 @@
 
 package org.apache.logging.log4j.core.config.plugins;
 
-import java.lang.annotation.*;
+import org.apache.logging.log4j.plugins.di.Produces;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
  * Marks a method as a factory for custom Plugin builders.
@@ -26,6 +32,7 @@ import java.lang.annotation.*;
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.METHOD)
+@Produces
 public @interface PluginBuilderFactory {
     // empty
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginConfiguration.java
index dee6f67..e9bc4c5 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginConfiguration.java
@@ -17,6 +17,7 @@
 package org.apache.logging.log4j.core.config.plugins;
 
 import org.apache.logging.log4j.core.config.plugins.inject.PluginConfigurationInjector;
+import org.apache.logging.log4j.plugins.di.Qualifier;
 import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 
 import java.lang.annotation.Documented;
@@ -34,6 +35,7 @@ import java.lang.annotation.Target;
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
 @InjectorStrategy(PluginConfigurationInjector.class)
+@Qualifier
 public @interface PluginConfiguration {
     // empty
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
index b832da9..70b2d9e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.config.plugins;
 
 import org.apache.logging.log4j.core.config.plugins.util.PluginElementNameProvider;
 import org.apache.logging.log4j.core.config.plugins.visitors.PluginElementVisitor;
+import org.apache.logging.log4j.plugins.di.Qualifier;
 import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 import org.apache.logging.log4j.plugins.name.NameProvider;
 
@@ -36,6 +37,7 @@ import java.lang.annotation.Target;
 @Target({ElementType.PARAMETER, ElementType.FIELD})
 @InjectorStrategy(PluginElementVisitor.class)
 @NameProvider(PluginElementNameProvider.class)
+@Qualifier
 public @interface PluginElement {
 
     /**
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
index 2e25631..abe1cf4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
@@ -16,7 +16,13 @@
  */
 package org.apache.logging.log4j.core.config.plugins;
 
-import java.lang.annotation.*;
+import org.apache.logging.log4j.plugins.di.Produces;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
  * Identifies a Method as the factory to create the plugin. This annotation should only be used on a {@code static}
@@ -29,6 +35,7 @@ import java.lang.annotation.*;
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.METHOD)
+@Produces
 public @interface PluginFactory {
     // empty
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
index 14a136c..7765a4b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
@@ -17,6 +17,7 @@
 package org.apache.logging.log4j.core.config.plugins;
 
 import org.apache.logging.log4j.core.config.plugins.visitors.PluginNodeVisitor;
+import org.apache.logging.log4j.plugins.di.Qualifier;
 import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 
 import java.lang.annotation.Documented;
@@ -33,6 +34,7 @@ import java.lang.annotation.Target;
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.FIELD})
 @InjectorStrategy(PluginNodeVisitor.class)
+@Qualifier
 public @interface PluginNode {
     // empty
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
index bcbadc0..0e925d0 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.config.plugins;
 
 import org.apache.logging.log4j.core.config.plugins.util.PluginValueNameProvider;
 import org.apache.logging.log4j.core.config.plugins.visitors.PluginValueVisitor;
+import org.apache.logging.log4j.plugins.di.Qualifier;
 import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 import org.apache.logging.log4j.plugins.name.NameProvider;
 
@@ -39,6 +40,7 @@ import java.lang.annotation.Target;
 @Target({ElementType.PARAMETER, ElementType.FIELD})
 @InjectorStrategy(PluginValueVisitor.class)
 @NameProvider(PluginValueNameProvider.class)
+@Qualifier
 public @interface PluginValue {
 
     String value();
diff --git a/log4j-plugins/pom.xml b/log4j-plugins/pom.xml
index a78d381..c562089 100644
--- a/log4j-plugins/pom.xml
+++ b/log4j-plugins/pom.xml
@@ -105,6 +105,7 @@
                   <includes>
                     <include>module-info.class</include>
                     <include>**/Log4jPlugins.class</include>
+                    <include>**/Log4jBeanInfo.class</include>
                   </includes>
                 </fileset>
                 <fileset>
@@ -142,9 +143,11 @@
               <source>${maven.compiler.source}</source>
               <target>${maven.compiler.target}</target>
               <proc>only</proc>
-              <compilerArguments>
-                <processor>org.apache.logging.log4j.plugins.processor.PluginProcessor</processor>
-              </compilerArguments>
+              <annotationProcessors>
+                <annotationProcessor>org.apache.logging.log4j.plugins.processor.PluginProcessor</annotationProcessor>
+                <annotationProcessor>org.apache.logging.log4j.plugins.processor.BeanProcessor</annotationProcessor>
+              </annotationProcessors>
+              <parameters>true</parameters>
             </configuration>
           </execution>
           <execution>
@@ -160,6 +163,7 @@
               <proc>only</proc>
               <annotationProcessors>
                 <annotationProcessor>org.apache.logging.log4j.plugins.processor.PluginProcessor</annotationProcessor>
+                <annotationProcessor>org.apache.logging.log4j.plugins.processor.BeanProcessor</annotationProcessor>
               </annotationProcessors>
               <compileSourceRoots>
                 <compileSourceRoot>${project.basedir}/src/test/java-test</compileSourceRoot>
@@ -180,7 +184,11 @@
               <proc>only</proc>
               <annotationProcessors>
                 <annotationProcessor>org.apache.logging.log4j.plugins.processor.PluginProcessor</annotationProcessor>
+                <annotationProcessor>org.apache.logging.log4j.plugins.processor.BeanProcessor</annotationProcessor>
               </annotationProcessors>
+              <compilerArguments>
+                <ApluginPackage>org.apache.logging.log4j.plugins</ApluginPackage>
+              </compilerArguments>
               <compileSourceRoots>
                 <compileSourceRoot>${project.basedir}/src/test/java</compileSourceRoot>
                 <compileSourceRoot>${project.basedir}/src/test/java-test</compileSourceRoot>
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
index 18f04ee..9ef058c 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
@@ -16,6 +16,8 @@
  */
 package org.apache.logging.log4j.plugins;
 
+import org.apache.logging.log4j.plugins.name.NameProvider;
+import org.apache.logging.log4j.plugins.name.PluginNameProvider;
 import org.apache.logging.log4j.util.Strings;
 
 import java.lang.annotation.Documented;
@@ -30,6 +32,7 @@ import java.lang.annotation.Target;
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.TYPE)
+@NameProvider(PluginNameProvider.class)
 public @interface Plugin {
 
     /**
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
index 07acea7..e3f41c8 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.plugins;
 
+import org.apache.logging.log4j.plugins.di.Qualifier;
 import org.apache.logging.log4j.plugins.name.AliasesProvider;
 import org.apache.logging.log4j.plugins.name.PluginAliasesProvider;
 
@@ -33,6 +34,7 @@ import java.lang.annotation.Target;
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
 @AliasesProvider(PluginAliasesProvider.class)
+@Qualifier
 public @interface PluginAliases {
 
     /**
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
index d844d02..4b5c9f0 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.plugins;
 
+import org.apache.logging.log4j.plugins.di.Qualifier;
 import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 import org.apache.logging.log4j.plugins.inject.PluginAttributeInjector;
 import org.apache.logging.log4j.plugins.name.NameProvider;
@@ -47,6 +48,7 @@ import java.lang.annotation.Target;
 @Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
 @InjectorStrategy(PluginAttributeInjector.class)
 @NameProvider(PluginAttributeNameProvider.class)
+@Qualifier
 public @interface PluginAttribute {
 
     /**
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
index a0a39b5..2eebabe 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
@@ -17,6 +17,7 @@
 
 package org.apache.logging.log4j.plugins;
 
+import org.apache.logging.log4j.plugins.di.Qualifier;
 import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 import org.apache.logging.log4j.plugins.inject.PluginBuilderAttributeInjector;
 import org.apache.logging.log4j.plugins.name.NameProvider;
@@ -39,6 +40,7 @@ import java.lang.annotation.Target;
 @Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.TYPE})
 @InjectorStrategy(PluginBuilderAttributeInjector.class)
 @NameProvider(PluginBuilderAttributeNameProvider.class)
+@Qualifier
 @Deprecated
 public @interface PluginBuilderAttribute {
 
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
index fa296ca..6951de1 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.plugins;
 
+import org.apache.logging.log4j.plugins.di.Qualifier;
 import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 import org.apache.logging.log4j.plugins.inject.PluginElementInjector;
 import org.apache.logging.log4j.plugins.name.NameProvider;
@@ -38,6 +39,7 @@ import java.lang.annotation.Target;
 @Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
 @InjectorStrategy(PluginElementInjector.class)
 @NameProvider(PluginElementNameProvider.class)
+@Qualifier
 public @interface PluginElement {
 
     /**
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
index f1d89c6..f32bc38 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
@@ -16,6 +16,8 @@
  */
 package org.apache.logging.log4j.plugins;
 
+import org.apache.logging.log4j.plugins.di.Producer;
+
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -37,6 +39,7 @@ import java.lang.annotation.Target;
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.METHOD)
+@Producer
 public @interface PluginFactory {
     // empty
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
index dcc5b0c..eec9d8f 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.plugins;
 
+import org.apache.logging.log4j.plugins.di.Qualifier;
 import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 import org.apache.logging.log4j.plugins.inject.PluginNodeInjector;
 
@@ -34,6 +35,7 @@ import java.lang.annotation.Target;
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
 @InjectorStrategy(PluginNodeInjector.class)
+@Qualifier
 public @interface PluginNode {
     // empty
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
index 5e7a3fe..b320306 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.plugins;
 
+import org.apache.logging.log4j.plugins.di.Qualifier;
 import org.apache.logging.log4j.plugins.inject.InjectorStrategy;
 import org.apache.logging.log4j.plugins.inject.PluginValueInjector;
 import org.apache.logging.log4j.plugins.name.NameProvider;
@@ -42,6 +43,7 @@ import java.lang.annotation.Target;
 @Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
 @InjectorStrategy(PluginValueInjector.class)
 @NameProvider(PluginValueNameProvider.class)
+@Qualifier
 public @interface PluginValue {
 
     /**
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Named.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Named.java
index 0c7a542..b8b48d4 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Named.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Named.java
@@ -30,6 +30,7 @@ import java.lang.annotation.RetentionPolicy;
 @Documented
 @NameProvider(NamedQualifierNameProvider.class)
 @Repeatable(NamedAliases.class)
+@Qualifier
 public @interface Named {
     String value() default Strings.EMPTY;
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/NamedAliases.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/NamedAliases.java
index 6903d2b..94adf0c 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/NamedAliases.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/NamedAliases.java
@@ -32,6 +32,7 @@ import java.lang.annotation.Target;
 @Documented
 @NameProvider(NamedAliasesProvider.class)
 @AliasesProvider(NamedAliasesProvider.class)
+@Qualifier
 public @interface NamedAliases {
     Named[] value();
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/AnnotationAlias.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Producer.java
similarity index 70%
rename from log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/AnnotationAlias.java
rename to log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Producer.java
index d570c3b..286723f 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/AnnotationAlias.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Producer.java
@@ -17,22 +17,14 @@
 
 package org.apache.logging.log4j.plugins.di;
 
-import java.lang.annotation.Annotation;
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-/**
- * Meta annotation for making an annotation an alias for another annotation. Annotations with this annotation will be
- * interpreted as if they were implemented by the given annotation type instead. This applies to
- * {@linkplain ScopeType scopes}, {@link Inject}, {@link Produces}, {@link Disposes}, {@link PostConstruct}, and
- * {@link PreDestroy}.
- */
-@Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.ANNOTATION_TYPE)
+@Retention(RetentionPolicy.RUNTIME)
 @Documented
-public @interface AnnotationAlias {
-    Class<? extends Annotation> value();
+public @interface Producer {
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Produces.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Produces.java
index ba641dd..2739193 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Produces.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Produces.java
@@ -45,8 +45,9 @@ import java.lang.annotation.Target;
  * @see <a href="https://docs.jboss.org/cdi/api/2.0/javax/enterprise/inject/Produces.html">CDI @Produces API Docs</a>
  * @see <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html">Spring @Bean API Docs</a>
  */
-@Target({ElementType.METHOD, ElementType.FIELD})
+@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
+@Producer
 public @interface Produces {
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Named.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Qualifier.java
similarity index 73%
copy from log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Named.java
copy to log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Qualifier.java
index 0c7a542..85bbbb0 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Named.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Qualifier.java
@@ -17,19 +17,14 @@
 
 package org.apache.logging.log4j.plugins.di;
 
-import org.apache.logging.log4j.plugins.name.NameProvider;
-import org.apache.logging.log4j.plugins.name.NamedQualifierNameProvider;
-import org.apache.logging.log4j.util.Strings;
-
 import java.lang.annotation.Documented;
-import java.lang.annotation.Repeatable;
+import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 @Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
 @Documented
-@NameProvider(NamedQualifierNameProvider.class)
-@Repeatable(NamedAliases.class)
-public @interface Named {
-    String value() default Strings.EMPTY;
+public @interface Qualifier {
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/spi/BeanInfoService.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/spi/BeanInfoService.java
new file mode 100644
index 0000000..f7f45e1
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/spi/BeanInfoService.java
@@ -0,0 +1,52 @@
+/*
+ * 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.spi;
+
+import java.util.List;
+import java.util.Map;
+
+public abstract class BeanInfoService {
+    private final List<String> injectableClassNames;
+    private final List<String> producibleClassNames;
+    private final List<String> destructibleClassNames;
+    private final Map<String, List<String>> pluginCategories;
+
+    protected BeanInfoService(final List<String> injectableClassNames, final List<String> producibleClassNames,
+                              final List<String> destructibleClassNames, final Map<String, List<String>> pluginCategories) {
+        this.injectableClassNames = injectableClassNames;
+        this.producibleClassNames = producibleClassNames;
+        this.destructibleClassNames = destructibleClassNames;
+        this.pluginCategories = pluginCategories;
+    }
+
+    public List<String> getInjectableClassNames() {
+        return injectableClassNames;
+    }
+
+    public List<String> getProducibleClassNames() {
+        return producibleClassNames;
+    }
+
+    public List<String> getDestructibleClassNames() {
+        return destructibleClassNames;
+    }
+
+    public Map<String, List<String>> getPluginCategories() {
+        return pluginCategories;
+    }
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/NamedAliasesProvider.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/NamedAliasesProvider.java
index a3e12c1..9471784 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/NamedAliasesProvider.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/NamedAliasesProvider.java
@@ -49,6 +49,6 @@ public class NamedAliasesProvider implements AnnotatedElementNameProvider<NamedA
         for (int i = 0; i < size; i++) {
             aliases.add(named[i + 1].value());
         }
-        return aliases;
+        return Collections.unmodifiableCollection(aliases);
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginNameProvider.java
similarity index 67%
copy from log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
copy to log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginNameProvider.java
index 0ea7221..7e71643 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/PluginNameProvider.java
@@ -15,17 +15,15 @@
  * limitations under the license.
  */
 
-package org.apache.logging.log4j.core.config.plugins;
+package org.apache.logging.log4j.plugins.name;
 
-import java.lang.annotation.*;
+import org.apache.logging.log4j.plugins.Plugin;
 
-/**
- * Marks a method as a factory for custom Plugin builders.
- * @deprecated Exists for compatibility with Log4j 2 2.x plugins. Not used for Log4j 2 3.x plugins.
- */
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-public @interface PluginBuilderFactory {
-    // empty
+import java.util.Optional;
+
+public class PluginNameProvider implements AnnotatedElementNameProvider<Plugin> {
+    @Override
+    public Optional<String> getSpecifiedName(final Plugin annotation) {
+        return Optional.of(annotation.name());
+    }
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/BeanProcessor.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/BeanProcessor.java
new file mode 100644
index 0000000..013bab6
--- /dev/null
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/BeanProcessor.java
@@ -0,0 +1,342 @@
+/*
+ * 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.processor;
+
+import org.apache.logging.log4j.plugins.di.Disposes;
+import org.apache.logging.log4j.plugins.di.Inject;
+import org.apache.logging.log4j.plugins.di.Producer;
+import org.apache.logging.log4j.plugins.di.Qualifier;
+import org.apache.logging.log4j.util.Strings;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedOptions;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.ElementKindVisitor9;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleAnnotationValueVisitor9;
+import javax.lang.model.util.Types;
+import javax.tools.FileObject;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardLocation;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.UncheckedIOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+// TODO: migrate to separate maven module between log4j-plugins and log4j-core
+@SupportedAnnotationTypes({"org.apache.logging.log4j.plugins.*", "org.apache.logging.log4j.core.config.plugins.*"})
+@SupportedOptions("pluginPackage")
+public class BeanProcessor extends AbstractProcessor {
+    public static final String BEAN_INFO_SERVICE_FILE = "META-INF/services/org.apache.logging.log4j.plugins.di.spi.BeanInfoService";
+
+    public BeanProcessor() {
+    }
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latestSupported();
+    }
+
+    private static class ProducerAnnotationVisitor extends ElementKindVisitor9<Void, Void> {
+        private final Set<ExecutableElement> producerMethods = new HashSet<>();
+        private final Set<VariableElement> producerFields = new HashSet<>();
+
+        @Override
+        public Void visitVariableAsField(final VariableElement e, final Void unused) {
+            producerFields.add(e);
+            return null;
+        }
+
+        @Override
+        public Void visitExecutableAsMethod(final ExecutableElement e, final Void unused) {
+            producerMethods.add(e);
+            return null;
+        }
+    }
+
+    private static class DisposesAnnotationVisitor extends ElementKindVisitor9<Void, Void> {
+        private final Set<ExecutableElement> disposesMethods = new HashSet<>();
+
+        @Override
+        public Void visitVariableAsParameter(final VariableElement e, final Void unused) {
+            disposesMethods.add((ExecutableElement) e.getEnclosingElement());
+            return null;
+        }
+    }
+
+    private static class InjectAnnotationVisitor extends ElementKindVisitor9<Void, Void> {
+        private final Set<TypeElement> injectableClasses = new HashSet<>();
+
+        @Override
+        public Void visitVariableAsField(final VariableElement e, final Void unused) {
+            injectableClasses.add((TypeElement) e.getEnclosingElement());
+            return null;
+        }
+
+        @Override
+        public Void visitExecutableAsConstructor(final ExecutableElement e, final Void unused) {
+            injectableClasses.add((TypeElement) e.getEnclosingElement());
+            return null;
+        }
+
+        @Override
+        public Void visitExecutableAsMethod(final ExecutableElement e, final Void unused) {
+            injectableClasses.add((TypeElement) e.getEnclosingElement());
+            return null;
+        }
+    }
+
+    private static class QualifiedAnnotationVisitor extends ElementKindVisitor9<Void, Void> {
+        private final Predicate<AnnotationMirror> isProducerAnnotation;
+        private final Set<TypeElement> injectableClasses = new HashSet<>();
+
+        private QualifiedAnnotationVisitor(final Predicate<AnnotationMirror> isProducerAnnotation) {
+            this.isProducerAnnotation = isProducerAnnotation;
+        }
+
+        @Override
+        public Void visitVariableAsField(final VariableElement e, final Void unused) {
+            if (e.getAnnotationMirrors().stream().noneMatch(isProducerAnnotation)) {
+                injectableClasses.add((TypeElement) e.getEnclosingElement());
+            }
+            return null;
+        }
+
+        @Override
+        public Void visitVariableAsParameter(final VariableElement e, final Void unused) {
+            final Element enclosingExecutable = e.getEnclosingElement();
+            final TypeElement typeElement = (TypeElement) enclosingExecutable.getEnclosingElement();
+            if (enclosingExecutable.getKind() == ElementKind.CONSTRUCTOR ||
+                    enclosingExecutable.getAnnotationMirrors().stream().noneMatch(isProducerAnnotation)) {
+                injectableClasses.add(typeElement);
+            }
+            return null;
+        }
+    }
+
+    private static class PluginAnnotationVisitor extends ElementKindVisitor9<Void, Void> {
+        private final Map<String, Set<TypeElement>> pluginCategories = new HashMap<>();
+
+        @Override
+        public Void visitTypeAsClass(final TypeElement e, final Void unused) {
+            final AnnotationMirror pluginAnnotation = e.getAnnotationMirrors()
+                    .stream()
+                    .filter(ann -> ann.getAnnotationType().asElement().getSimpleName().contentEquals("Plugin"))
+                    .findAny()
+                    .orElseThrow();
+            final ExecutableElement categoryKey = pluginAnnotation.getElementValues()
+                    .keySet()
+                    .stream()
+                    .filter(element -> element.getSimpleName().contentEquals("category"))
+                    .findAny()
+                    .orElseThrow();
+
+            final String category = pluginAnnotation.getElementValues()
+                    .get(categoryKey)
+                    .accept(new SimpleAnnotationValueVisitor9<String, Void>() {
+                        @Override
+                        public String visitString(final String s, final Void unused1) {
+                            return s;
+                        }
+                    }, null);
+            pluginCategories.computeIfAbsent(category, ignored -> new HashSet<>()).add(e);
+
+            return null;
+        }
+    }
+
+    @Override
+    public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
+        if (annotations.isEmpty()) {
+            return false;
+        }
+
+        final TypeElement[] producerAnnotations = annotations.stream()
+                .filter(e -> e.getAnnotation(Producer.class) != null)
+                .toArray(TypeElement[]::new);
+        final var producesAnnotationVisitor = new ProducerAnnotationVisitor();
+        roundEnv.getElementsAnnotatedWithAny(producerAnnotations).forEach(producesAnnotationVisitor::visit);
+
+        final var disposesAnnotationVisitor = new DisposesAnnotationVisitor();
+        roundEnv.getElementsAnnotatedWith(Disposes.class).forEach(disposesAnnotationVisitor::visit);
+
+        final var injectAnnotationVisitor = new InjectAnnotationVisitor();
+        roundEnv.getElementsAnnotatedWith(Inject.class).forEach(injectAnnotationVisitor::visit);
+
+        final Types types = processingEnv.getTypeUtils();
+        final var qualifiedAnnotationVisitor = new QualifiedAnnotationVisitor(annotationMirror -> {
+            for (final TypeElement producerAnnotation : producerAnnotations) {
+                if (types.isSameType(producerAnnotation.asType(), annotationMirror.getAnnotationType())) {
+                    return true;
+                }
+            }
+            return false;
+        });
+        final TypeElement[] qualifierAnnotations = annotations.stream()
+                .filter(e -> e.getAnnotation(Qualifier.class) != null)
+                .toArray(TypeElement[]::new);
+        roundEnv.getElementsAnnotatedWithAny(qualifierAnnotations).forEach(qualifiedAnnotationVisitor::visit);
+
+        final TypeElement[] pluginAnnotations = annotations.stream()
+                .filter(e -> e.getSimpleName().contentEquals("Plugin"))
+                .toArray(TypeElement[]::new);
+        final var pluginAnnotationVisitor = new PluginAnnotationVisitor();
+        roundEnv.getElementsAnnotatedWithAny(pluginAnnotations).forEach(pluginAnnotationVisitor::visit);
+
+        final Set<ExecutableElement> producerMethods = producesAnnotationVisitor.producerMethods;
+        final Set<VariableElement> producerFields = producesAnnotationVisitor.producerFields;
+        final Set<ExecutableElement> disposesMethods = disposesAnnotationVisitor.disposesMethods;
+        final Set<TypeElement> injectableClasses = injectAnnotationVisitor.injectableClasses;
+        final Set<TypeElement> implicitInjectableClasses = qualifiedAnnotationVisitor.injectableClasses;
+        final Map<String, Set<TypeElement>> pluginCategories = pluginAnnotationVisitor.pluginCategories;
+        final Set<PackageElement> packageElements = new HashSet<>();
+
+        final Elements elements = processingEnv.getElementUtils();
+        final Set<CharSequence> producibleClassNames = Stream.concat(
+                producerMethods.stream()
+                        .map(e -> (TypeElement) e.getEnclosingElement())
+                        .peek(e -> packageElements.add(elements.getPackageOf(e)))
+                        .map(elements::getBinaryName),
+                producerFields.stream()
+                        .map(e -> (TypeElement) e.getEnclosingElement())
+                        .peek(e -> packageElements.add(elements.getPackageOf(e)))
+                        .map(elements::getBinaryName))
+                .collect(Collectors.toSet());
+        final Set<CharSequence> destructibleClassNames = disposesMethods.stream()
+                .map(e -> (TypeElement) e.getEnclosingElement())
+                .peek(e -> packageElements.add(elements.getPackageOf(e)))
+                .map(elements::getBinaryName)
+                .collect(Collectors.toSet());
+        final Set<CharSequence> injectableClassNames = Stream.concat(
+                injectableClasses.stream()
+                        .peek(e -> packageElements.add(elements.getPackageOf(e)))
+                        .map(elements::getBinaryName),
+                implicitInjectableClasses.stream()
+                        .peek(e -> packageElements.add(elements.getPackageOf(e)))
+                        .map(elements::getBinaryName))
+                .collect(Collectors.toSet());
+        final Map<String, List<CharSequence>> pluginClassNames = pluginCategories.entrySet().stream().collect(
+                Collectors.toMap(Map.Entry::getKey,
+                        entry -> entry.getValue().stream()
+                                .peek(el -> packageElements.add(elements.getPackageOf(el)))
+                                .map(elements::getBinaryName)
+                                .sorted(CharSequence::compare)
+                                .collect(Collectors.toList())));
+
+        String packageName = processingEnv.getOptions().get("pluginPackage");
+        if (packageName == null) {
+            packageName = packageElements.stream()
+                    .map(PackageElement::getQualifiedName)
+                    .map(CharSequence.class::cast)
+                    .reduce(BeanProcessor::commonPrefix)
+                    .orElseThrow()
+                    .toString();
+        }
+        try {
+            writeBeanInfoServiceFile(packageName);
+            writeBeanInfoServiceClass(packageName, injectableClassNames, producibleClassNames, destructibleClassNames, pluginClassNames);
+            return false;
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    private void writeBeanInfoServiceFile(final String packageName) throws IOException {
+        final FileObject fileObject = processingEnv.getFiler()
+                .createResource(StandardLocation.CLASS_OUTPUT, "", BEAN_INFO_SERVICE_FILE);
+        try (PrintWriter out = new PrintWriter(fileObject.openWriter())) {
+            out.println(packageName + ".plugins.Log4jBeanInfo");
+        }
+    }
+
+    private void writeBeanInfoServiceClass(final String packageName, final Set<CharSequence> injectableClassNames,
+                                           final Set<CharSequence> producibleClassNames,
+                                           final Set<CharSequence> destructibleClassNames,
+                                           final Map<String, List<CharSequence>> pluginClassNames)
+            throws IOException {
+        final JavaFileObject sourceFile = processingEnv.getFiler()
+                .createSourceFile(packageName + ".plugins.Log4jBeanInfo");
+        try (final PrintWriter out = new PrintWriter(sourceFile.openWriter())) {
+            out.println("package " + packageName + ".plugins;");
+            out.println();
+            out.println("import java.util.List;");
+            out.println("import java.util.Map;");
+            out.println();
+            out.println("@javax.annotation.processing.Generated(\"" + getClass().getName() + "\")");
+            out.println("public class Log4jBeanInfo extends org.apache.logging.log4j.plugins.di.spi.BeanInfoService {");
+            out.println();
+            out.println("  private static final List<String> INJECTABLE = List.of(" + getListOfNames(injectableClassNames) + ");");
+            out.println();
+            out.println("  private static final List<String> PRODUCIBLE = List.of(" + getListOfNames(producibleClassNames) + ");");
+            out.println();
+            out.println("  private static final List<String> DESTRUCTIBLE = List.of(" + getListOfNames(destructibleClassNames) + ");");
+            out.println();
+            out.println("  private static final Map<String, List<String>> PLUGIN_CATEGORIES = Map.of(" + getMapOfPluginNames(pluginClassNames) + ");");
+            out.println();
+            out.println("  public Log4jBeanInfo() {");
+            out.println("    super(INJECTABLE, PRODUCIBLE, DESTRUCTIBLE, PLUGIN_CATEGORIES);");
+            out.println("  }");
+            out.println();
+            out.println("}");
+        }
+    }
+
+    private static String getListOfNames(final Set<CharSequence> names) {
+        return names.isEmpty() ? Strings.EMPTY : names.stream().sorted(CharSequence::compare).collect(
+                Collectors.joining("\",\n    \"", "\n    \"", "\"\n  "));
+    }
+
+    private static String getMapOfPluginNames(final Map<String, List<CharSequence>> pluginClassNames) {
+        return pluginClassNames.isEmpty() ? Strings.EMPTY : pluginClassNames.entrySet()
+                .stream()
+                .sorted(Map.Entry.comparingByKey())
+                .map(e -> '"' + e.getKey() + "\", List.of(" + e.getValue().stream().collect(Collectors.joining("\",\n      \"", "\n      \"", "\"\n    ")) + ')')
+                .collect(Collectors.joining(",\n    ", "\n    ", "\n  "));
+    }
+
+    private static CharSequence commonPrefix(final CharSequence str1, final CharSequence str2) {
+        final int minLength = Math.min(str1.length(), str2.length());
+        for (int i = 0; i < minLength; i++) {
+            if (str1.charAt(i) != str2.charAt(i)) {
+                if (i > 1 && str1.charAt(i - 1) == '.') {
+                    return str1.subSequence(0, i - 1);
+                } else {
+                    return str1.subSequence(0, i);
+                }
+            }
+        }
+        return str1.subSequence(0, minLength);
+    }
+
+}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
index ec18989..09bef4f 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
@@ -32,7 +32,7 @@ import javax.lang.model.element.ElementVisitor;
 import javax.lang.model.element.Name;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.util.Elements;
-import javax.lang.model.util.SimpleElementVisitor7;
+import javax.lang.model.util.SimpleElementVisitor8;
 import javax.tools.Diagnostic.Kind;
 import javax.tools.FileObject;
 import javax.tools.JavaFileObject;
@@ -95,12 +95,10 @@ public class PluginProcessor extends AbstractProcessor {
             writeClassFile(packageName, list);
             writeServiceFile(packageName);
             messager.printMessage(Kind.NOTE, "Annotations processed");
-            return true;
         } catch (final Exception ex) {
-            ex.printStackTrace();
             error(ex.getMessage());
-            return false;
         }
+        return false;
     }
 
     private void error(final CharSequence message) {
@@ -209,7 +207,7 @@ public class PluginProcessor extends AbstractProcessor {
     /**
      * ElementVisitor to scan the Plugin annotation.
      */
-    private static class PluginElementVisitor extends SimpleElementVisitor7<PluginEntry, Plugin> {
+    private static class PluginElementVisitor extends SimpleElementVisitor8<PluginEntry, Plugin> {
 
         private final Elements elements;
 
@@ -232,7 +230,7 @@ public class PluginProcessor extends AbstractProcessor {
     }
 
     private String commonPrefix(String str1, String str2) {
-        int minLength = str1.length() < str2.length() ? str1.length() : str2.length();
+        int minLength = Math.min(str1.length(), str2.length());
         for (int i = 0; i < minLength; i++) {
             if (str1.charAt(i) != str2.charAt(i)) {
                 if (i > 1 && str1.charAt(i-1) == '.') {
@@ -248,12 +246,12 @@ public class PluginProcessor extends AbstractProcessor {
     /**
      * ElementVisitor to scan the PluginAliases annotation.
      */
-    private static class PluginAliasesElementVisitor extends SimpleElementVisitor7<Collection<PluginEntry>, Plugin> {
+    private static class PluginAliasesElementVisitor extends SimpleElementVisitor8<Collection<PluginEntry>, Plugin> {
 
         private final Elements elements;
 
         private PluginAliasesElementVisitor(final Elements elements) {
-            super(Collections.<PluginEntry> emptyList());
+            super(Collections.emptyList());
             this.elements = elements;
         }
 
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 86c068a..f6122dc 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
@@ -18,9 +18,9 @@ package org.apache.logging.log4j.plugins.processor;
 
 import org.apache.logging.log4j.plugins.util.PluginType;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedHashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -35,7 +35,7 @@ public abstract class PluginService {
         PluginEntry[] entries = getEntries();
         for (PluginEntry entry : entries) {
             String category = entry.getCategory().toLowerCase();
-            List<PluginType<?>> list = categories.computeIfAbsent(category, ignored -> new LinkedList<>());
+            List<PluginType<?>> list = categories.computeIfAbsent(category, ignored -> new ArrayList<>());
             PluginType<?> type = new PluginType<>(entry, this.getClass().getClassLoader());
             list.add(type);
         }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/AnnotationUtil.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/AnnotationUtil.java
index 7bfcc3f..4b5abc4 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/AnnotationUtil.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/AnnotationUtil.java
@@ -17,20 +17,14 @@
 
 package org.apache.logging.log4j.plugins.util;
 
-import org.apache.logging.log4j.plugins.di.AnnotationAlias;
-
 import java.lang.annotation.Annotation;
 import java.lang.reflect.AnnotatedElement;
 
 public final class AnnotationUtil {
 
-    public static boolean isAnnotationPresent(final AnnotatedElement element, final Class<? extends Annotation> annotationType) {
-        if (element.isAnnotationPresent(annotationType)) {
-            return true;
-        }
+    public static boolean isMetaAnnotationPresent(final AnnotatedElement element, final Class<? extends Annotation> metaAnnotation) {
         for (final Annotation annotation : element.getAnnotations()) {
-            final AnnotationAlias alias = annotation.annotationType().getAnnotation(AnnotationAlias.class);
-            if (alias != null && annotationType.equals(alias.value())) {
+            if (annotation.annotationType().isAnnotationPresent(metaAnnotation)) {
                 return true;
             }
         }
diff --git a/log4j-plugins/src/main/java9/module-info.java b/log4j-plugins/src/main/java9/module-info.java
index b4144dc..4506235 100644
--- a/log4j-plugins/src/main/java9/module-info.java
+++ b/log4j-plugins/src/main/java9/module-info.java
@@ -18,6 +18,7 @@ module org.apache.logging.log4j.plugins {
     exports org.apache.logging.log4j.plugins;
     exports org.apache.logging.log4j.plugins.convert;
     exports org.apache.logging.log4j.plugins.di;
+    exports org.apache.logging.log4j.plugins.di.spi;
     exports org.apache.logging.log4j.plugins.processor;
     exports org.apache.logging.log4j.plugins.util;
     exports org.apache.logging.log4j.plugins.validation;
@@ -27,12 +28,14 @@ module org.apache.logging.log4j.plugins {
     exports org.apache.logging.log4j.plugins.inject;
     exports org.apache.logging.log4j.plugins.name;
 
-    requires java.compiler;
-    requires org.apache.logging.log4j;
+    requires transitive java.compiler; // TODO: break out annotation processor into separate module
+    requires transitive org.apache.logging.log4j;
     requires transitive org.osgi.framework;
 
     provides org.apache.logging.log4j.plugins.processor.PluginService with org.apache.logging.log4j.plugins.convert.plugins.Log4jPlugins;
-    provides javax.annotation.processing.Processor with org.apache.logging.log4j.plugins.processor.PluginProcessor;
+    provides org.apache.logging.log4j.plugins.di.spi.BeanInfoService with org.apache.logging.log4j.plugins.convert.plugins.Log4jBeanInfo;
+    provides javax.annotation.processing.Processor with org.apache.logging.log4j.plugins.processor.PluginProcessor, org.apache.logging.log4j.plugins.processor.BeanProcessor;
 
     uses org.apache.logging.log4j.plugins.processor.PluginService;
+//    uses org.apache.logging.log4j.plugins.di.spi.BeanInfoService;
 }
diff --git a/log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
index 5d6951a..4aebe10 100644
--- a/log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
+++ b/log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
@@ -14,4 +14,22 @@
 # See the license for the specific language governing permissions and
 # limitations under the license.
 #
+
+#
+# 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.
+#
 org.apache.logging.log4j.plugins.processor.PluginProcessor
+org.apache.logging.log4j.plugins.processor.BeanProcessor
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Named.java b/log4j-plugins/src/test/java-test/org/apache/logging/log4j/plugins/test/validation/ExampleBean.java
similarity index 55%
copy from log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Named.java
copy to log4j-plugins/src/test/java-test/org/apache/logging/log4j/plugins/test/validation/ExampleBean.java
index 0c7a542..5a89264 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Named.java
+++ b/log4j-plugins/src/test/java-test/org/apache/logging/log4j/plugins/test/validation/ExampleBean.java
@@ -14,22 +14,32 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
+package org.apache.logging.log4j.plugins.test.validation;
 
-package org.apache.logging.log4j.plugins.di;
+import java.util.Map;
+import org.apache.logging.log4j.plugins.di.Inject;
 
-import org.apache.logging.log4j.plugins.name.NameProvider;
-import org.apache.logging.log4j.plugins.name.NamedQualifierNameProvider;
-import org.apache.logging.log4j.util.Strings;
+public class ExampleBean {
+    private final String alpha;
+    private final int beta;
+    private final Map<String, String> gamma;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Repeatable;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+    @Inject
+    public ExampleBean(final String alpha, final int beta, final Map<String, String> gamma) {
+        this.alpha = alpha;
+        this.beta = beta;
+        this.gamma = gamma;
+    }
 
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-@NameProvider(NamedQualifierNameProvider.class)
-@Repeatable(NamedAliases.class)
-public @interface Named {
-    String value() default Strings.EMPTY;
+    public String getAlpha() {
+        return alpha;
+    }
+
+    public int getBeta() {
+        return beta;
+    }
+
+    public Map<String, String> getGamma() {
+        return gamma;
+    }
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Named.java b/log4j-plugins/src/test/java-test/org/apache/logging/log4j/plugins/test/validation/ImplicitBean.java
similarity index 55%
copy from log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Named.java
copy to log4j-plugins/src/test/java-test/org/apache/logging/log4j/plugins/test/validation/ImplicitBean.java
index 0c7a542..fd75e5f 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Named.java
+++ b/log4j-plugins/src/test/java-test/org/apache/logging/log4j/plugins/test/validation/ImplicitBean.java
@@ -14,22 +14,31 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
+package org.apache.logging.log4j.plugins.test.validation;
 
-package org.apache.logging.log4j.plugins.di;
+import java.util.Map;
+import org.apache.logging.log4j.plugins.di.Named;
 
-import org.apache.logging.log4j.plugins.name.NameProvider;
-import org.apache.logging.log4j.plugins.name.NamedQualifierNameProvider;
-import org.apache.logging.log4j.util.Strings;
+public class ImplicitBean {
+    private final String alpha;
+    private final int beta;
+    private final Map<String, String> gamma;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Repeatable;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+    public ImplicitBean(@Named final String alpha, final int beta, final Map<String, String> gamma) {
+        this.alpha = alpha;
+        this.beta = beta;
+        this.gamma = gamma;
+    }
 
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-@NameProvider(NamedQualifierNameProvider.class)
-@Repeatable(NamedAliases.class)
-public @interface Named {
-    String value() default Strings.EMPTY;
+    public String getAlpha() {
+        return alpha;
+    }
+
+    public int getBeta() {
+        return beta;
+    }
+
+    public Map<String, String> getGamma() {
+        return gamma;
+    }
 }
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/AnnotationUtil.java b/log4j-plugins/src/test/java-test/org/apache/logging/log4j/plugins/test/validation/ImplicitMethodBean.java
similarity index 50%
copy from log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/AnnotationUtil.java
copy to log4j-plugins/src/test/java-test/org/apache/logging/log4j/plugins/test/validation/ImplicitMethodBean.java
index 7bfcc3f..c36b0ef 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/AnnotationUtil.java
+++ b/log4j-plugins/src/test/java-test/org/apache/logging/log4j/plugins/test/validation/ImplicitMethodBean.java
@@ -14,29 +14,40 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
+package org.apache.logging.log4j.plugins.test.validation;
 
-package org.apache.logging.log4j.plugins.util;
+import java.util.Map;
+import org.apache.logging.log4j.plugins.di.Named;
 
-import org.apache.logging.log4j.plugins.di.AnnotationAlias;
+public class ImplicitMethodBean {
+    private String alpha;
+    private int beta;
+    private Map<String, String> gamma;
 
-import java.lang.annotation.Annotation;
-import java.lang.reflect.AnnotatedElement;
+    public String getAlpha() {
+        return alpha;
+    }
+
+    public ImplicitMethodBean setAlpha(@Named final String alpha) {
+        this.alpha = alpha;
+        return this;
+    }
 
-public final class AnnotationUtil {
+    public int getBeta() {
+        return beta;
+    }
+
+    public ImplicitMethodBean setBeta(@Named final int beta) {
+        this.beta = beta;
+        return this;
+    }
 
-    public static boolean isAnnotationPresent(final AnnotatedElement element, final Class<? extends Annotation> annotationType) {
-        if (element.isAnnotationPresent(annotationType)) {
-            return true;
-        }
-        for (final Annotation annotation : element.getAnnotations()) {
-            final AnnotationAlias alias = annotation.annotationType().getAnnotation(AnnotationAlias.class);
-            if (alias != null && annotationType.equals(alias.value())) {
-                return true;
-            }
-        }
-        return false;
+    public Map<String, String> getGamma() {
+        return gamma;
     }
 
-    private AnnotationUtil() {
+    public ImplicitMethodBean setGamma(@Named final Map<String, String> gamma) {
+        this.gamma = gamma;
+        return this;
     }
 }
diff --git a/log4j-plugins/src/test/java-test/org/apache/logging/log4j/plugins/test/validation/ProductionBean.java b/log4j-plugins/src/test/java-test/org/apache/logging/log4j/plugins/test/validation/ProductionBean.java
new file mode 100644
index 0000000..51cd722
--- /dev/null
+++ b/log4j-plugins/src/test/java-test/org/apache/logging/log4j/plugins/test/validation/ProductionBean.java
@@ -0,0 +1,56 @@
+/*
+ * 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.test.validation;
+
+import org.apache.logging.log4j.plugins.di.Disposes;
+import org.apache.logging.log4j.plugins.di.Inject;
+import org.apache.logging.log4j.plugins.di.Produces;
+import org.apache.logging.log4j.plugins.di.Provider;
+
+public class ProductionBean {
+    private final String alpha;
+
+    private ProductionBean(final String alpha) {
+        this.alpha = alpha;
+    }
+
+    public String getAlpha() {
+        return alpha;
+    }
+
+    @Produces
+    public static final String ALPHA = "hello world";
+
+    public static void destroyBean(@Disposes ProductionBean bean) {
+        System.out.println(bean.getAlpha());
+    }
+
+    public static class Builder implements Provider<ProductionBean> {
+        private String alpha;
+
+        @Inject
+        public Builder setAlpha(String alpha) {
+            this.alpha = alpha;
+            return this;
+        }
+
+        @Override
+        public ProductionBean get() {
+            return new ProductionBean(alpha);
+        }
+    }
+}
diff --git a/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/BeanProcessorTest.java b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/BeanProcessorTest.java
new file mode 100644
index 0000000..b63070c
--- /dev/null
+++ b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/BeanProcessorTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.processor;
+
+import org.apache.logging.log4j.plugins.di.spi.BeanInfoService;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.ServiceLoader;
+
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class BeanProcessorTest {
+    @Test
+    void canLoadTestCategory() {
+        final BeanInfoService service = ServiceLoader.load(BeanInfoService.class, getClass().getClassLoader())
+                .findFirst()
+                .orElseThrow();
+        final List<String> testPlugins = service.getPluginCategories().get("Test");
+        assertNotNull(testPlugins);
+        assertNotEquals(0, testPlugins.size());
+        assertTrue(testPlugins.stream().anyMatch(name -> name.equals(FakePlugin.class.getName())));
+    }
+
+    @Test
+    void smokeTests() {
+        final BeanInfoService service = ServiceLoader.load(BeanInfoService.class, getClass().getClassLoader())
+                .findFirst()
+                .orElseThrow();
+        assertTrue(service.getInjectableClassNames().stream().anyMatch(name -> name.equals("org.apache.logging.log4j.plugins.test.validation.ExampleBean")));
+        assertTrue(service.getInjectableClassNames().stream().anyMatch(name -> name.equals("org.apache.logging.log4j.plugins.test.validation.ImplicitBean")));
+        assertTrue(service.getInjectableClassNames().stream().anyMatch(name -> name.equals("org.apache.logging.log4j.plugins.test.validation.ImplicitMethodBean")));
+        assertTrue(service.getInjectableClassNames().stream().anyMatch(name -> name.equals("org.apache.logging.log4j.plugins.test.validation.ProductionBean$Builder")));
+        assertTrue(service.getProducibleClassNames().stream().anyMatch(name -> name.equals("org.apache.logging.log4j.plugins.test.validation.ProductionBean")));
+        assertTrue(service.getDestructibleClassNames().stream().anyMatch(name -> name.equals("org.apache.logging.log4j.plugins.test.validation.ProductionBean")));
+    }
+}
\ No newline at end of file
diff --git a/log4j-plugins/src/test/java9/module-info.java b/log4j-plugins/src/test/java9/module-info.java
index 3ce37fc..41a87f2 100644
--- a/log4j-plugins/src/test/java9/module-info.java
+++ b/log4j-plugins/src/test/java9/module-info.java
@@ -1,9 +1,21 @@
 open module org.apache.logging.log4j.plugins {
     exports org.apache.logging.log4j.plugins;
+    exports org.apache.logging.log4j.plugins.convert;
+    exports org.apache.logging.log4j.plugins.di;
+    exports org.apache.logging.log4j.plugins.di.spi;
+    exports org.apache.logging.log4j.plugins.name;
+    exports org.apache.logging.log4j.plugins.processor;
+    exports org.apache.logging.log4j.plugins.util;
+    exports org.apache.logging.log4j.plugins.bind;
+    exports org.apache.logging.log4j.plugins.inject;
+
+    exports org.apache.logging.log4j.plugins.validation;
+    exports org.apache.logging.log4j.plugins.validation.constraints;
+    exports org.apache.logging.log4j.plugins.validation.validators;
     exports org.apache.logging.log4j.plugins.test.validation;
 
-    requires java.compiler;
-    requires org.apache.logging.log4j;
+    requires transitive java.compiler;
+    requires transitive org.apache.logging.log4j;
     requires org.apache.logging.log4j.test;
     requires org.junit.jupiter.api;
     requires org.junit.jupiter.engine;
@@ -12,7 +24,9 @@ open module org.apache.logging.log4j.plugins {
     requires junit;
 
     provides org.apache.logging.log4j.plugins.processor.PluginService with org.apache.logging.log4j.plugins.convert.plugins.Log4jPlugins;
-    provides javax.annotation.processing.Processor with org.apache.logging.log4j.plugins.processor.PluginProcessor;
+    provides org.apache.logging.log4j.plugins.di.spi.BeanInfoService with org.apache.logging.log4j.plugins.convert.plugins.Log4jBeanInfo;
+    provides javax.annotation.processing.Processor with org.apache.logging.log4j.plugins.processor.PluginProcessor, org.apache.logging.log4j.plugins.processor.BeanProcessor;
 
     uses org.apache.logging.log4j.plugins.processor.PluginService;
+    uses org.apache.logging.log4j.plugins.di.spi.BeanInfoService;
 }

[logging-log4j2] 01/03: Fix compile warning

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 64f8151e5605863eaeb97870b8824899824e5daf
Author: Matt Sicker <bo...@gmail.com>
AuthorDate: Sat Jul 10 18:58:01 2021 -0500

    Fix compile warning
---
 .../apache/logging/log4j/plugins/name/AnnotatedElementNameProvider.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/AnnotatedElementNameProvider.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/AnnotatedElementNameProvider.java
index 95e303a..2f7bda0 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/AnnotatedElementNameProvider.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/name/AnnotatedElementNameProvider.java
@@ -68,7 +68,7 @@ public interface AnnotatedElementNameProvider<A extends Annotation> {
             if (methodName.startsWith("is")) {
                 return BeanUtils.decapitalize(methodName.substring(2));
             }
-            if (methodName.startsWith("set") | methodName.startsWith("get")) {
+            if (methodName.startsWith("set") || methodName.startsWith("get")) {
                 return BeanUtils.decapitalize(methodName.substring(3));
             }
             if (methodName.startsWith("with")) {