SHIRO-501 - Add support for String interpolation

If the optional dependency 'commons-configuration2' is on the classpath String 
interpolation will be available.
String prefixes 'sys', 'env' and 'const' which provide system properties, 
environment variables, and field constants respectively.


Project: http://git-wip-us.apache.org/repos/asf/shiro/repo
Commit: http://git-wip-us.apache.org/repos/asf/shiro/commit/af75fb58
Tree: http://git-wip-us.apache.org/repos/asf/shiro/tree/af75fb58
Diff: http://git-wip-us.apache.org/repos/asf/shiro/diff/af75fb58

Branch: refs/heads/master
Commit: af75fb584ef6981c3c5263d00a396ec5f900716c
Parents: f9fb8b9
Author: Brian Demers <bdem...@apache.org>
Authored: Mon Oct 3 12:22:30 2016 -0400
Committer: Brian Demers <bdem...@apache.org>
Committed: Tue Oct 18 12:46:13 2016 -0400

----------------------------------------------------------------------
 config/ogdl/pom.xml                             |   6 +
 .../shiro/config/CommonsInterpolator.java       |  72 +++++++++
 .../shiro/config/DefaultInterpolator.java       |  39 +++++
 .../org/apache/shiro/config/Interpolator.java   |  35 +++++
 .../apache/shiro/config/ReflectionBuilder.java  |  17 ++-
 .../shiro/config/CommonsInterpolatorTest.groovy |  57 +++++++
 .../shiro/config/DefaultInterpolatorTest.groovy |  48 ++++++
 .../shiro/config/ReflectionBuilderTest.groovy   | 148 +++++++++++++++++++
 .../org/apache/shiro/config/SimpleBean.groovy   |   1 +
 pom.xml                                         |  14 ++
 10 files changed, 436 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/shiro/blob/af75fb58/config/ogdl/pom.xml
----------------------------------------------------------------------
diff --git a/config/ogdl/pom.xml b/config/ogdl/pom.xml
index ad85a21..cdfa47e 100644
--- a/config/ogdl/pom.xml
+++ b/config/ogdl/pom.xml
@@ -68,6 +68,12 @@
             <artifactId>commons-beanutils</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-configuration2</artifactId>
+            <optional>true</optional>
+        </dependency>
+
         <!-- Test dependencies: -->
         <dependency>
             <groupId>org.slf4j</groupId>

