This is an automated email from the ASF dual-hosted git repository. mattsicker pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit c88538c81e785d71c39199478046e217d453d41e Author: Matt Sicker <[email protected]> AuthorDate: Sun May 22 13:49:42 2022 -0500 Rename PluginOrder to Ordered Signed-off-by: Matt Sicker <[email protected]> --- .../plugins/test/validation/generic/BetaBean.java | 4 +- .../plugins/convert/TypeConverterRegistryTest.java | 4 +- .../apache/logging/log4j/plugins/di/KeyTest.java | 99 ++++++++++++++++++++++ .../plugins/{PluginOrder.java => Ordered.java} | 24 +----- .../org/apache/logging/log4j/plugins/di/Key.java | 60 +++++++------ .../log4j/plugins/util/OrderedComparator.java | 73 ++++++++++++++++ .../log4j/plugins/util/PluginNamespace.java | 6 +- 7 files changed, 218 insertions(+), 52 deletions(-) diff --git a/log4j-plugins-test/src/main/java/org/apache/logging/log4j/plugins/test/validation/generic/BetaBean.java b/log4j-plugins-test/src/main/java/org/apache/logging/log4j/plugins/test/validation/generic/BetaBean.java index b4b4991715..66eafa0ff0 100644 --- a/log4j-plugins-test/src/main/java/org/apache/logging/log4j/plugins/test/validation/generic/BetaBean.java +++ b/log4j-plugins-test/src/main/java/org/apache/logging/log4j/plugins/test/validation/generic/BetaBean.java @@ -18,13 +18,13 @@ package org.apache.logging.log4j.plugins.test.validation.generic; import org.apache.logging.log4j.plugins.Namespace; +import org.apache.logging.log4j.plugins.Ordered; import org.apache.logging.log4j.plugins.Plugin; -import org.apache.logging.log4j.plugins.PluginOrder; import org.apache.logging.log4j.plugins.Singleton; @Namespace("Bean") @Plugin("Beta") -@PluginOrder(PluginOrder.FIRST) +@Ordered(Ordered.FIRST) @Singleton public class BetaBean implements BaseBean { } diff --git a/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java b/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java index 4f1e780be2..b3892cd1e4 100644 --- a/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java +++ b/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java @@ -17,8 +17,8 @@ package org.apache.logging.log4j.plugins.convert; +import org.apache.logging.log4j.plugins.Ordered; import org.apache.logging.log4j.plugins.Plugin; -import org.apache.logging.log4j.plugins.PluginOrder; import org.apache.logging.log4j.plugins.di.DI; import org.apache.logging.log4j.plugins.di.Injector; import org.junit.jupiter.api.Test; @@ -49,7 +49,7 @@ class TypeConverterRegistryTest { @SuppressWarnings("ComparableType") @TypeConverters @Plugin - @PluginOrder(PluginOrder.FIRST) + @Ordered(Ordered.FIRST) public static final class CustomTestClass1Converter2 implements TypeConverter<CustomTestClass1>, Comparable<TypeConverter<?>> { diff --git a/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/di/KeyTest.java b/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/di/KeyTest.java new file mode 100644 index 0000000000..4ae4dc6f1f --- /dev/null +++ b/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/di/KeyTest.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ + +package org.apache.logging.log4j.plugins.di; + +import org.apache.logging.log4j.plugins.Named; +import org.apache.logging.log4j.plugins.Namespace; +import org.apache.logging.log4j.plugins.Ordered; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + +// TODO: add tests for meta namespace annotations +// TODO: add tests for more complex types with generics etc +class KeyTest { + + @Namespace("namespace") + @Named("name") + @Ordered(42) + static class AnnotatedClass { + } + + @Test + void forClass() { + final Key<AnnotatedClass> key = Key.forClass(AnnotatedClass.class); + assertEquals("namespace", key.getNamespace()); + assertEquals("name", key.getName()); + assertEquals(42, key.getOrder()); + assertEquals(AnnotatedClass.class, key.getType()); + assertEquals(AnnotatedClass.class, key.getRawType()); + } + + interface AnnotatedMethod { + @Namespace("foo") + @Named("bar") + @Ordered(10) + String string(); + } + + @Test + void forMethod() { + final Key<String> key = assertDoesNotThrow(() -> Key.forMethod(AnnotatedMethod.class.getMethod("string"))); + assertEquals("foo", key.getNamespace()); + assertEquals("bar", key.getName()); + assertEquals(10, key.getOrder()); + assertEquals(String.class, key.getType()); + assertEquals(String.class, key.getRawType()); + } + + interface AnnotatedParameter { + void method(@Namespace("foo") @Named String bar); + } + + @Test + void forParameter() { + final Method method = assertDoesNotThrow(() -> AnnotatedParameter.class.getMethod("method", String.class)); + final Key<String> key = Key.forParameter(method.getParameters()[0]); + assertEquals("foo", key.getNamespace()); + assertEquals("bar", key.getName()); + assertEquals(0, key.getOrder()); + assertEquals(String.class, key.getType()); + assertEquals(String.class, key.getRawType()); + } + + static class AnnotatedField { + @Namespace("foo") + @Named("bar") + public String string; + } + + @Test + void forField() { + final Field field = assertDoesNotThrow(() -> AnnotatedField.class.getField("string")); + final Key<String> key = Key.forField(field); + assertEquals("foo", key.getNamespace()); + assertEquals("bar", key.getName()); + assertEquals(0, key.getOrder()); + assertEquals(String.class, key.getType()); + assertEquals(String.class, key.getRawType()); + } +} diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginOrder.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Ordered.java similarity index 60% rename from log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginOrder.java rename to log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Ordered.java index f13e6dc950..b044223120 100644 --- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginOrder.java +++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Ordered.java @@ -22,35 +22,17 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.util.Comparator; /** - * Specifies the order in which the annotated class should be considered in when processing plugins. + * Specifies the order in which the annotated element should be considered for dependency injection. */ -@Target(ElementType.TYPE) +@Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented -public @interface PluginOrder { +public @interface Ordered { int value(); int FIRST = Integer.MIN_VALUE; int LAST = Integer.MAX_VALUE; - - Comparator<Class<?>> COMPARATOR = (lhs, rhs) -> { - if (lhs == rhs) { - return 0; - } - final PluginOrder lhsOrder = lhs.getAnnotation(PluginOrder.class); - final PluginOrder rhsOrder = rhs.getAnnotation(PluginOrder.class); - if (lhsOrder != null && rhsOrder != null) { - return Integer.compare(lhsOrder.value(), rhsOrder.value()); - } else if (lhsOrder != null) { - return -1; - } else if (rhsOrder != null) { - return 1; - } else { - return lhs.getName().compareTo(rhs.getName()); - } - }; } diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Key.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Key.java index 09967452d8..b060376424 100644 --- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Key.java +++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Key.java @@ -17,9 +17,11 @@ package org.apache.logging.log4j.plugins.di; +import org.apache.logging.log4j.plugins.Ordered; import org.apache.logging.log4j.plugins.QualifierType; import org.apache.logging.log4j.plugins.util.AnnotationUtil; import org.apache.logging.log4j.plugins.util.TypeUtil; +import org.apache.logging.log4j.util.Strings; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; @@ -34,7 +36,7 @@ import java.util.Objects; import java.util.function.Supplier; /** - * Type with an optional {@link QualifierType} type, name, and category. Keys are used for binding to and looking up instance + * Type with an optional {@link QualifierType} type, name, and namespace. Keys are used for binding to and looking up instance * factories via {@link Injector}. * * @param <T> type of key @@ -45,6 +47,7 @@ public class Key<T> { private final Class<? extends Annotation> qualifierType; private final String name; private final String namespace; + private final int order; private final int hashCode; private String toString; @@ -67,21 +70,23 @@ public class Key<T> { qualifierType = qualifier != null ? qualifier.annotationType() : null; name = Keys.getName(superclass); namespace = Keys.getNamespace(superclass); + order = getOrder(superclass); hashCode = Objects.hash(type, qualifierType, name.toLowerCase(Locale.ROOT), namespace.toLowerCase(Locale.ROOT)); } private Key( final Type type, final Class<T> rawType, final Class<? extends Annotation> qualifierType, final String name, - final String namespace) { + final String namespace, final int order) { this.type = type; this.rawType = rawType; this.qualifierType = qualifierType; this.name = name; this.namespace = namespace; + this.order = order; hashCode = Objects.hash(type, qualifierType, name.toLowerCase(Locale.ROOT), namespace.toLowerCase(Locale.ROOT)); } - public Type getType() { + public final Type getType() { return type; } @@ -89,34 +94,34 @@ public class Key<T> { return rawType; } - public String getName() { + public final String getName() { return name; } - public String getNamespace() { + public final String getNamespace() { return namespace; } - public Class<? extends Annotation> getQualifierType() { - return qualifierType; + public final int getOrder() { + return order; } /** * Returns a new key using the provided name and the same type and qualifier type as this instance. */ public final Key<T> withName(final String name) { - return new Key<>(type, rawType, qualifierType, name, namespace); + return new Key<>(type, rawType, qualifierType, name, namespace, order); } public final Key<T> withNamespace(final String namespace) { - return new Key<>(type, rawType, qualifierType, name, namespace); + return new Key<>(type, rawType, qualifierType, name, namespace, order); } /** * Returns a new key using the provided qualifier type and the same type and name as this instance. */ public final Key<T> withQualifierType(final Class<? extends Annotation> qualifierType) { - return new Key<>(type, rawType, qualifierType, name, namespace); + return new Key<>(type, rawType, qualifierType, name, namespace, order); } /** @@ -125,7 +130,8 @@ public class Key<T> { */ public final <P> Key<P> getSuppliedType() { if (type instanceof ParameterizedType && Supplier.class.isAssignableFrom(rawType)) { - return forQualifiedNamedType(qualifierType, name, ((ParameterizedType) type).getActualTypeArguments()[0], namespace); + return forQualifiedNamedType(qualifierType, name, ((ParameterizedType) type).getActualTypeArguments()[0], namespace, + order); } return null; } @@ -133,7 +139,7 @@ public class Key<T> { public final <P> Key<P> getParameterizedTypeArgument(final int arg) { if (type instanceof ParameterizedType) { return forQualifiedNamedType(qualifierType, name, ((ParameterizedType) type).getActualTypeArguments()[arg], - namespace); + namespace, order); } return null; } @@ -162,12 +168,8 @@ public class Key<T> { public final String toString() { String string = toString; if (string == null) { - toString = string = "Key{" + - "type=" + type.getTypeName() + - (qualifierType != null ? ", qualifierType=" + qualifierType.getSimpleName() : "") + - ", name='" + name + '\'' + - ", category='" + namespace + '\'' + - '}'; + toString = string = String.format("Key{namespace='%s', name='%s', type=%s, qualifierType=%s}", + namespace, name, type.getTypeName(), qualifierType != null ? qualifierType.getSimpleName() : Strings.EMPTY); } return string; } @@ -179,7 +181,8 @@ public class Key<T> { return forQualifiedNamedType(getQualifierType(clazz), Keys.getName(clazz), clazz, - Keys.getNamespace(clazz)); + Keys.getNamespace(clazz), + getOrder(clazz)); } /** @@ -189,7 +192,8 @@ public class Key<T> { return forQualifiedNamedType(getQualifierType(method), Keys.getName(method), method.getGenericReturnType(), - Keys.getNamespace(method)); + Keys.getNamespace(method), + getOrder(method)); } /** @@ -199,7 +203,8 @@ public class Key<T> { return forQualifiedNamedType(getQualifierType(parameter), Keys.getName(parameter), parameter.getParameterizedType(), - Keys.getNamespace(parameter)); + Keys.getNamespace(parameter), + 0); } /** @@ -209,17 +214,24 @@ public class Key<T> { return forQualifiedNamedType(getQualifierType(field), Keys.getName(field), field.getGenericType(), - Keys.getNamespace(field)); + Keys.getNamespace(field), + 0); } private static <T> Key<T> forQualifiedNamedType( - final Class<? extends Annotation> qualifierType, final String name, final Type type, final String category) { + final Class<? extends Annotation> qualifierType, final String name, final Type type, final String namespace, + final int order) { final Class<T> rawType = TypeUtil.cast(TypeUtil.getRawType(type)); - return new Key<>(type, rawType, qualifierType, name, category); + return new Key<>(type, rawType, qualifierType, name, namespace, order); } private static Class<? extends Annotation> getQualifierType(final AnnotatedElement element) { final Annotation qualifierAnnotation = AnnotationUtil.getMetaAnnotation(element, QualifierType.class); return qualifierAnnotation != null ? qualifierAnnotation.annotationType() : null; } + + private static int getOrder(final AnnotatedElement element) { + final Ordered annotation = element.getAnnotation(Ordered.class); + return annotation != null ? annotation.value() : 0; + } } diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/OrderedComparator.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/OrderedComparator.java new file mode 100644 index 0000000000..cf19faa4be --- /dev/null +++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/OrderedComparator.java @@ -0,0 +1,73 @@ +/* + * 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.util; + +import org.apache.logging.log4j.plugins.Ordered; +import org.apache.logging.log4j.plugins.di.Keys; +import org.apache.logging.log4j.util.Strings; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.AnnotatedType; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.Comparator; + +/** + * Comparator for annotated elements using {@link Ordered} followed by their name from {@link Keys#getName}. + */ +public class OrderedComparator implements Comparator<AnnotatedElement> { + public static final OrderedComparator INSTANCE = new OrderedComparator(); + + @Override + public int compare(final AnnotatedElement lhs, final AnnotatedElement rhs) { + if (lhs == rhs) { + return 0; + } + final Ordered lhsOrder = lhs.getAnnotation(Ordered.class); + final Ordered rhsOrder = rhs.getAnnotation(Ordered.class); + if (lhsOrder != null && rhsOrder != null) { + return Integer.compare(lhsOrder.value(), rhsOrder.value()); + } else if (lhsOrder != null) { + return -1; + } else if (rhsOrder != null) { + return 1; + } else { + return getName(lhs).compareToIgnoreCase(getName(rhs)); + } + } + + private static String getName(final AnnotatedElement element) { + if (element instanceof Class<?>) { + return Keys.getName((Class<?>) element); + } + if (element instanceof Field) { + return Keys.getName((Field) element); + } + if (element instanceof Parameter) { + return Keys.getName((Parameter) element); + } + if (element instanceof Method) { + return Keys.getName((Method) element); + } + if (element instanceof AnnotatedType) { + return Keys.getName((AnnotatedType) element); + } + return Strings.EMPTY; + } +} diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginNamespace.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginNamespace.java index 938d9828b7..bb6856eac8 100644 --- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginNamespace.java +++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginNamespace.java @@ -18,7 +18,7 @@ package org.apache.logging.log4j.plugins.util; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.plugins.PluginOrder; +import org.apache.logging.log4j.plugins.Ordered; import org.apache.logging.log4j.plugins.Singleton; import org.apache.logging.log4j.status.StatusLogger; @@ -109,12 +109,12 @@ public class PluginNamespace extends AbstractCollection<PluginType<?>> { /** * Merges the provided plugin type into this namespace using the given key and returns the merged result. - * Merging is done by preferring plugins according to {@link PluginOrder} where a conflict occurs with the + * Merging is done by preferring plugins according to {@link Ordered} where a conflict occurs with the * same key. */ public PluginType<?> merge(final String key, final PluginType<?> pluginType) { final PluginType<?> result = plugins.merge(key, pluginType, (lhs, rhs) -> { - final int compare = PluginOrder.COMPARATOR.compare(lhs.getPluginClass(), rhs.getPluginClass()); + final int compare = OrderedComparator.INSTANCE.compare(lhs.getPluginClass(), rhs.getPluginClass()); LOGGER.debug("PluginNamespace merge for key {} with comparison result {}", key, compare); return compare <= 0 ? lhs : rhs; });
