From a3045f14c7ad58742cc9407bdc92c1c19b77abdc Mon Sep 17 00:00:00 2001
From: Roger Kapsi <rkapsi@squarespace.com>
Date: Fri, 19 Aug 2016 13:50:34 -0400
Subject: [PATCH] [LOG4J2-1531]: Adding ability to pass arbitary Objects into
 Plugins and PluginFactories for programatic/DSL configuration

---
 .../log4j/core/config/AbstractConfiguration.java   |  13 +--
 .../org/apache/logging/log4j/core/config/Node.java |  26 +++--
 .../log4j/core/config/builder/api/Component.java   |  41 +++++---
 .../core/config/builder/api/ComponentBuilder.java  |   9 ++
 .../core/config/builder/api/ComponentConfig.java   |  80 ++++++++++++++
 .../config/builder/api/ConfigurationBuilder.java   |  12 ++-
 .../config/builder/impl/BuiltConfiguration.java    |   2 +-
 .../builder/impl/DefaultComponentBuilder.java      |  31 ++++--
 .../builder/impl/DefaultConfigurationBuilder.java  |  13 ++-
 .../config/composite/CompositeConfiguration.java   |   4 +-
 .../config/composite/DefaultMergeStrategy.java     |  30 +++---
 .../log4j/core/config/json/JsonConfiguration.java  |  11 +-
 .../log4j/core/config/plugins/PluginArgument.java  |  40 +++++++
 .../log4j/core/config/plugins/PluginValue.java     |   2 +
 .../core/config/plugins/util/PluginBuilder.java    |   4 +-
 .../plugins/visitors/PluginArgumentVisitor.java    |  41 ++++++++
 .../plugins/visitors/PluginAttributeVisitor.java   |   2 +-
 .../visitors/PluginBuilderAttributeVisitor.java    |   2 +-
 .../plugins/visitors/PluginValueVisitor.java       |  12 ++-
 .../log4j/core/config/xml/XmlConfiguration.java    |   7 +-
 .../log4j/core/config/ComponentArgumentTest.java   | 115 +++++++++++++++++++++
 .../validators/RequiredValidatorTest.java          |   2 +-
 .../ValidatingPluginWithGenericBuilderTest.java    |   2 +-
 ...ngPluginWithGenericSubclassFoo1BuilderTest.java |   4 +-
 .../ValidatingPluginWithTypedBuilderTest.java      |   2 +-
 25 files changed, 427 insertions(+), 80 deletions(-)
 create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ComponentConfig.java
 create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginArgument.java
 create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginArgumentVisitor.java
 create mode 100644 log4j-core/src/test/java/org/apache/logging/log4j/core/config/ComponentArgumentTest.java

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
index a152ea7..21b2d37 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
@@ -44,6 +44,7 @@ import org.apache.logging.log4j.core.appender.ConsoleAppender;
 import org.apache.logging.log4j.core.async.AsyncLoggerConfig;
 import org.apache.logging.log4j.core.async.AsyncLoggerConfigDelegate;
 import org.apache.logging.log4j.core.async.AsyncLoggerConfigDisruptor;
+import org.apache.logging.log4j.core.config.builder.api.ComponentConfig;
 import org.apache.logging.log4j.core.config.plugins.util.PluginBuilder;
 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