http://git-wip-us.apache.org/repos/asf/shiro/blob/af75fb58/config/ogdl/src/main/java/org/apache/shiro/config/CommonsInterpolator.java
----------------------------------------------------------------------
diff --git 
a/config/ogdl/src/main/java/org/apache/shiro/config/CommonsInterpolator.java 
b/config/ogdl/src/main/java/org/apache/shiro/config/CommonsInterpolator.java
new file mode 100644
index 0000000..0d1c7fc
--- /dev/null
+++ b/config/ogdl/src/main/java/org/apache/shiro/config/CommonsInterpolator.java
@@ -0,0 +1,72 @@
+/*
+ * 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.shiro.config;
+
+import org.apache.commons.configuration2.interpol.ConfigurationInterpolator;
+import org.apache.commons.configuration2.interpol.ConstantLookup;
+import org.apache.commons.configuration2.interpol.EnvironmentLookup;
+import org.apache.commons.configuration2.interpol.SystemPropertiesLookup;
+
+/**
+ * Commons-Config interpolation wrapper. This implementation uses a {@link 
ConfigurationInterpolator} with the default
+ * lookup: <code>sys</code> (system properties), <code>env</code> (environment 
variables>, and <code>const</code> (constants).
+ *
+ * <table>
+ *     <tr>
+ *         <th>lookup</th>
+ *         <th>example</th>
+ *         <th>value</th>
+ *     </tr>
+ *     <tr>
+ *         <td>sys</td>
+ *         <td>${sys:os.name}</td>
+ *         <td>mac os x</td>
+ *     </tr>
+ *     <tr>
+ *         <td>env</td>
+ *         <td>${env:EDITOR}</td>
+ *         <td>vi</td>
+ *     </tr>
+ *     <tr>
+ *         <td>const</td>
+ *         <td>${const:java.awt.event.KeyEvent.VK_ENTER}</td>
+ *         <td>\n</td>
+ *     </tr>
+ * </table>
+ *
+ * @see ConfigurationInterpolator
+ * @since 1.4
+ */
+public class CommonsInterpolator implements Interpolator {
+
+    final private ConfigurationInterpolator interpolator;
+
+    public CommonsInterpolator() {
+        this.interpolator = new ConfigurationInterpolator();
+
+        interpolator.registerLookup("const", new ConstantLookup());
+        interpolator.addDefaultLookup(new SystemPropertiesLookup());
+        interpolator.addDefaultLookup(new EnvironmentLookup());
+    }
+
+    @Override
+    public String interpolate(String value) {
+        return (String) interpolator.interpolate(value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/af75fb58/config/ogdl/src/main/java/org/apache/shiro/config/DefaultInterpolator.java
----------------------------------------------------------------------
diff --git 
a/config/ogdl/src/main/java/org/apache/shiro/config/DefaultInterpolator.java 
b/config/ogdl/src/main/java/org/apache/shiro/config/DefaultInterpolator.java
new file mode 100644
index 0000000..8addd2f
--- /dev/null
+++ b/config/ogdl/src/main/java/org/apache/shiro/config/DefaultInterpolator.java
@@ -0,0 +1,39 @@
+/*
+ * 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.shiro.config;
+
+/**
+ * This {@link Interpolator} simply returns the original value.  This is 
implementation is useful when interpolation
+ * is not desired.
+ *
+ * @since 1.4
+ */
+public class DefaultInterpolator implements Interpolator {
+
+    /**
+     * Simply returns the original <code>value</code>.
+     *
+     * @param value value to be interpolated.
+     * @return Simply returns the original <code>value</code>.
+     */
+    @Override
+    public String interpolate(String value) {
+        return value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/af75fb58/config/ogdl/src/main/java/org/apache/shiro/config/Interpolator.java
----------------------------------------------------------------------
diff --git 
a/config/ogdl/src/main/java/org/apache/shiro/config/Interpolator.java 
b/config/ogdl/src/main/java/org/apache/shiro/config/Interpolator.java
new file mode 100644
index 0000000..0de933e
--- /dev/null
+++ b/config/ogdl/src/main/java/org/apache/shiro/config/Interpolator.java
@@ -0,0 +1,35 @@
+/*
+ * 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.shiro.config;
+
+/**
+ * Basic String interpolation interface.  Typically implementations will use 
the Maven/Ant like notation: ${key}, but
+ * This is up to the implementation.
+ *
+ * @since 1.4
+ */
+public interface Interpolator {
+
+    /**
+     * Interpolates <code>value</code> and returns the result.
+     * @param value the source text
+     * @return the String result of the interpolation, or <code>value</code>, 
if there was not change.
+     */
+    String interpolate(String value);
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/af75fb58/config/ogdl/src/main/java/org/apache/shiro/config/ReflectionBuilder.java
----------------------------------------------------------------------
diff --git 
a/config/ogdl/src/main/java/org/apache/shiro/config/ReflectionBuilder.java 
b/config/ogdl/src/main/java/org/apache/shiro/config/ReflectionBuilder.java
index 22a05f7..af4fa06 100644
--- a/config/ogdl/src/main/java/org/apache/shiro/config/ReflectionBuilder.java
+++ b/config/ogdl/src/main/java/org/apache/shiro/config/ReflectionBuilder.java
@@ -83,6 +83,8 @@ public class ReflectionBuilder {
 
     private static final String EVENT_BUS_NAME = "eventBus";
 
+    private final Interpolator interpolator;
+
     private final Map<String, Object> objects;
     /**
      * @since 1.3
@@ -110,6 +112,9 @@ public class ReflectionBuilder {
     }
 
     public ReflectionBuilder(Map<String, ?> defaults) {
+
+        this.interpolator = createInterpolator();
+
         this.objects = createDefaultObjectMap();
         this.registeredEventSubscribers = new LinkedHashMap<String,Object>();
         apply(defaults);
@@ -247,7 +252,8 @@ public class ReflectionBuilder {
 
             for (Map.Entry<String, String> entry : kvPairs.entrySet()) {
                 String lhs = entry.getKey();
-                String rhs = entry.getValue();
+                String rhs = (String) 
interpolator.interpolate(entry.getValue());
+//                String rhs = entry.getValue();
 
                 String beanId = parseBeanId(lhs);
                 if (beanId != null) { //a beanId could be parsed, so the line 
is a bean instance definition
@@ -719,6 +725,15 @@ public class ReflectionBuilder {
         applyProperty(object, propertyName, value);
     }
 
+    private Interpolator createInterpolator() {
+
+        if 
(ClassUtils.isAvailable("org.apache.commons.configuration2.interpol.ConfigurationInterpolator"))
 {
+            return new CommonsInterpolator();
+        }
+
+        return new DefaultInterpolator();
+    }
+
     private class BeanConfigurationProcessor {
 
         private final List<Statement> statements = new ArrayList<Statement>();

http://git-wip-us.apache.org/repos/asf/shiro/blob/af75fb58/config/ogdl/src/test/groovy/org/apache/shiro/config/CommonsInterpolatorTest.groovy
----------------------------------------------------------------------
diff --git 
a/config/ogdl/src/test/groovy/org/apache/shiro/config/CommonsInterpolatorTest.groovy
 
b/config/ogdl/src/test/groovy/org/apache/shiro/config/CommonsInterpolatorTest.groovy
new file mode 100644
index 0000000..851aeb0
--- /dev/null
+++ 
b/config/ogdl/src/test/groovy/org/apache/shiro/config/CommonsInterpolatorTest.groovy
@@ -0,0 +1,57 @@
+/*
+ * 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.shiro.config
+
+import org.junit.Test
+
+import static org.junit.Assert.*
+
+/**
+ * Tests for {@link CommonsInterpolator}.
+ * @since 1.4
+ */
+class CommonsInterpolatorTest {
+
+    @SuppressWarnings("unused")
+    public final static String TEST_ME = "success";
+
+    @Test
+    void testBasicOperation() {
+
+        def interpolator = new CommonsInterpolator();
+
+        assertNull interpolator.interpolate(null);
+
+        def sourceString = """
+            \${os.name}
+            \${foobar}
+            \${const:org.apache.shiro.config.CommonsInterpolatorTest.TEST_ME}
+            Some other text
+        """
+
+        def expectedResult = """
+            ${System.getProperty("os.name")}
+            \${foobar}
+            success
+            Some other text
+        """.toString()
+
+        assertEquals expectedResult, interpolator.interpolate(sourceString)
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/af75fb58/config/ogdl/src/test/groovy/org/apache/shiro/config/DefaultInterpolatorTest.groovy
----------------------------------------------------------------------
diff --git 
a/config/ogdl/src/test/groovy/org/apache/shiro/config/DefaultInterpolatorTest.groovy
 
b/config/ogdl/src/test/groovy/org/apache/shiro/config/DefaultInterpolatorTest.groovy
new file mode 100644
index 0000000..4456068
--- /dev/null
+++ 
b/config/ogdl/src/test/groovy/org/apache/shiro/config/DefaultInterpolatorTest.groovy
@@ -0,0 +1,48 @@
+/*
+ * 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.shiro.config
+
+import org.junit.Test
+
+import static org.junit.Assert.*
+
+/**
+ * Tests for {@link DefaultInterpolator}.
+ * @since 1.4
+ */
+public class DefaultInterpolatorTest {
+
+    @Test
+    void testBasicOperation() {
+
+        def interpolator = new DefaultInterpolator();
+
+        assertNull interpolator.interpolate(null);
+
+        def sourceString = """
+            \${sys:os.name}
+            \${foobar}
+            \${env:HOSTTYPE}
+            Some other text
+        """
+
+        assertSame sourceString, interpolator.interpolate(sourceString)
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/af75fb58/config/ogdl/src/test/groovy/org/apache/shiro/config/ReflectionBuilderTest.groovy
----------------------------------------------------------------------
diff --git 
a/config/ogdl/src/test/groovy/org/apache/shiro/config/ReflectionBuilderTest.groovy
 
b/config/ogdl/src/test/groovy/org/apache/shiro/config/ReflectionBuilderTest.groovy
index ffeb318..5b12d4c 100644
--- 
a/config/ogdl/src/test/groovy/org/apache/shiro/config/ReflectionBuilderTest.groovy
+++ 
b/config/ogdl/src/test/groovy/org/apache/shiro/config/ReflectionBuilderTest.groovy
@@ -21,10 +21,12 @@ package org.apache.shiro.config
 import org.apache.shiro.codec.Base64
 import org.apache.shiro.codec.CodecSupport
 import org.apache.shiro.codec.Hex
+import org.apache.shiro.config.event.BeanEvent
 import org.apache.shiro.util.CollectionUtils
 import org.junit.Test
 
 import static org.junit.Assert.*
+import static org.hamcrest.Matchers.*
 
 /**
  * Unit tests for the {@link ReflectionBuilder} implementation.
@@ -524,4 +526,150 @@ class ReflectionBuilderTest {
         assertEquals(5, bean.getIntProp());
         assertEquals("someString", bean.getStringProp());
     }
+
+    @Test
+    void testBeanListeners() {
+
+        def ini = new Ini();
+        ini.load '''
+            loggingListener = 
org.apache.shiro.config.event.LoggingBeanEventListener
+            listenerOne = org.apache.shiro.config.RecordingBeanListener
+            listenerTwo = org.apache.shiro.config.RecordingBeanListener
+
+            simpleBeanFactory = org.apache.shiro.config.SimpleBeanFactory
+            simpleBeanFactory.factoryInt = 5
+            simpleBeanFactory.factoryString = someString
+
+            compositeBean = org.apache.shiro.config.CompositeBean
+            compositeBean.simpleBean = $simpleBeanFactory
+        '''
+
+        ReflectionBuilder builder = new ReflectionBuilder();
+        Map<String, ?> objects = 
builder.buildObjects(ini.getSections().iterator().next());
+        assertFalse(CollectionUtils.isEmpty(objects));
+
+        assertInstantiatedEvents("listenerOne", objects, 4) //3 beans 
following + its own instantiated event
+        assertConfiguredEvents("listenerOne", objects, 4) //3 beans following 
+ its own configured event
+        assertInitializedEvents("listenerOne", objects, 4) //3 beans following 
+ its own initialized event
+
+        assertInstantiatedEvents("listenerTwo", objects, 3) //2 beans 
following + its own instantiated event
+        assertConfiguredEvents("listenerTwo", objects, 3); //2 beans following 
+ its own configured event
+        assertInitializedEvents("listenerTwo", objects, 3); //2 beans 
following + its own initialized event
+
+        builder.destroy();
+
+        assertDestroyedEvents("listenerOne", objects, 4); //3 beans defined 
after it + its own destroyed event
+        assertDestroyedEvents("listenerTwo", objects, 3); //2 beans defined 
after it + its own destroyed event
+    }
+
+
+    /**
+     * @since 1.4
+     */
+    @Test
+    void testSimpleInterpolation() {
+
+        Map<String, String> defs = new LinkedHashMap<String, String>();
+        defs.put("simpleBeanFactory", 
"org.apache.shiro.config.SimpleBeanFactory");
+        defs.put("simpleBeanFactory.factoryInt", "5");
+        defs.put("simpleBeanFactory.factoryString", "\${os.name}");
+        defs.put("compositeBean", "org.apache.shiro.config.CompositeBean");
+        defs.put("compositeBean.simpleBean", '$simpleBeanFactory');
+
+        ReflectionBuilder builder = new ReflectionBuilder();
+        Map objects = builder.buildObjects(defs);
+        assertFalse(CollectionUtils.isEmpty(objects));
+        CompositeBean compositeBean = (CompositeBean) 
objects.get("compositeBean");
+        SimpleBean bean = compositeBean.getSimpleBean();
+        assertNotNull(bean);
+        assertEquals(5, bean.getIntProp());
+        assertEquals(System.getProperty("os.name"), bean.getStringProp());
+
+    }
+
+    /**
+     * @since 1.4
+     */
+    @Test
+    void testInterpolationForMapKeysAndLists() {
+
+        // using os.name and os.arch because they are available on every system
+
+        Map<String, String> defs = new LinkedHashMap<String, String>();
+        defs.put("simpleBean1", "org.apache.shiro.config.SimpleBean");
+        defs.put("simpleBean1.stringList", "\${os.name}, \${os.arch}");
+        defs.put("simpleBean2", "org.apache.shiro.config.SimpleBean");
+        defs.put("compositeBean", "org.apache.shiro.config.CompositeBean");
+        defs.put("compositeBean.simpleBeanMap", '\${os.name}:$simpleBean1, 
two:$simpleBean2');
+
+        ReflectionBuilder builder = new ReflectionBuilder();
+        Map objects = builder.buildObjects(defs);
+        assertFalse(CollectionUtils.isEmpty(objects));
+
+        CompositeBean compositeBean = (CompositeBean) 
objects.get("compositeBean");
+        assertNotNull(compositeBean);
+
+        def beanMap = compositeBean.getSimpleBeanMap()
+        assertNotNull(beanMap)
+        assertThat beanMap, allOf(hasKey(System.getProperty("os.name")), 
hasKey("two"), aMapWithSize(2))
+
+        def beanOne = beanMap.get(System.getProperty("os.name"))
+        assertThat beanOne.stringList, 
allOf(hasItem(System.getProperty("os.name")), 
hasItem(System.getProperty("os.arch")), hasSize(2))
+
+        assertNotNull(beanMap.get("two"))
+    }
+
+    void assertInstantiatedEvents(String name, Map<String, ?> objects, int 
expected) {
+        def bean = objects.get(name) as RecordingBeanListener
+        def events = bean.getInstantiatedEvents()
+        assertEquals(expected, events.size())
+
+        checkType(name, events, "simpleBeanFactory", SimpleBeanFactory);
+        checkType(name, events, "compositeBean", CompositeBean);
+    }
+
+    void assertConfiguredEvents(String name, Map<String, ?> objects, int 
expected) {
+        def bean = objects.get(name) as RecordingBeanListener
+        def events = bean.getConfiguredEvents();
+        assertEquals(expected, events.size())
+
+        checkType(name, events, "listenerTwo", RecordingBeanListener);
+        checkType(name, events, "simpleBeanFactory", SimpleBeanFactory);
+        checkType(name, events, "compositeBean", CompositeBean);
+    }
+
+    void assertInitializedEvents(String name, Map<String, ?> objects, int 
expected) {
+        def bean = objects.get(name) as RecordingBeanListener
+        def events = bean.getInitializedEvents();
+        assertEquals(expected, events.size())
+
+        checkType(name, events, "listenerTwo", RecordingBeanListener);
+        checkType(name, events, "simpleBeanFactory", SimpleBeanFactory);
+        checkType(name, events, "compositeBean", CompositeBean);
+    }
+
+    void assertDestroyedEvents(String name, Map<String, ?> objects, int 
expected) {
+        def bean = objects.get(name) as RecordingBeanListener
+        def events = bean.getDestroyedEvents();
+        assertEquals(expected, events.size())
+
+        if (expected > 3) {
+            checkType(name, events, "listenerOne", RecordingBeanListener);
+        }
+        checkType(name, events, "listenerTwo", RecordingBeanListener);
+        checkType(name, events, "simpleBeanFactory", SimpleBeanFactory);
+        checkType(name, events, "compositeBean", CompositeBean);
+    }
+
+    void checkType(String instanceName, List<? extends BeanEvent> events, 
String name, Class<?> expectedType) {
+        for(BeanEvent event: events) {
+            if(event.getBeanName().equals(name)) {
+                assertTrue("Notification for bean " + name + " did not provide 
an instance of " + expectedType
+                        + " to listener " + instanceName,
+                expectedType.isInstance(event.getBean()))
+                return;
+            }
+        }
+        fail("No bean named " + name + " was ever notified to listener " + 
instanceName + ".");
+    }
 }

http://git-wip-us.apache.org/repos/asf/shiro/blob/af75fb58/config/ogdl/src/test/groovy/org/apache/shiro/config/SimpleBean.groovy
----------------------------------------------------------------------
diff --git 
a/config/ogdl/src/test/groovy/org/apache/shiro/config/SimpleBean.groovy 
b/config/ogdl/src/test/groovy/org/apache/shiro/config/SimpleBean.groovy
index 49b21bd..244ef48 100644
--- a/config/ogdl/src/test/groovy/org/apache/shiro/config/SimpleBean.groovy
+++ b/config/ogdl/src/test/groovy/org/apache/shiro/config/SimpleBean.groovy
@@ -25,6 +25,7 @@ class SimpleBean {
     int intProp;
     byte[] byteArrayProp;
     List<SimpleBean> simpleBeans;
+    List<String> stringList;
     Map<String,Object> mapProp = new LinkedHashMap<String,Object>();
 
     public SimpleBean(){}

http://git-wip-us.apache.org/repos/asf/shiro/blob/af75fb58/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index d1b41e3..ac78c2b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -747,6 +747,20 @@
                 <artifactId>aspectjweaver</artifactId>
                 <version>${aspectj.version}</version>
             </dependency>
+
+            <dependency>
+                <!-- optional dep for the reflection builder -->
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-configuration2</artifactId>
+                <version>2.1</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>commons-logging</groupId>
+                        <artifactId>commons-logging</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+
             <dependency>
                 <groupId>org.openid4java</groupId>
                 <artifactId>openid4java-consumer</artifactId>

Reply via email to