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 e96557e29843b2b3a4237db5ebb248f35a14bd81
Author: Matt Sicker <[email protected]>
AuthorDate: Sun Nov 6 14:36:07 2022 -0600

    LOG4J2-3626 - Flatten ThreadContextMap with default methods
    
    Signed-off-by: Matt Sicker <[email protected]>
---
 .../org/apache/logging/log4j/ThreadContext.java    | 22 +-----
 .../log4j/spi/CleanableThreadContextMap.java       | 18 +----
 .../CopyOnWriteSortedArrayThreadContextMap.java    |  4 +-
 .../logging/log4j/spi/DefaultThreadContextMap.java |  4 +-
 .../GarbageFreeSortedArrayThreadContextMap.java    |  4 +-
 .../logging/log4j/spi/NoOpThreadContextMap.java    | 21 +++++
 .../logging/log4j/spi/ObjectThreadContextMap.java  | 36 +--------
 .../apache/logging/log4j/spi/ThreadContextMap.java | 91 +++++++++++++++++++++-
 .../logging/log4j/spi/ThreadContextMap2.java       | 32 +-------
 .../apache/logging/log4j/util/PropertiesUtil.java  |  2 +-
 .../logging/log4j/perf/nogc/OpenHashStringMap.java | 19 +++--
 .../org/apache/logging/slf4j/MDCContextMap.java    | 10 +--
 src/changes/changes.xml                            |  3 +
 13 files changed, 149 insertions(+), 117 deletions(-)

diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
index c61ca0701c..75f4d932c5 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
@@ -18,13 +18,11 @@
 package org.apache.logging.log4j;
 
 import org.apache.logging.log4j.message.ParameterizedMessage;
-import org.apache.logging.log4j.spi.CleanableThreadContextMap;
 import org.apache.logging.log4j.spi.DefaultThreadContextMap;
 import org.apache.logging.log4j.spi.DefaultThreadContextStack;
 import org.apache.logging.log4j.spi.NoOpThreadContextMap;
 import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap;
 import org.apache.logging.log4j.spi.ThreadContextMap;
-import org.apache.logging.log4j.spi.ThreadContextMap2;
 import org.apache.logging.log4j.spi.ThreadContextMapFactory;
 import org.apache.logging.log4j.spi.ThreadContextStack;
 import org.apache.logging.log4j.util.PropertiesUtil;