@@ -394,12 +395,12 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
             final byte[] buffer, final String contentType) {
         if (advertiserString != null) {
             final Node node = new Node(null, advertiserString, null);
-            final Map<String, String> attributes = node.getAttributes();
-            attributes.put("content", new String(buffer));
-            attributes.put("contentType", contentType);
-            attributes.put("name", "configuration");
+            final ComponentConfig config = node.getComponentConfig();
+            config.putAttribute("content", new String(buffer));
+            config.putAttribute("contentType", contentType);
+            config.putAttribute("name", "configuration");
             if (configSource.getLocation() != null) {
-                attributes.put("location", configSource.getLocation());
+                config.putAttribute("location", configSource.getLocation());
             }
             advertiserNode = node;
         }
@@ -413,7 +414,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
                 final Class<? extends Advertiser> clazz = type.getPluginClass().asSubclass(Advertiser.class);
                 try {
                     advertiser = clazz.newInstance();
-                    advertisement = advertiser.advertise(advertiserNode.getAttributes());
+                    advertisement = advertiser.advertise(advertiserNode.getComponentConfig().getAttributes());
                 } catch (final InstantiationException e) {
                     LOGGER.error("InstantiationException attempting to instantiate advertiser: {}", nodeName, e);
                 } catch (final IllegalAccessException e) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
index c92c904..d01ed19 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
@@ -17,10 +17,10 @@
 package org.apache.logging.log4j.core.config;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.logging.log4j.core.config.builder.api.ComponentConfig;
 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
 
 /**
@@ -38,9 +38,9 @@ public class Node {
 
     private final Node parent;
     private final String name;
-    private String value;
+    private Object value;
     private final PluginType<?> type;
-    private final Map<String, String> attributes = new HashMap<>();
+    private final ComponentConfig config = new ComponentConfig();
     private final List<Node> children = new ArrayList<>();
     private Object object;
 
@@ -69,16 +69,24 @@ public class Node {
         this.parent = node.parent;
         this.name = node.name;
         this.type = node.type;
-        this.attributes.putAll(node.getAttributes());
+        this.config.putAll(node.getComponentConfig());
         this.value = node.getValue();
         for (final Node child : node.getChildren()) {
             this.children.add(new Node(child));
         }
         this.object = node.object;
     }
-
+    
+    public ComponentConfig getComponentConfig() {
+        return config;
+    }
+    
+    /**
+     * @deprecated Use {@link #getComponentConfig()}
+     */
+    @Deprecated
     public Map<String, String> getAttributes() {
-        return attributes;
+        return config.getAttributes();
     }
 
     public List<Node> getChildren() {
@@ -88,12 +96,12 @@ public class Node {
     public boolean hasChildren() {
         return !children.isEmpty();
     }
-
-    public String getValue() {
+    
+    public Object getValue() {
         return value;
     }
 
-    public void setValue(final String value) {
+    public void setValue(final Object value) {
         this.value = value;
     }
 
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/Component.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/Component.java
index 8ad901f..1edab60 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/Component.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/Component.java
@@ -17,7 +17,6 @@
 package org.apache.logging.log4j.core.config.builder.api;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -27,25 +26,30 @@ import java.util.Map;
  * @since 2.4
  */
 public class Component {
-
-    private final Map<String, String> attributes = new HashMap<>();
+    
+    private final ComponentConfig config = new ComponentConfig();
     private final List<Component> components = new ArrayList<>();
     private final String pluginType;
-    private final String value;
+    private final Object value;
 
     public Component(final String pluginType) {
-        this(pluginType, null, null);
+        this(pluginType, null, (String)null);
     }
 
     public Component(final String pluginType, final String name) {
-        this(pluginType, name, null);
+        this(pluginType, name, (String)null);
     }
-
+    
+    @Deprecated
     public Component(final String pluginType, final String name, final String value) {
+        this(pluginType, name, (Object)value);
+    }
+    
+    public Component(final String pluginType, final String name, final Object value) {
         this.pluginType = pluginType;
         this.value = value;
         if (name != null && name.length() > 0) {
-            attributes.put("name", name);
+            config.putAttribute("name", name);
         }
     }
 
@@ -54,17 +58,28 @@ public class Component {
         this.value = null;
     }
 
-
+    public Object addArgument(final String key, final Object value) {
+        return config.putArgument(key, value);
+    }
+    
     public String addAttribute(final String key, final String newValue) {
-        return attributes.put(key, newValue);
+        return config.putAttribute(key, newValue);
     }
 
     public void addComponent(final Component component) {
         components.add(component);
     }
 
+    public ComponentConfig getComponentConfig() {
+        return config;
+    }
+    
+    /**
+     * @deprecated Use {@link #getComponentConfig()}
+     */
+    @Deprecated
     public Map<String, String> getAttributes() {
-        return attributes;
+        return config.getAttributes();
     }
 
     public List<Component> getComponents() {
@@ -74,8 +89,8 @@ public class Component {
     public String getPluginType() {
         return pluginType;
     }
-
-    public String getValue() {
+    
+    public Object getValue() {
         return value;
     }
  }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ComponentBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ComponentBuilder.java
index 873c52f..7f0871a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ComponentBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ComponentBuilder.java
@@ -28,6 +28,15 @@ import org.apache.logging.log4j.core.util.Builder;
 public interface ComponentBuilder<T extends ComponentBuilder<T>> extends Builder<Component> {
 
     /**
+     * Adds a Object argument.
+     * 
+     * @param key The attribute key.
+     * @param value The value of the argument.
+     * @return This ComponentBuilder.
+     */
+    T addArgument(String key, Object value);
+    
+    /**
      * Adds a String attribute.
      * @param key The attribute key.
      * @param value The value of the attribute.
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ComponentConfig.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ComponentConfig.java
new file mode 100644
index 0000000..0eca739
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ComponentConfig.java
@@ -0,0 +1,80 @@
+/*
+ * 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.core.config.builder.api;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @see Component#getComponentConfig()
+ */
+public class ComponentConfig implements Cloneable {
+
+    private final Map<String, Object> arguments;
+
+    private final Map<String, String> attributes;
+
+    public ComponentConfig() {
+        this(new HashMap<String, Object>(), new HashMap<String, String>());
+    }
+
+    private ComponentConfig(final Map<String, Object> arguments, final Map<String, String> attributes) {
+        this.arguments = arguments;
+        this.attributes = attributes;
+    }
+
+    public void putAll(final ComponentConfig config) {
+        if (config != this) {
+            arguments.putAll(config.arguments);
+            attributes.putAll(config.attributes);
+        }
+    }
+
+    public Map<String, Object> getArguments() {
+        return arguments;
+    }
+
+    public Object putArgument(final String key, final Object value) {
+        return arguments.put(key, value);
+    }
+
+    public Object getArgument(final String key) {
+        return arguments.get(key);
+    }
+
+    public Map<String, String> getAttributes() {
+        return attributes;
+    }
+
+    public String putAttribute(final String key, final String value) {
+        return attributes.put(key, value);
+    }
+
+    public String getAttribute(final String key) {
+        return attributes.get(key);
+    }
+
+    @Override
+    public ComponentConfig clone() {
+        return new ComponentConfig(new HashMap<>(arguments), new HashMap<>(attributes));
+    }
+
+    @Override
+    public String toString() {
+        return "arguments=" + arguments + ", attributes=" + attributes;
+    }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
index 1fbfa01..c0e0efd 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
@@ -220,9 +220,19 @@ public interface ConfigurationBuilder<T extends Configuration> extends Builder<T
      * @param value The value of the component.
      * @return A new ComponentBuilder.
      */
+    @Deprecated
     <B extends ComponentBuilder<B>> ComponentBuilder<B> newComponent(String name, String pluginName, String value);
 
-
+    /**
+     * Returns a builder for creating generic components.
+     * @param <B> ComponentBuilder target type
+     * @param name The name of the component (may be null).
+     * @param pluginName The Plugin type of the component.
+     * @param value The value of the component.
+     * @return A new ComponentBuilder.
+     */
+    <B extends ComponentBuilder<B>> ComponentBuilder<B> newComponent(String name, String pluginName, Object value);
+    
     /**
      * Returns a builder for creating CustomLevels
      * @param name The name of the custom level.
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
index 029caf2..c6663bf 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
@@ -171,7 +171,7 @@ public class BuiltConfiguration extends AbstractConfiguration {
         final String name = component.getPluginType();
         final PluginType<?> pluginType = pluginManager.getPluginType(name);
         final Node node = new Node(parent, name, pluginType);
-        node.getAttributes().putAll(component.getAttributes());
+        node.getComponentConfig().putAll(component.getComponentConfig());
         node.setValue(component.getValue());
         final List<Node> children = node.getChildren();
         for (final Component child : component.getComponents()) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultComponentBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultComponentBuilder.java
index d1c066c..6af272a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultComponentBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultComponentBuilder.java
@@ -17,14 +17,13 @@
 package org.apache.logging.log4j.core.config.builder.impl;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.builder.api.Component;
 import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ComponentConfig;
 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
 
 /**
@@ -38,27 +37,40 @@ class DefaultComponentBuilder<T extends ComponentBuilder<T>, CB extends Configur
 
     private final CB builder;
     private final String type;
-    private final Map<String, String> attributes = new HashMap<>();
+    private final ComponentConfig config = new ComponentConfig();
     private final List<Component> components = new ArrayList<>();
     private final String name;
-    private final String value;
+    private final Object value;
 
     public DefaultComponentBuilder(final CB builder, final String type) {
-        this(builder, null, type, null);
+        this(builder, null, type, (String)null);
     }
 
     public DefaultComponentBuilder(final CB builder, final String name, final String type) {
-        this(builder, name, type, null);
+        this(builder, name, type, (String)null);
     }
-
+    
+    @Deprecated
     public DefaultComponentBuilder(final CB builder, final String name, final String type,
             final String value) {
+        this(builder, name, type, (Object)value);
+    }
+    
+    public DefaultComponentBuilder(final CB builder, final String name, final String type,
+            final Object value) {
         this.type = type;
         this.builder = builder;
         this.name = name;
         this.value = value;
     }
 
+    @SuppressWarnings("unchecked")
+    @Override
+    public T addArgument(String key, Object value) {
+        config.putArgument(key, value);
+        return (T)this;
+    }
+
     @Override
     public T addAttribute(final String key, final boolean value) {
         return put(key, Boolean.toString(value));
@@ -74,7 +86,6 @@ class DefaultComponentBuilder<T extends ComponentBuilder<T>, CB extends Configur
         return put(key, Integer.toString(value));
     }
 
-
     @Override
     public T addAttribute(final String key, final Level level) {
         return put(key, level.toString());
@@ -101,7 +112,7 @@ class DefaultComponentBuilder<T extends ComponentBuilder<T>, CB extends Configur
     @Override
     public Component build() {
         final Component component = new Component(type, name, value);
-        component.getAttributes().putAll(attributes);
+        component.getComponentConfig().putAll(config);
         component.getComponents().addAll(components);
         return component;
     }
@@ -118,7 +129,7 @@ class DefaultComponentBuilder<T extends ComponentBuilder<T>, CB extends Configur
 
     @SuppressWarnings("unchecked")
     protected T put(final String key, final String value) {
-        attributes.put(key, value);
+        config.putAttribute(key, value);
         return (T) this;
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java
index 38b4fdb..e72dea8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java
@@ -155,7 +155,7 @@ public class DefaultConfigurationBuilder<T extends BuiltConfiguration> implement
             final Constructor<T> constructor = clazz.getConstructor(ConfigurationSource.class, Component.class);
             configuration = constructor.newInstance(source, root);
             configuration.setMonitorInterval(monitorInterval);
-            configuration.getRootNode().getAttributes().putAll(root.getAttributes());
+            configuration.getRootNode().getComponentConfig().putAll(root.getComponentConfig());
             if (name != null) {
                 configuration.setName(name);
             }
@@ -265,12 +265,19 @@ public class DefaultConfigurationBuilder<T extends BuiltConfiguration> implement
     }
 
     @Override
+    @Deprecated
     public <B extends ComponentBuilder<B>> ComponentBuilder<B> newComponent(final String name, final String type,
                                                                             final String value) {
+        return newComponent(name, type, (Object)value);
+    }
+    
+    
+    @Override
+    public <B extends ComponentBuilder<B>> ComponentBuilder<B> newComponent(final String name, final String type, 
+                                                                            final Object value) {
         return new DefaultComponentBuilder<>(this, name, type, value);
     }
 
-
     @Override
     public CustomLevelComponentBuilder newCustomLevel(final String name, final int level) {
         return new DefaultCustomLevelComponentBuilder(this, name, level);
@@ -401,7 +408,7 @@ public class DefaultConfigurationBuilder<T extends BuiltConfiguration> implement
 
     @Override
     public ConfigurationBuilder<T> addRootProperty(final String key, final String value) {
-        root.getAttributes().put(key, value);
+        root.getComponentConfig().putAttribute(key, value);
         return this;
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
index f272fc1..78712c7 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
@@ -78,7 +78,7 @@ public class CompositeConfiguration extends AbstractConfiguration implements Rec
         }
         final StatusConfiguration statusConfig = new StatusConfiguration().withVerboseClasses(VERBOSE_CLASSES)
                 .withStatus(getDefaultStatus());
-        for (final Map.Entry<String, String> entry : rootNode.getAttributes().entrySet()) {
+        for (final Map.Entry<String, String> entry : rootNode.getComponentConfig().getAttributes().entrySet()) {
             final String key = entry.getKey();
             final String value = getStrSubstitutor().replace(entry.getValue());
             if ("status".equalsIgnoreCase(key)) {
@@ -175,7 +175,7 @@ public class CompositeConfiguration extends AbstractConfiguration implements Rec
 
     private void printNodes(final String indent, final Node node, final StringBuilder sb) {
         sb.append(indent).append(node.getName()).append(" type: ").append(node.getType()).append("\n");
-        sb.append(indent).append(node.getAttributes().toString()).append("\n");
+        sb.append(indent).append(node.getComponentConfig().getAttributes()).append("\n");
         for (final Node child : node.getChildren()) {
             printNodes(indent + "  ", child, sb);
         }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java
index c799e1d..ca103cc 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java
@@ -69,9 +69,9 @@ public class DefaultMergeStrategy implements MergeStrategy {
      */
     @Override
     public void mergeRootProperties(final Node rootNode, final AbstractConfiguration configuration) {
-        for (final Map.Entry<String, String> attribute : configuration.getRootNode().getAttributes().entrySet()) {
+        for (final Map.Entry<String, String> attribute : configuration.getRootNode().getComponentConfig().getAttributes().entrySet()) {
             boolean isFound = false;
-            for (final Map.Entry<String, String> targetAttribute : rootNode.getAttributes().entrySet()) {
+            for (final Map.Entry<String, String> targetAttribute : rootNode.getComponentConfig().getAttributes().entrySet()) {
                 if (targetAttribute.getKey().equalsIgnoreCase(attribute.getKey())) {
                     if (attribute.getKey().equalsIgnoreCase(STATUS)) {
                         final Level targetLevel = Level.getLevel(targetAttribute.getValue().toUpperCase());
@@ -99,7 +99,7 @@ public class DefaultMergeStrategy implements MergeStrategy {
                 }
             }
             if (!isFound) {
-                rootNode.getAttributes().put(attribute.getKey(), attribute.getValue());
+                rootNode.getComponentConfig().putAttribute(attribute.getKey(), attribute.getValue());
             }
         }
     }
@@ -136,7 +136,7 @@ public class DefaultMergeStrategy implements MergeStrategy {
                     case APPENDERS: {
                         for (final Node node : sourceChildNode.getChildren()) {
                             for (final Node targetNode : targetChildNode.getChildren()) {
-                                if (targetNode.getAttributes().get(NAME).equals(node.getAttributes().get(NAME))) {
+                                if (targetNode.getComponentConfig().getAttribute(NAME).equals(node.getComponentConfig().getAttribute(NAME))) {
                                     targetChildNode.getChildren().remove(targetNode);
                                     break;
                                 }
@@ -152,7 +152,7 @@ public class DefaultMergeStrategy implements MergeStrategy {
                             targetLoggers.put(node.getName(), node);
                         }
                         for (final Node node : sourceChildNode.getChildren()) {
-                            final Node targetNode = getLoggerNode(targetChildNode, node.getAttributes().get(NAME));
+                            final Node targetNode = getLoggerNode(targetChildNode, node.getComponentConfig().getAttribute(NAME));
                             final Node loggerNode = new Node(targetChildNode, node.getName(), node.getType());
                             if (targetNode != null) {
                                 for (final Node sourceLoggerChild : node.getChildren()) {
@@ -174,7 +174,7 @@ public class DefaultMergeStrategy implements MergeStrategy {
                                     } else {
                                         final Node childNode = new Node(loggerNode, sourceLoggerChild.getName(),
                                                 sourceLoggerChild.getType());
-                                        childNode.getAttributes().putAll(sourceLoggerChild.getAttributes());
+                                        childNode.getComponentConfig().putAll(sourceLoggerChild.getComponentConfig());
                                         if (childNode.getName().equalsIgnoreCase("AppenderRef")) {
                                             for (final Node targetChild : targetNode.getChildren()) {
                                                 if (isSameReference(targetChild, childNode)) {
@@ -195,7 +195,7 @@ public class DefaultMergeStrategy implements MergeStrategy {
                                     }
                                 }
                             } else {
-                                loggerNode.getAttributes().putAll(node.getAttributes());
+                                loggerNode.getComponentConfig().putAll(node.getComponentConfig());
                                 loggerNode.getChildren().addAll(node.getChildren());
                                 targetChildNode.getChildren().add(loggerNode);
                             }
@@ -223,7 +223,7 @@ public class DefaultMergeStrategy implements MergeStrategy {
 
     private Node getLoggerNode(final Node parentNode, final String name) {
         for (final Node node : parentNode.getChildren()) {
-            final String nodeName = node.getAttributes().get(NAME);
+            final String nodeName = node.getComponentConfig().getAttribute(NAME);
             if (name == null && nodeName == null) {
                 return node;
             }
@@ -239,13 +239,13 @@ public class DefaultMergeStrategy implements MergeStrategy {
         if (CompositeFilter.class.isAssignableFrom(targetChildNode.getType().getPluginClass())) {
             final Node node = new Node(targetChildNode, sourceChildNode.getName(), sourceChildNode.getType());
             node.getChildren().addAll(sourceChildNode.getChildren());
-            node.getAttributes().putAll(sourceChildNode.getAttributes());
+            node.getComponentConfig().putAll(sourceChildNode.getComponentConfig());
             targetChildNode.getChildren().add(node);
         } else {
-            final PluginType pluginType = pluginManager.getPluginType(FILTERS);
+            final PluginType<?> pluginType = pluginManager.getPluginType(FILTERS);
             final Node filtersNode = new Node(targetChildNode, FILTERS, pluginType);
             final Node node = new Node(filtersNode, sourceChildNode.getName(), sourceChildNode.getType());
-            node.getAttributes().putAll(sourceChildNode.getAttributes());
+            node.getComponentConfig().putAll(sourceChildNode.getComponentConfig());
             final List<Node> children = filtersNode.getChildren();
             children.add(targetChildNode);
             children.add(node);
@@ -260,12 +260,12 @@ public class DefaultMergeStrategy implements MergeStrategy {
     }
 
     private boolean isSameName(final Node node1, final Node node2) {
-        final String value = node1.getAttributes().get(NAME);
-        return value != null && value.toLowerCase().equals(node2.getAttributes().get(NAME).toLowerCase());
+        final String value = node1.getComponentConfig().getAttribute(NAME);
+        return value != null && value.toLowerCase().equals(node2.getComponentConfig().getAttribute(NAME).toLowerCase());
     }
 
     private boolean isSameReference(final Node node1, final Node node2) {
-        final String value = node1.getAttributes().get(REF);
-        return value != null && value.toLowerCase().equals(node2.getAttributes().get(REF).toLowerCase());
+        final String value = node1.getComponentConfig().getAttribute(REF);
+        return value != null && value.toLowerCase().equals(node2.getComponentConfig().getAttribute(REF).toLowerCase());
     }
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfiguration.java
index 427fa6d..ec02cab 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfiguration.java
@@ -26,9 +26,6 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.logging.log4j.core.config.AbstractConfiguration;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.ConfigurationSource;
@@ -42,6 +39,10 @@ import org.apache.logging.log4j.core.config.status.StatusConfiguration;
 import org.apache.logging.log4j.core.util.FileWatcher;
 import org.apache.logging.log4j.core.util.Patterns;
 
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 /**
  * Creates a Node hierarchy from a JSON file.
  */
@@ -69,7 +70,7 @@ public class JsonConfiguration extends AbstractConfiguration implements Reconfig
             processAttributes(rootNode, root);
             final StatusConfiguration statusConfig = new StatusConfiguration().withVerboseClasses(VERBOSE_CLASSES)
                     .withStatus(getDefaultStatus());
-            for (final Map.Entry<String, String> entry : rootNode.getAttributes().entrySet()) {
+            for (final Map.Entry<String, String> entry : rootNode.getComponentConfig().getAttributes().entrySet()) {
                 final String key = entry.getKey();
                 final String value = getStrSubstitutor().replace(entry.getValue());
                 // TODO: this duplicates a lot of the XmlConfiguration constructor
@@ -228,7 +229,7 @@ public class JsonConfiguration extends AbstractConfiguration implements Reconfig
     }
 
     private void processAttributes(final Node parent, final JsonNode node) {
-        final Map<String, String> attrs = parent.getAttributes();
+        final Map<String, String> attrs = parent.getComponentConfig().getAttributes();
         final Iterator<Map.Entry<String, JsonNode>> iter = node.fields();
         while (iter.hasNext()) {
             final Map.Entry<String, JsonNode> entry = iter.next();
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginArgument.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginArgument.java
new file mode 100644
index 0000000..ac17b1f
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginArgument.java
@@ -0,0 +1,40 @@
+/*
+ * 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.core.config.plugins;
+
+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;
+
+import org.apache.logging.log4j.core.config.plugins.visitors.PluginArgumentVisitor;
+
+/**
+ * Identifies a Plugin argument.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER, ElementType.FIELD})
+@PluginVisitorStrategy(PluginArgumentVisitor.class)
+public @interface PluginArgument {
+    
+    /**
+     * Specifies the name of the argument (case-insensitive) this annotation corresponds to.
+     */
+    String value();
+}
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 9c20cc2..7cf0adf 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
@@ -37,4 +37,6 @@ import org.apache.logging.log4j.core.config.plugins.visitors.PluginValueVisitor;
 public @interface PluginValue {
 
     String value();
+    
+    boolean useRawValue() default false;
 }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java
index 8da7356..0ea59d0 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java
@@ -23,8 +23,6 @@ import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -285,7 +283,7 @@ public class PluginBuilder implements Builder<Object> {
     }
 
     private void checkForRemainingAttributes() {
-        final Map<String, String> attrs = node.getAttributes();
+        final Map<String, String> attrs = node.getComponentConfig().getAttributes();
         if (!attrs.isEmpty()) {
             final StringBuilder sb = new StringBuilder();
             for (final String key : attrs.keySet()) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginArgumentVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginArgumentVisitor.java
new file mode 100644
index 0000000..7dd27c2
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginArgumentVisitor.java
@@ -0,0 +1,41 @@
+/*
+ * 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.core.config.plugins.visitors;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.core.config.builder.api.ComponentConfig;
+import org.apache.logging.log4j.core.config.plugins.PluginArgument;
+
+/**
+ * PluginVisitor implementation for {@link PluginArgument}.
+ */
+public class PluginArgumentVisitor extends AbstractPluginVisitor<PluginArgument> {
+    public PluginArgumentVisitor() {
+        super(PluginArgument.class);
+    }
+
+    @Override
+    public Object visit(final Configuration configuration, final Node node, final LogEvent event,
+                        final StringBuilder log) {
+        final String name = this.annotation.value();
+        final ComponentConfig config = node.getComponentConfig();
+        return config.getArgument(name);
+    }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
index f4da42b..e7c1e4f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
@@ -38,7 +38,7 @@ public class PluginAttributeVisitor extends AbstractPluginVisitor<PluginAttribut
     public Object visit(final Configuration configuration, final Node node, final LogEvent event,
                         final StringBuilder log) {
         final String name = this.annotation.value();
-        final Map<String, String> attributes = node.getAttributes();
+        final Map<String, String> attributes = node.getComponentConfig().getAttributes();
         final String rawValue = removeAttributeValue(attributes, name, this.aliases);
         final String replacedValue = this.substitutor.replace(event, rawValue);
         final Object defaultValue = findDefaultValue(event);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
index e951456..72f4c02 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
@@ -44,7 +44,7 @@ public class PluginBuilderAttributeVisitor extends AbstractPluginVisitor<PluginB
                         final StringBuilder log) {
         final String overridden = this.annotation.value();
         final String name = overridden.isEmpty() ? this.member.getName() : overridden;
-        final Map<String, String> attributes = node.getAttributes();
+        final Map<String, String> attributes = node.getComponentConfig().getAttributes();
         final String rawValue = removeAttributeValue(attributes, name, this.aliases);
         final String replacedValue = this.substitutor.replace(event, rawValue);
         final Object value = convert(replacedValue, null);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
index 82dc20d..9b1cb86 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
@@ -17,6 +17,8 @@
 
 package org.apache.logging.log4j.core.config.plugins.visitors;
 
+import java.util.Objects;
+
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.Node;
@@ -36,8 +38,14 @@ public class PluginValueVisitor extends AbstractPluginVisitor<PluginValue> {
     public Object visit(final Configuration configuration, final Node node, final LogEvent event,
                         final StringBuilder log) {
         final String name = this.annotation.value();
-        final String rawValue = Strings.isNotEmpty(node.getValue()) ? node.getValue() :
-                removeAttributeValue(node.getAttributes(), "value");
+
+        if (this.annotation.useRawValue()) {
+            return node.getValue();
+        }
+        
+        final String stringValue = Objects.toString(node.getValue());
+        final String rawValue = Strings.isNotEmpty(stringValue) ? stringValue :
+                removeAttributeValue(node.getComponentConfig().getAttributes(), "value");
         final String value = this.substitutor.replace(event, rawValue);
         StringBuilders.appendKeyDqValue(log, name, value);
         return value;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
index ea3f753..cddd6fe 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
@@ -24,6 +24,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
@@ -279,9 +280,9 @@ public class XmlConfiguration extends AbstractConfiguration implements Reconfigu
                 final Node childNode = new Node(node, name, type);
                 constructHierarchy(childNode, child);
                 if (type == null) {
-                    final String value = childNode.getValue();
+                    final String value = Objects.toString(childNode.getValue());
                     if (!childNode.hasChildren() && value != null) {
-                        node.getAttributes().put(name, value);
+                        node.getComponentConfig().putAttribute(name, value);
                     } else {
                         status.add(new Status(name, element, ErrorType.CLASS_NOT_FOUND));
                     }
@@ -320,7 +321,7 @@ public class XmlConfiguration extends AbstractConfiguration implements Reconfigu
 
     private Map<String, String> processAttributes(final Node node, final Element element) {
         final NamedNodeMap attrs = element.getAttributes();
-        final Map<String, String> attributes = node.getAttributes();
+        final Map<String, String> attributes = node.getComponentConfig().getAttributes();
 
         for (int i = 0; i < attrs.getLength(); ++i) {
             final org.w3c.dom.Node w3cNode = attrs.item(i);
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/ComponentArgumentTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/ComponentArgumentTest.java
new file mode 100644
index 0000000..b81ea9c
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/ComponentArgumentTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.core.config;
+
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
+import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginArgument;
+import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.filter.AbstractFilter;
+import org.junit.Test;
+
+public class ComponentArgumentTest {
+    
+    /**
+     * This is a function we want to pass into {@link JavaFunctionFilter}.
+     */
+    public static interface Function<U, R> {
+        public R apply(U u);
+    }
+    
+    @Test
+    public void testArgument() throws Exception {
+        final Object message = "Hello, World!";
+        
+        final CountDownLatch latch = new CountDownLatch(1);
+        Function<Object, Boolean> fn = new Function<Object, Boolean>() {
+            @Override
+            public Boolean apply(Object msg) {
+                if (msg != null && msg.equals(message)) {
+                    latch.countDown();
+                    return true;
+                }
+                return false;
+            }
+        };
+        
+        String pkg = ComponentArgumentTest.class.getClass().getPackage().getName();
+        
+        ConfigurationBuilder<BuiltConfiguration> builder 
+                = ConfigurationBuilderFactory.newConfigurationBuilder();
+        
+        builder.setPackages(pkg);
+        builder.add(builder.newFilter("JavaFunctionFilter", Filter.Result.DENY, Filter.Result.NEUTRAL)
+                .addArgument("fn", fn));
+        
+        BuiltConfiguration configuration = builder.build();
+        
+        Configurator.initialize(configuration);
+        
+        Logger logger = LogManager.getLogger(ComponentArgumentTest.class);
+        logger.fatal(message);
+        
+        if (!latch.await(5L, TimeUnit.SECONDS)) {
+            throw new IllegalStateException();
+        }
+        
+        // ... and you should see no output.
+    }
+    
+    @Plugin(name = "JavaFunctionFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
+    public static class JavaFunctionFilter extends AbstractFilter {
+      
+        @PluginFactory
+        public static JavaFunctionFilter createFilter(
+              @PluginArgument("fn") Function<Object, Boolean> fn,
+              @PluginAttribute("onMatch") Filter.Result onMatch,
+              @PluginAttribute("onMisMatch") Filter.Result onMisMatch) {
+          
+            return new JavaFunctionFilter(fn, onMatch, onMisMatch);
+        }
+          
+        private final Function<Object, Boolean> fn;
+    
+        private JavaFunctionFilter(Function<Object, Boolean> fn, 
+                Filter.Result onMatch, Filter.Result onMisMatch) {
+            super(onMatch, onMisMatch);
+            
+            this.fn = Objects.requireNonNull(fn);
+        }
+
+        @Override
+        public Result filter(org.apache.logging.log4j.core.Logger logger, 
+                Level level, Marker marker, Object msg, Throwable t) {
+            
+            Boolean value = fn.apply(msg);
+            return value == null || !Boolean.TRUE.equals(value) ? onMismatch : onMatch;
+        }
+    }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidatorTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidatorTest.java
index 15a51ae..ad85963 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidatorTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidatorTest.java
@@ -53,7 +53,7 @@ public class RequiredValidatorTest {
 
     @Test
     public void testNonNullValue() throws Exception {
-        node.getAttributes().put("name", "foo");
+        node.getComponentConfig().putAttribute("name", "foo");
         final ValidatingPlugin validatingPlugin = (ValidatingPlugin) new PluginBuilder(plugin)
             .withConfiguration(new NullConfiguration())
             .withConfigurationNode(node)
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
index 8e02f20..71607d4 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
@@ -55,7 +55,7 @@ public class ValidatingPluginWithGenericBuilderTest {
 
     @Test
     public void testNonNullValue() throws Exception {
-        node.getAttributes().put("name", "foo");
+        node.getComponentConfig().putAttribute("name", "foo");
         final ValidatingPluginWithGenericBuilder validatingPlugin = (ValidatingPluginWithGenericBuilder) new PluginBuilder(plugin)
             .withConfiguration(new NullConfiguration())
             .withConfigurationNode(node)
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericSubclassFoo1BuilderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericSubclassFoo1BuilderTest.java
index d6f3966..3c848c0 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericSubclassFoo1BuilderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericSubclassFoo1BuilderTest.java
@@ -55,8 +55,8 @@ public class ValidatingPluginWithGenericSubclassFoo1BuilderTest {
 
     @Test
     public void testNonNullValue() throws Exception {
-        node.getAttributes().put("thing", "thing1");
-        node.getAttributes().put("foo1", "foo1");
+        node.getComponentConfig().putAttribute("thing", "thing1");
+        node.getComponentConfig().putAttribute("foo1", "foo1");
         final PluginWithGenericSubclassFoo1Builder validatingPlugin = (PluginWithGenericSubclassFoo1Builder) new PluginBuilder(plugin)
             .withConfiguration(new NullConfiguration())
             .withConfigurationNode(node)
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithTypedBuilderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithTypedBuilderTest.java
index ae236b4..32517ff 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithTypedBuilderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithTypedBuilderTest.java
@@ -58,7 +58,7 @@ public class ValidatingPluginWithTypedBuilderTest {
 
     @Test
     public void testNonNullValue() throws Exception {
-        node.getAttributes().put("name", "foo");
+        node.getComponentConfig().putAttribute("name", "foo");
         // @formatter:off
         final ValidatingPluginWithTypedBuilder validatingPlugin = (ValidatingPluginWithTypedBuilder) 
                 new PluginBuilder(plugin).
-- 
2.9.3

