You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by br...@apache.org on 2014/10/19 19:50:52 UTC

svn commit: r1632960 - in /commons/sandbox/beanutils2/trunk/src: changes/ main/java/org/apache/commons/beanutils2/ test/java/org/apache/commons/beanutils2/

Author: britter
Date: Sun Oct 19 17:50:51 2014
New Revision: 1632960

URL: http://svn.apache.org/r1632960
Log:
SANDBOX-475: BeanUtils and Maps

Added:
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanAccessorFactory.java   (with props)
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/MapBeanAccessor.java   (with props)
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/MapBeanPropertySetter.java   (with props)
    commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/MapBeanTestCase.java   (with props)
Modified:
    commons/sandbox/beanutils2/trunk/src/changes/changes.xml
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanUtils.java
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultIndexedPropertyGetterAccessor.java
    commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultMappedPropertyGetterAccessor.java

Modified: commons/sandbox/beanutils2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/changes/changes.xml?rev=1632960&r1=1632959&r2=1632960&view=diff
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/changes/changes.xml (original)
+++ commons/sandbox/beanutils2/trunk/src/changes/changes.xml Sun Oct 19 17:50:51 2014
@@ -23,6 +23,9 @@
   </properties>
   <body>
   <release version="2.0" date="TBA" description="Redesign of beanutils with a fluent API">
+    <action dev="britter" type="add" issue="SANDBOX-478">
+      BeanUtils and Maps
+    </action>
     <action dev="britter" type="add" due-to="Yogesh Rao" issue="SANDBOX-472">
       Add a registry for Transformer implementations
     </action>

Added: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanAccessorFactory.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanAccessorFactory.java?rev=1632960&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanAccessorFactory.java (added)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanAccessorFactory.java Sun Oct 19 17:50:51 2014
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.beanutils2;
+
+import java.util.Map;
+
+final class BeanAccessorFactory {
+
+    public static <B> BeanAccessor<B> createBeanAccessor(B bean) {
+        if (bean instanceof Map) {
+            return new MapBeanAccessor<B>(asMap(bean));
+        } else {
+            return new DefaultBeanAccessor<B>(bean);
+        }
+    }
+
+    private static <B> Map<String, Object> asMap(B bean) {
+        Map map = (Map) bean;
+        checkKeyType(map);
+        // we did all we can to ensure the correct key type
+        @SuppressWarnings("unchecked")
+        Map<String, Object> typedMap = (Map<String, Object>) map;
+        return typedMap;
+    }
+
+    /**
+     * Make sure that the generic parameter of the map keys is String.
+     *
+     * @param map the map to check
+     */
+    private static void checkKeyType(Map map) {
+        if (!map.isEmpty()) {
+            Object firstKey = map.keySet().iterator().next();
+            Assertions.checkArgument((firstKey instanceof String), "Map keys have to be of type String!");
+        }
+    }
+}

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanAccessorFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanUtils.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanUtils.java?rev=1632960&r1=1632959&r2=1632960&view=diff
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanUtils.java (original)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/BeanUtils.java Sun Oct 19 17:50:51 2014
@@ -21,6 +21,8 @@ package org.apache.commons.beanutils2;
 
 import static org.apache.commons.beanutils2.Assertions.checkNotNull;
 
