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:25 UTC
[logging-log4j2] 03/03: Add foundation for bean annotation
processing and plugin metadata
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;
}