@@ -274,15 +272,7 @@ public final class ThreadContext {
      * @since 2.7
      */
     public static void putAll(final Map<String, String> m) {
-        if (contextMap instanceof ThreadContextMap2) {
-            ((ThreadContextMap2) contextMap).putAll(m);
-        } else if (contextMap instanceof DefaultThreadContextMap) {
-            ((DefaultThreadContextMap) contextMap).putAll(m);
-        } else {
-            for (final Map.Entry<String, String> entry: m.entrySet()) {
-                contextMap.put(entry.getKey(), entry.getValue());
-            }
-        }
+        contextMap.putAll(m);
     }
 
     /**
@@ -316,15 +306,7 @@ public final class ThreadContext {
      * @since 2.8
      */
     public static void removeAll(final Iterable<String> keys) {
-        if (contextMap instanceof CleanableThreadContextMap) {
-            ((CleanableThreadContextMap) contextMap).removeAll(keys);
-        } else if (contextMap instanceof DefaultThreadContextMap) {
-            ((DefaultThreadContextMap) contextMap).removeAll(keys);
-        } else {
-            for (final String key : keys) {
-                contextMap.remove(key);
-            }
-        }
+        contextMap.removeAll(keys);
     }
 
     /**
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CleanableThreadContextMap.java
 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CleanableThreadContextMap.java
index f32a06e6e0..9f0dd3e7df 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CleanableThreadContextMap.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CleanableThreadContextMap.java
@@ -17,23 +17,13 @@
 package org.apache.logging.log4j.spi;
 
 /**
- * Extension service provider interface to implement additional custom MDC 
behavior for
- * {@link org.apache.logging.log4j.ThreadContext}.
+ * Legacy interface for backward compatibility with extensions to 
ThreadContextMap.
+ * These methods have since been moved to default methods on ThreadContextMap.
  *
  * @see ThreadContextMap
  * @since 2.8
+ * @deprecated use {@link ThreadContextMap} directly
  */
+@Deprecated(since = "3.0.0")
 public interface CleanableThreadContextMap extends ThreadContextMap2 {
-
-    /**
-     * Removes all given context map keys from the current thread's context 
map.
-     *
-     * <p>If the current thread does not have a context map it is
-     * created as a side effect.</p>
-
-     * @param keys The keys.
-     * @since 2.8
-     */
-    void removeAll(final Iterable<String> keys);
-
 }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
index ea0a0fd5e4..27e29cfb39 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
@@ -18,11 +18,11 @@ package org.apache.logging.log4j.spi;
 
 import org.apache.logging.log4j.util.LazyBoolean;
 import org.apache.logging.log4j.util.LazyInt;
+import org.apache.logging.log4j.util.PropertiesUtil;
 import org.apache.logging.log4j.util.PropertyEnvironment;
 import org.apache.logging.log4j.util.ReadOnlyStringMap;
 import org.apache.logging.log4j.util.SortedArrayStringMap;
 import org.apache.logging.log4j.util.StringMap;
-import org.apache.logging.log4j.util.PropertiesUtil;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -38,7 +38,7 @@ import java.util.Objects;
  *
  * @since 2.7
  */
-class CopyOnWriteSortedArrayThreadContextMap implements 
ReadOnlyThreadContextMap, ObjectThreadContextMap, CopyOnWrite {
+class CopyOnWriteSortedArrayThreadContextMap implements 
ReadOnlyThreadContextMap, ThreadContextMap, CopyOnWrite {
 
     /**
      * Property name ({@value} ) for selecting {@code InheritableThreadLocal} 
(value "true") or plain
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java
 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java
index 2efec39f7b..665480ee2e 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java
@@ -18,10 +18,10 @@ package org.apache.logging.log4j.spi;
 
 import org.apache.logging.log4j.util.BiConsumer;
 import org.apache.logging.log4j.util.LazyBoolean;
+import org.apache.logging.log4j.util.PropertiesUtil;
 import org.apache.logging.log4j.util.PropertyEnvironment;
 import org.apache.logging.log4j.util.ReadOnlyStringMap;
 import org.apache.logging.log4j.util.TriConsumer;
-import org.apache.logging.log4j.util.PropertiesUtil;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -90,6 +90,7 @@ public class DefaultThreadContextMap implements 
ThreadContextMap, ReadOnlyString
         localMap.set(Collections.unmodifiableMap(map));
     }
 
+    @Override
     public void putAll(final Map<String, String> m) {
         if (!useMap) {
             return;
@@ -116,6 +117,7 @@ public class DefaultThreadContextMap implements 
ThreadContextMap, ReadOnlyString
         }
     }
 
+    @Override
     public void removeAll(final Iterable<String> keys) {
         final Map<String, String> map = localMap.get();
         if (map != null) {
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
index 08f5bb9924..f46c014f7e 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
@@ -18,11 +18,11 @@ package org.apache.logging.log4j.spi;
 
 import org.apache.logging.log4j.util.LazyBoolean;
 import org.apache.logging.log4j.util.LazyInt;
+import org.apache.logging.log4j.util.PropertiesUtil;
 import org.apache.logging.log4j.util.PropertyEnvironment;
 import org.apache.logging.log4j.util.ReadOnlyStringMap;
 import org.apache.logging.log4j.util.SortedArrayStringMap;
 import org.apache.logging.log4j.util.StringMap;
-import org.apache.logging.log4j.util.PropertiesUtil;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -38,7 +38,7 @@ import java.util.Objects;
  * </p>
  * @since 2.7
  */
-class GarbageFreeSortedArrayThreadContextMap implements 
ReadOnlyThreadContextMap, ObjectThreadContextMap  {
+class GarbageFreeSortedArrayThreadContextMap implements 
ReadOnlyThreadContextMap, ThreadContextMap  {
 
     /**
      * Property name ({@value} ) for selecting {@code InheritableThreadLocal} 
(value "true") or plain
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java
 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java
index 2f858fce32..f46ffec06b 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java
@@ -62,4 +62,25 @@ public class NoOpThreadContextMap implements 
ThreadContextMap {
     @Override
     public void remove(final String key) {
     }
+
+    @Override
+    public void putAll(final Map<String, String> map) {
+    }
+
+    @Override
+    public void removeAll(final Iterable<String> keys) {
+    }
+
+    @Override
+    public <V> V getValue(final String key) {
+        return null;
+    }
+
+    @Override
+    public <V> void putValue(final String key, final V value) {
+    }
+
+    @Override
+    public <V> void putAllValues(final Map<String, V> values) {
+    }
 }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ObjectThreadContextMap.java
 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ObjectThreadContextMap.java
index c4bc014d3a..aa07de1baf 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ObjectThreadContextMap.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ObjectThreadContextMap.java
@@ -16,42 +16,14 @@
  */
 package org.apache.logging.log4j.spi;
 
-import java.util.Map;
-
 /**
- * Extension service provider interface to allow putting Object values in the
- * {@link org.apache.logging.log4j.ThreadContext}.
+ * Legacy interface for backward compatibility with extensions to 
ThreadContextMap.
+ * These methods have since been moved to default methods on ThreadContextMap.
  *
  * @see ThreadContextMap
  * @since 2.8
+ * @deprecated use {@link ThreadContextMap} directly
  */
+@Deprecated(since = "3.0.0")
 public interface ObjectThreadContextMap extends CleanableThreadContextMap {
-
-    /**
-     * Returns the Object value for the specified key, or {@code null} if the 
specified key does not exist in this
-     * collection.
-     *
-     * @param key the key whose value to return
-     * @param <V> The type of the returned value.
-     * @return the value for the specified key or {@code null}
-     */
-    <V> V getValue(String key);
-
-    /**
-     * Puts the specified key-value pair into the collection.
-     *
-     * @param key the key to add or remove. Keys may be {@code null}.
-     * @param <V> The type of the stored and returned value.
-     * @param value the value to add. Values may be {@code null}.
-     */
-    <V> void putValue(String key, V value);
-
-    /**
-     * Puts all given key-value pairs into the collection.
-     *
-     * @param values the map of key-value pairs to add
-     * @param <V> The type of the value being added.
-     */
-    <V> void putAllValues(Map<String, V> values);
-
 }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap.java
index 5040bb928e..af357b20c6 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap.java
@@ -16,9 +16,12 @@
  */
 package org.apache.logging.log4j.spi;
 
-import java.util.Map;
-
 import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.util.Cast;
+import org.apache.logging.log4j.util.SortedArrayStringMap;
+import org.apache.logging.log4j.util.StringMap;
+
+import java.util.Map;
 
 /**
  * Service provider interface to implement custom MDC behavior for {@link 
org.apache.logging.log4j.ThreadContext}.
@@ -26,6 +29,9 @@ import org.apache.logging.log4j.ThreadContext;
  * Since 2.8, {@code ThreadContextMap} implementations that implement the 
{@link ReadOnlyThreadContextMap} interface
  * are accessible to applications via the {@link 
ThreadContext#getThreadContextMap()} method.
  * </p>
+ * <p>
+ * Since 3.0.0, {@code ThreadContextMap} combines all its extension interfaces 
into default methods on this interface.
+ * </p>
  */
 public interface ThreadContextMap {
 
@@ -86,4 +92,85 @@ public interface ThreadContextMap {
      * @param key The key to remove.
      */
     void remove(final String key);
+
+    /**
+     * Puts all given context map entries into the current thread's
+     * context map.
+     *
+     * <p>If the current thread does not have a context map it is
+     * created as a side effect.</p>
+     * @param map The map.
+     * @since 3.0.0
+     */
+    default void putAll(Map<String, String> map) {
+        map.forEach(this::put);
+    }
+
+    /**
+     * Returns the context data for reading. Note that regardless of whether 
the returned context data has been
+     * {@linkplain StringMap#freeze() frozen} (made read-only) or not, callers 
should not attempt to modify
+     * the returned data structure.
+     *
+     * @return the {@code StringMap}
+     * @since 3.0.0
+     */
+    default StringMap getReadOnlyContextData() {
+        if (this instanceof ReadOnlyThreadContextMap) {
+            return ((ReadOnlyThreadContextMap) this).getReadOnlyContextData();
+        }
+        final Map<String, String> copy = getCopy();
+        StringMap map = new SortedArrayStringMap(copy.size());
+        copy.forEach(map::putValue);
+        map.freeze();
+        return map;
+    }
+
+    /**
+     * Removes all given context map keys from the current thread's context 
map.
+     *
+     * <p>If the current thread does not have a context map it is
+     * created as a side effect.</p>
+
+     * @param keys The keys.
+     * @since 3.0.0
+     */
+    default void removeAll(Iterable<String> keys) {
+        keys.forEach(this::remove);
+    }
+
+    /**
+     * Returns the Object value for the specified key, or {@code null} if the 
specified key does not exist in this
+     * collection.
+     *
+     * @param key the key whose value to return
+     * @param <V> The type of the returned value.
+     * @return the value for the specified key or {@code null}
+     * @since 3.0.0
+     */
+    default <V> V getValue(String key) {
+        return Cast.cast(get(key));
+    }
+
+    /**
+     * Puts the specified key-value pair into the collection.
+     *
+     * @param key the key to add or remove. Keys may be {@code null}.
+     * @param <V> The type of the stored and returned value.
+     * @param value the value to add. Values may be {@code null}.
+     * @since 3.0.0
+     */
+    default <V> void putValue(String key, V value) {
+        put(key, value != null ? value.toString() : null);
+    }
+
+    /**
+     * Puts all given key-value pairs into the collection.
+     *
+     * @param values the map of key-value pairs to add
+     * @param <V> The type of the value being added.
+     * @since 3.0.0
+     */
+    default <V> void putAllValues(Map<String, V> values) {
+        values.forEach(this::putValue);
+    }
 }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap2.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap2.java
index b48d5ab90b..1ec419da32 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap2.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap2.java
@@ -16,38 +16,14 @@
  */
 package org.apache.logging.log4j.spi;
 
-import java.util.Map;
-
-import org.apache.logging.log4j.util.StringMap;
-
 /**
- * Extension service provider interface to implement additional custom MDC 
behavior for
- * {@link org.apache.logging.log4j.ThreadContext}.
- *
- * Consider implementing {@link CleanableThreadContextMap} instead.
+ * Legacy interface for backward compatibility with extensions to 
ThreadContextMap.
+ * These methods have since been moved to default methods on ThreadContextMap.
  *
  * @see ThreadContextMap
  * @since 2.7
+ * @deprecated use {@link ThreadContextMap} directly
  */
+@Deprecated(since = "3.0.0")
 public interface ThreadContextMap2 extends ThreadContextMap {
-
-    /**
-     * Puts all given context map entries into the current thread's
-     * context map.
-     *
-     * <p>If the current thread does not have a context map it is
-     * created as a side effect.</p>
-     * @param map The map.
-     * @since 2.7
-     */
-    void putAll(final Map<String, String> map);
-
-    /**
-     * Returns the context data for reading. Note that regardless of whether 
the returned context data has been
-     * {@linkplain StringMap#freeze() frozen} (made read-only) or not, callers 
should not attempt to modify
-     * the returned data structure.
-     *
-     * @return the {@code StringMap}
-     */
-    StringMap getReadOnlyContextData();
 }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
index 74abfe51d3..a12a22538e 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
@@ -115,7 +115,7 @@ public class PropertiesUtil implements PropertyEnvironment {
      *
      * @return the main Log4j PropertiesUtil instance.
      */
-    public static PropertyEnvironment getProperties() {
+    public static PropertiesUtil getProperties() {
         return COMPONENT_PROPERTIES.value();
     }
 
diff --git 
a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/OpenHashStringMap.java
 
b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/OpenHashStringMap.java
index f976869278..942641506e 100644
--- 
a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/OpenHashStringMap.java
+++ 
b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/OpenHashStringMap.java
@@ -16,6 +16,12 @@
  */
 package org.apache.logging.log4j.perf.nogc;
 
+import org.apache.logging.log4j.spi.ThreadContextMap;
+import org.apache.logging.log4j.util.BiConsumer;
+import org.apache.logging.log4j.util.ReadOnlyStringMap;
+import org.apache.logging.log4j.util.StringMap;
+import org.apache.logging.log4j.util.TriConsumer;
+
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
@@ -26,12 +32,6 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 
-import org.apache.logging.log4j.util.ReadOnlyStringMap;
-import org.apache.logging.log4j.util.StringMap;
-import org.apache.logging.log4j.spi.ThreadContextMap;
-import org.apache.logging.log4j.util.BiConsumer;
-import org.apache.logging.log4j.util.TriConsumer;
-
 /**
  * Open hash map-based implementation of the {@code ReadOnlyStringMap} 
interface.
  * Implementation based on <a 
href="http://fastutil.di.unimi.it/";>fastutil</a>'s
@@ -485,7 +485,8 @@ public class OpenHashStringMap<K, V> implements StringMap, 
ThreadContextMap {
     }
 
     /** {@inheritDoc} */
-    public void putAll(final Map<? extends K, ? extends V> map) {
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void putAll(final Map map) {
         if (loadFactor <= .5) {
             // The resulting map will be sized for m.size() elements
             ensureCapacity(map.size());
@@ -493,9 +494,7 @@ public class OpenHashStringMap<K, V> implements StringMap, 
ThreadContextMap {
             // The resulting map will be tentatively sized for size() +  
m.size() elements
             tryCapacity(size() + map.size());
         }
-        for (final Map.Entry<? extends K, ? extends V> entry : map.entrySet()) 
{
-            putObjectValue(entry.getKey(), entry.getValue());
-        }
+        map.forEach((key, value) -> putObjectValue((K) key, (V) value));
     }
 
     private V putObjectValue(final K k, final V v) {
diff --git 
a/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java 
b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java
index b04d358236..f224d16ede 100644
--- a/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java
+++ b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java
@@ -16,18 +16,18 @@
  */
 package org.apache.logging.slf4j;
 
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.apache.logging.log4j.spi.CleanableThreadContextMap;
+import org.apache.logging.log4j.spi.ThreadContextMap;
 import org.apache.logging.log4j.util.SortedArrayStringMap;
 import org.apache.logging.log4j.util.StringMap;
 import org.slf4j.MDC;
 
+import java.util.Map;
+import java.util.Map.Entry;
+
 /**
  * Bind the ThreadContextMap to the SLF4J MDC.
  */
-public class MDCContextMap implements CleanableThreadContextMap {
+public class MDCContextMap implements ThreadContextMap {
 
     private static final StringMap EMPTY_CONTEXT_DATA = new 
SortedArrayStringMap(1);
     static {
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index d3f790c843..c96d40f79a 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -31,6 +31,9 @@
          - "remove" - Removed
     -->
     <release version="3.0.0" date="2022-MM-DD" description="GA Release 3.0.0">
+      <action issue="LOG4J2-3626" dev="mattsicker" type="update">
+        Flatten the ThreadContextMap interfaces with default methods.
+      </action>
       <action issue="LOG4J2-3300" dev="mattsicker" type="add">
         Add conditional annotations to support more declarative binding 
factory bundle classes.
       </action>

Reply via email to