+import java.util.Map;
+
 /**
  * Entry point into the API. Provides methods for:
  * <ul>
@@ -47,7 +49,7 @@ public final class BeanUtils {
      */
     public static <B> BeanAccessor<B> on(B bean) {
         bean = checkNotNull(bean, "No bean specified");
-        return new DefaultBeanAccessor<B>(bean);
+        return BeanAccessorFactory.createBeanAccessor(bean);
     }
 
     /**

Modified: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultIndexedPropertyGetterAccessor.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultIndexedPropertyGetterAccessor.java?rev=1632960&r1=1632959&r2=1632960&view=diff
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultIndexedPropertyGetterAccessor.java (original)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultIndexedPropertyGetterAccessor.java Sun Oct 19 17:50:51 2014
@@ -46,7 +46,7 @@ final class DefaultIndexedPropertyGetter
         checkArgument(index >= 0, "Indexed property '%s' in bean of type %s cannot be get from a negative index %s",
                 propertyName, bean.getClass().getName(), index);
         Object indexedValue = invokeGetter(index);
-        return new DefaultBeanAccessor<Object>(indexedValue);
+        return BeanAccessorFactory.createBeanAccessor(indexedValue);
     }
 
     private Object invokeGetter(int index) {

Modified: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultMappedPropertyGetterAccessor.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultMappedPropertyGetterAccessor.java?rev=1632960&r1=1632959&r2=1632960&view=diff
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultMappedPropertyGetterAccessor.java (original)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/DefaultMappedPropertyGetterAccessor.java Sun Oct 19 17:50:51 2014
@@ -66,7 +66,7 @@ class DefaultMappedPropertyGetterAccesso
 
     private BeanAccessor<?> wrapInAccessor(Object mappedValue) {
         if (mappedValue != null) {
-            return new DefaultBeanAccessor<Object>(mappedValue);
+            return BeanAccessorFactory.createBeanAccessor(mappedValue);
         } else {
             return new NullBeanAccessor<Object>(bean.getClass().getName(), mappedReadMethod.getName());
         }

Added: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/MapBeanAccessor.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/MapBeanAccessor.java?rev=1632960&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/MapBeanAccessor.java (added)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/MapBeanAccessor.java Sun Oct 19 17:50:51 2014
@@ -0,0 +1,133 @@
+/*
+ * 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.commons.beanutils2;
+
+import static org.apache.commons.beanutils2.Assertions.checkNotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An implementation of the {@link org.apache.commons.beanutils2.BeanAccessor} interface, that accesses a Map as though
+ * it were a Java Bean.
+ *
+ * @param <B> a subtype of the {@link java.util.Map} interface
+ */
+final class MapBeanAccessor<B> implements BeanAccessor<B> {
+
+    private Map<String, Object> map;
+
+    public MapBeanAccessor(Map<String, Object> map) {
+        this.map = map;
+    }
+
+    public BeanAccessor<?> get(String propertyName) {
+        checkNotNull(propertyName, "Parameter 'propertyName' must not be null!");
+        if (map.containsKey(propertyName)) {
+            Object value = map.get(propertyName);
+            return BeanAccessorFactory.createBeanAccessor(value);
+        }
+        // TODO better default message doesn't fit for map access
+        throw new NoSuchPropertyException(propertyName, map.getClass(), null);
+    }
+
+    public IndexedPropertyGetterAccessor<?> getIndexed(String propertyName) {
+        throw new NoSuchPropertyException(propertyName, map.getClass(), null);
+    }
+
+    public MappedPropertyGetterAccessor getMapped(String propertyName) {
+        throw new NoSuchPropertyException(propertyName, map.getClass(), null);
+    }
+
+    public B get() {
+        // BeanUtils.on(B) has been called with a Map, though creating this MapBeanAccessor. Because of this we can be
+        // sure that B is a subtype of Map.
+        @SuppressWarnings("unchecked")
+        B returned = (B) map;
+        return returned;
+    }
+
+    public <V> V cast() {
+        // BeanUtils.on(B) has been called with a Map, though creating this MapBeanAccessor. Because of this we can be
+        // sure that B is a subtype of Map.
+        @SuppressWarnings("unchecked")
+        V returned = (V) map;
+        return returned;
+    }
+
+    public BeanPropertySetter<B> set(String propertyName) {
+        checkNotNull(propertyName, "Parameter 'propertyName' must not be null!");
+        return new MapBeanPropertySetter<B>(map, propertyName);
+    }
+
+    public IndexedPropertySetterAccessor<B> setIndexed(String propertyName) {
+        throw new NoSuchPropertyException(propertyName, map.getClass(), null);
+    }
+
+    public MappedPropertySetterAccessor<B> setMapped(String propertyName) {
+        throw new NoSuchPropertyException(propertyName, map.getClass(), null);
+    }
+
+    public B cloneBean() {
+        // FIXME would be better to get a new instance of the type of the wrapped map
+        Map<String, Object> cloned = new HashMap<String, Object>();
+        cloned.putAll(map);
+        // BeanUtils.on(B) has been called with a Map, though creating this MapBeanAccessor. Because of this we can be
+        // sure that B is a subtype of Map.
+        @SuppressWarnings("unchecked")
+        B returned = (B) cloned;
+        return returned;
+    }
+
+    public <T extends B> void copyPropertiesTo(T target) {
+        checkNotNull(target, "Parameter 'target' must not be null!");
+        // FIXME find out whether target has the correct generic types
+        // BeanUtils.on(B) has been called with a Map, though creating this MapBeanAccessor. Because of this we can be
+        // sure that B is a subtype of Map and T must also be of a subtype of Map.
+        @SuppressWarnings("unchecked")
+        Map<String, Object> targetMap = (Map<String, Object>) target;
+        targetMap.putAll(map);
+    }
+
+    public Map<String, Object> describe() {
+        Map<String, Object> copy = new HashMap<String, Object>();
+        copy.putAll(map);
+        return copy;
+    }
+
+    public void populate(Map<String, Object> properties) {
+        checkNotNull(properties, "Parameter 'properties' must not be null!");
+        map.putAll(properties);
+    }
+
+    public ArgumentsAccessor invoke(String methodName) {
+        checkNotNull(methodName, "Parameter 'methodName' must not be null!");
+        return new DefaultArgumentsAccessor(getBeanClass(), false, methodName, map);
+    }
+
+    public ArgumentsAccessor invokeExact(String methodName) {
+        checkNotNull(methodName, "Parameter 'methodName' must not be null!");
+        return new DefaultArgumentsAccessor(getBeanClass(), true, methodName, map);
+    }
+
+    private Class<Map> getBeanClass() {
+        @SuppressWarnings("unchecked")
+        Class<Map> clazz = (Class<Map>) map.getClass();
+        return clazz;
+    }
+}

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/MapBeanAccessor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/MapBeanPropertySetter.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/MapBeanPropertySetter.java?rev=1632960&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/MapBeanPropertySetter.java (added)
+++ commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/MapBeanPropertySetter.java Sun Oct 19 17:50:51 2014
@@ -0,0 +1,36 @@
+/*
+ * 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.commons.beanutils2;
+
+import java.util.Map;
+
+final class MapBeanPropertySetter<B> implements BeanPropertySetter<B> {
+
+    private Map<String, Object> map;
+    private String key;
+
+    public MapBeanPropertySetter(Map<String, Object> map, String key) {
+        this.map = map;
+        this.key = key;
+    }
+
+    public <V> BeanAccessor<B> with(V value) {
+        map.put(key, value);
+        return (BeanAccessor<B>) BeanAccessorFactory.createBeanAccessor(map);
+    }
+}

Propchange: commons/sandbox/beanutils2/trunk/src/main/java/org/apache/commons/beanutils2/MapBeanPropertySetter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/MapBeanTestCase.java
URL: http://svn.apache.org/viewvc/commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/MapBeanTestCase.java?rev=1632960&view=auto
==============================================================================
--- commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/MapBeanTestCase.java (added)
+++ commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/MapBeanTestCase.java Sun Oct 19 17:50:51 2014
@@ -0,0 +1,232 @@
+/*
+ * 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.commons.beanutils2;
+
+import static org.apache.commons.beanutils2.Argument.argument;
+import static org.apache.commons.beanutils2.BeanUtils.on;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class MapBeanTestCase {
+
+    private Map<String, Object> map;
+    private MapTestBean bean;
+
+    @Before
+    public void setUp() throws Exception {
+        map = new HashMap<String, Object>();
+        map.put("integerProperty", Integer.valueOf(15));
+
+        Map<String, Object> nestedMap = new HashMap<String, Object>();
+        nestedMap.put("booleanProperty", Boolean.TRUE);
+        map.put("nestedMap", nestedMap);
+
+        bean = new MapTestBean(map);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void nullPropertyNameThrowsException() throws Exception {
+        on(map).get(null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void mapKeysHaveToBeOfTypeString() throws Exception {
+        on(Collections.singletonMap(new Object(), new Object()));
+    }
+
+    @Test(expected = NoSuchPropertyException.class)
+    public void missingPropertyThrowsException() throws Exception {
+        on(map).get("nonExistingProperty");
+    }
+
+    @Test
+    public void returnsIntegerProperty() throws Exception {
+        assertEquals(on(map).get("integerProperty").get(), Integer.valueOf(15));
+    }
+
+    @Test
+    public void returnsNestedMap() throws Exception {
+        assertEquals(Boolean.TRUE, on(map).get("nestedMap").get("booleanProperty").get());
+    }
+
+    @Test(expected = NoSuchPropertyException.class)
+    public void gettingIndexedPropertiesThrowsException() throws Exception {
+        on(map).getIndexed("whatever");
+    }
+
+    @Test(expected = NoSuchPropertyException.class)
+    public void gettingMappedPropertiesThrowsException() throws Exception {
+        on(map).getMapped("whatever");
+    }
+
+    @Test
+    public void getReturnsWrappedMap() throws Exception {
+        Map<String, Object> wrapped = on(map).get();
+        assertSame(map, wrapped);
+        assertEquals(map, wrapped);
+    }
+
+    @Test
+    public void castToHashMap() throws Exception {
+        HashMap<String, Object> castedMap = on(map).cast();
+        assertSame(map, castedMap);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void setNullPropertyNameThrowsException() throws Exception {
+        on(map).set(null);
+    }
+
+    @Test
+    public void setPropertyOverridesValueAssociatedWithKey() throws Exception {
+        on(map).set("integerProperty").with(Integer.valueOf(1));
+        assertEquals(Integer.valueOf(1), map.get("integerProperty"));
+    }
+
+    @Test
+    public void setPropertyWithNullAssociatesKeyWithNull() throws Exception {
+        on(map).set("integerProperty").with(null);
+        assertNull(map.get("integerProperty"));
+    }
+
+    @Test
+    public void setPropertyAddsNewKeyValuePairs() throws Exception {
+        on(map).set("newKey").with("newValue");
+        assertEquals("newValue", map.get("newKey"));
+    }
+
+    @Test(expected = NoSuchPropertyException.class)
+    public void settingIndexedPropertiesThrowsException() throws Exception {
+        on(map).setIndexed("whatever");
+    }
+
+    @Test(expected = NoSuchPropertyException.class)
+    public void settingMappedPropertiesThrowsExcpetion() throws Exception {
+        on(map).setMapped("whatever");
+    }
+
+    @Test
+    public void cloningReturnsNewMapWithSameKeyValues() throws Exception {
+        Map<String, Object> cloned = on(map).cloneBean();
+        assertNotSame(map, cloned);
+        assertEquals(map, cloned);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void copyPropertiesToNullThrowsException() throws Exception {
+        on(map).copyPropertiesTo(null);
+    }
+
+    @Test
+    public void copyPropertiesToAddsAllPropertiesToGivenMap() throws Exception {
+        HashMap<String, Object> target = new HashMap<String, Object>();
+        on(map).copyPropertiesTo(target);
+        assertEquals(map, target);
+    }
+
+    @Test
+    public void describeCreatesMapWithSameKeyValuePairs() throws Exception {
+        Map<String, Object> description = on(map).describe();
+        assertNotSame(map, description);
+        assertEquals(map, description);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void populateNullThrowsException() throws Exception {
+        on(map).populate(null);
+    }
+
+    @Test
+    public void populateAddsAllKeyValuePairs() throws Exception {
+        on(map).populate(Collections.<String, Object>singletonMap("newKey", "newValue"));
+        assertEquals("newValue", map.get("newKey"));
+    }
+
+    @Test
+    public void populateOverridesExistingKeyValuePairs() throws Exception {
+        on(map).populate(Collections.<String, Object>singletonMap("integerProperty", Integer.valueOf(12)));
+        assertEquals(Integer.valueOf(12), map.get("integerProperty"));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void invokeNullThrowsException() throws Exception {
+        on(map).invoke(null);
+    }
+
+    @Test
+    public void invokesMapMethods() throws Exception {
+        assertEquals(2, on(map).invoke("size").with().get());
+        assertEquals(15, on(map).invoke("get").with(argument("integerProperty")).get());
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void invokeExactNullThrowsException() throws Exception {
+        on(map).invokeExact(null);
+    }
+
+    @Test
+    public void invokesExactMethods() throws Exception {
+        assertEquals(2, on(map).invokeExact("size").with().get());
+        assertEquals(15, on(map).invokeExact("get").with(argument(Object.class, "integerProperty")).get());
+    }
+
+    @Test(expected = NoSuchBeanMethodException.class)
+    public void invokeExactGetDoesNotWorkWithStringArgument() throws Exception {
+        // it is declared as get(Object), so calling it with String doesn't work
+        on(map).invokeExact("get").with(argument("integerProperty"));
+    }
+
+    @Test
+    public void mapsReturnedFromIndexedPropertiesAreWrappedCorrectly() throws Exception {
+        assertEquals(Integer.valueOf(15), on(bean).getIndexed("indexedMap").at(0).get("integerProperty").get());
+    }
+
+    @Test
+    public void mapsReturnedFromMappedPropertiesAreWrappedCorrectly() throws Exception {
+        assertEquals(Integer.valueOf(15), on(bean).getMapped("mappedMap").of("whatever").get("integerProperty").get());
+    }
+
+    private static class MapTestBean {
+
+        private Map<String, Object> map;
+
+        private MapTestBean(Map<String, Object> map) {
+            this.map = map;
+        }
+
+        public Map<String, Object> getMappedMap(String key) {
+            return map;
+        }
+
+        public Map<String, Object> getIndexedMap(int index) {
+            return map;
+        }
+    }
+}

Propchange: commons/sandbox/beanutils2/trunk/src/test/java/org/apache/commons/beanutils2/MapBeanTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native