geronimo-xbean-scm mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dblev...@apache.org
Subject svn commit: r635096 - in /geronimo/xbean/trunk/xbean-reflect/src: main/java/org/apache/xbean/propertyeditor/ main/java/org/apache/xbean/recipe/ test/java/org/apache/xbean/recipe/
Date Sat, 08 Mar 2008 22:21:14 GMT
Author: dblevins
Date: Sat Mar  8 14:20:49 2008
New Revision: 635096

URL: http://svn.apache.org/viewvc?rev=635096&view=rev
Log:
XBEAN-103: Support for Generic Collections and Maps

Added:
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/GenericCollectionConverter.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/GenericMapConverter.java
    geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/GenericCollectionsTest.java
Modified:
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditors.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CollectionRecipe.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/RecipeHelper.java

Added: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/GenericCollectionConverter.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/GenericCollectionConverter.java?rev=635096&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/GenericCollectionConverter.java
(added)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/GenericCollectionConverter.java
Sat Mar  8 14:20:49 2008
@@ -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.xbean.propertyeditor;
+
+import java.beans.PropertyEditor;
+import java.util.List;
+import java.util.Collection;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class GenericCollectionConverter extends AbstractCollectionConverter {
+
+    public GenericCollectionConverter(Class type, PropertyEditor editor) {
+        super(type, editor);
+    }
+
+    protected Object createCollection(List list) {
+        try {
+            Collection collection = (Collection) getType().newInstance();
+            collection.addAll(list);
+            return collection;
+        } catch (Exception e) {
+            throw new PropertyEditorException(e);
+        }
+    }
+}

Added: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/GenericMapConverter.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/GenericMapConverter.java?rev=635096&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/GenericMapConverter.java
(added)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/GenericMapConverter.java
Sat Mar  8 14:20:49 2008
@@ -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.xbean.propertyeditor;
+
+import java.beans.PropertyEditor;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class GenericMapConverter extends AbstractMapConverter {
+    public GenericMapConverter(Class type, PropertyEditor keyEditor, PropertyEditor valueEditor)
{
+        super(type, keyEditor, valueEditor);
+    }
+
+    protected Map createMap(Map data) {
+        try {
+            Map map = (Map) getType().newInstance();
+            map.putAll(data);
+            return map;
+        } catch (Exception e) {
+            throw new PropertyEditorException(e);
+        }
+    }
+}

Modified: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditors.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditors.java?rev=635096&r1=635095&r2=635096&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditors.java
(original)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditors.java
Sat Mar  8 14:20:49 2008
@@ -16,11 +16,27 @@
  */
 package org.apache.xbean.propertyeditor;
 
+import static org.apache.xbean.recipe.RecipeHelper.getTypeParameters;
+import static org.apache.xbean.recipe.RecipeHelper.*;
+import org.apache.xbean.recipe.RecipeHelper;
+
 import java.beans.PropertyEditor;
 import java.beans.PropertyEditorManager;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Collection;
+import java.util.SortedSet;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.LinkedHashSet;
+import java.util.ArrayList;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.LinkedHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.lang.reflect.Type;
 
 /**
  * The property editor manager.  This orchestrates Geronimo usage of
@@ -196,7 +212,7 @@
 
     }
 
-    public static Object getValue(Class type, String value) throws PropertyEditorException
{
+    public static Object getValue(Type type, String value) throws PropertyEditorException
{
         if (type == null) throw new NullPointerException("type is null");
         if (value == null) throw new NullPointerException("value is null");
 
@@ -206,10 +222,12 @@
             return converter.toObject(value);
         }
 
+        Class clazz = toClass(type);
+
         // fall back to a property editor
         PropertyEditor editor = findEditor(type);
         if (editor == null) {
-            throw new PropertyEditorException("Unable to find PropertyEditor for " + type.getSimpleName());
+            throw new PropertyEditorException("Unable to find PropertyEditor for " + clazz.getSimpleName());
         }
 
         // create the object value
@@ -218,15 +236,86 @@
         try {
             objectValue = editor.getValue();
         } catch (Exception e) {
-            throw new PropertyEditorException("Error while converting \"" + value + "\" to
a " + type.getSimpleName() +
+            throw new PropertyEditorException("Error while converting \"" + value + "\" to
a " + clazz.getSimpleName() +
                     " using the property editor " + editor.getClass().getSimpleName(), e);
         }
         return objectValue;
     }
 
-    private static Converter findConverter(Class type) {
+    private static Converter findConverter(Type type) {
         if (type == null) throw new NullPointerException("type is null");
 
+        Class clazz = toClass(type);
+
+
+
+        // it's possible this was a request for an array class.  We might not
+        // recognize the array type directly, but the component type might be
+        // resolvable
+        if (clazz.isArray() && !clazz.getComponentType().isArray()) {
+            // do a recursive lookup on the base type
+            Converter converter = findConverter(clazz.getComponentType());
+            // if we found a suitable editor for the base component type,
+            // wrapper this in an array adaptor for real use
+            if (converter != null) {
+                return new ArrayConverter(clazz, converter);
+            } else {
+                return null;
+            }
+        }
+
+        if (Collection.class.isAssignableFrom(clazz)){
+            Type[] types = getTypeParameters(Collection.class, type);
+
+            Type componentType = String.class;
+            if (types != null && types.length == 1 && types[0] instanceof
Class) {
+                componentType = types[0];
+            }
+
+            Converter converter = findConverter(componentType);
+
+            if (converter != null){
+                if (RecipeHelper.hasDefaultConstructor(clazz)) {
+                    return new GenericCollectionConverter(clazz, converter);
+                } else if (SortedSet.class.isAssignableFrom(clazz)) {
+                    return new GenericCollectionConverter(TreeSet.class, converter);
+                } else if (Set.class.isAssignableFrom(clazz)) {
+                    return new GenericCollectionConverter(LinkedHashSet.class, converter);
+                } else {
+                    return new GenericCollectionConverter(ArrayList.class, converter);
+                }
+            }
+            
+            return null;
+        }
+
+        if (Map.class.isAssignableFrom(clazz)){
+            Type[] types = getTypeParameters(Map.class, type);
+
+            Type keyType = String.class;
+            Type valueType = String.class;
+            if (types != null && types.length == 2 && types[0] instanceof
Class && types[1] instanceof Class) {
+                keyType = types[0];
+                valueType = types[1];
+            }
+
+            Converter keyConverter = findConverter(keyType);
+            Converter valueConverter = findConverter(valueType);
+
+            if (keyConverter != null && valueConverter != null){
+                if (RecipeHelper.hasDefaultConstructor(clazz)) {
+                    return new GenericMapConverter(clazz, keyConverter, valueConverter);
+                } else if (SortedMap.class.isAssignableFrom(clazz)) {
+                    return new GenericMapConverter(TreeMap.class, keyConverter, valueConverter);
+                } else if (ConcurrentMap.class.isAssignableFrom(clazz)) {
+                    return new GenericMapConverter(ConcurrentHashMap.class, keyConverter,
valueConverter);
+                } else {
+                    return new GenericMapConverter(LinkedHashMap.class, keyConverter, valueConverter);
+                }
+            }
+
+            return null;
+        }
         Converter converter = (Converter) registry.get(type);
 
         // we're outta here if we got one.
@@ -234,7 +323,7 @@
             return converter;
         }
 
-        Class[] declaredClasses = type.getDeclaredClasses();
+        Class[] declaredClasses = clazz.getDeclaredClasses();
         for (int i = 0; i < declaredClasses.length; i++) {
             Class declaredClass = declaredClasses[i];
             if (Converter.class.isAssignableFrom(declaredClass)) {
@@ -244,7 +333,7 @@
 
                     // try to get the converter from the registry... the converter
                     // created above may have been for another class
-                    converter = (Converter) registry.get(type);
+                    converter = (Converter) registry.get(clazz);
                     if (converter != null) {
                         return converter;
                     }
@@ -254,19 +343,6 @@
             }
         }
 
-        // it's possible this was a request for an array class.  We might not
-        // recognize the array type directly, but the component type might be
-        // resolvable
-        if (type.isArray() && !type.getComponentType().isArray()) {
-            // do a recursive lookup on the base type
-            converter = findConverter(type.getComponentType());
-            // if we found a suitable editor for the base component type,
-            // wrapper this in an array adaptor for real use
-            if (converter != null) {
-                return new ArrayConverter(type, converter);
-            }
-        }
-
         // nothing found
         return null;
     }
@@ -278,27 +354,30 @@
      * @return The resolved editor, if any.  Returns null if a suitable editor
      *         could not be located.
      */
-    private static PropertyEditor findEditor(Class type) {
+    private static PropertyEditor findEditor(Type type) {
         if (type == null) throw new NullPointerException("type is null");
 
+        Class clazz = toClass(type);
+
         // try to locate this directly from the editor manager first.
-        PropertyEditor editor = PropertyEditorManager.findEditor(type);
+        PropertyEditor editor = PropertyEditorManager.findEditor(clazz);
 
         // we're outta here if we got one.
         if (editor != null) {
             return editor;
         }
 
+
         // it's possible this was a request for an array class.  We might not
         // recognize the array type directly, but the component type might be
         // resolvable
-        if (type.isArray() && !type.getComponentType().isArray()) {
+        if (clazz.isArray() && !clazz.getComponentType().isArray()) {
             // do a recursive lookup on the base type
-            editor = findEditor(type.getComponentType());
+            editor = findEditor(clazz.getComponentType());
             // if we found a suitable editor for the base component type,
             // wrapper this in an array adaptor for real use
             if (editor != null) {
-                return new ArrayConverter(type, editor);
+                return new ArrayConverter(clazz, editor);
             }
         }
 

Modified: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CollectionRecipe.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CollectionRecipe.java?rev=635096&r1=635095&r2=635096&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CollectionRecipe.java
(original)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CollectionRecipe.java
Sat Mar  8 14:20:49 2008
@@ -135,8 +135,8 @@
         }
 
         // get component type
-        Type componentType = Object.class;
         Type[] typeParameters = RecipeHelper.getTypeParameters(Collection.class, expectedType);
+        Type componentType = Object.class;
         if (typeParameters != null && typeParameters.length == 1 && typeParameters[0]
instanceof Class) {
             componentType = typeParameters[0];
         }

Modified: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/RecipeHelper.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/RecipeHelper.java?rev=635096&r1=635095&r2=635096&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/RecipeHelper.java
(original)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/RecipeHelper.java
Sat Mar  8 14:20:49 2008
@@ -57,6 +57,9 @@
         if (!Modifier.isPublic(type.getModifiers())) {
             return false;
         }
+        if (Modifier.isAbstract(type.getModifiers())) {
+            return false;
+        }
         Constructor[] constructors = type.getConstructors();
         for (Constructor constructor : constructors) {
             if (Modifier.isPublic(constructor.getModifiers()) &&
@@ -166,7 +169,7 @@
 
         if (value instanceof String && (expectedType != Object.class)) {
             String stringValue = (String) value;
-            value = PropertyEditors.getValue(toClass(expectedType), stringValue);
+            value = PropertyEditors.getValue(expectedType, stringValue);
         }
         return value;
     }

Added: geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/GenericCollectionsTest.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/GenericCollectionsTest.java?rev=635096&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/GenericCollectionsTest.java
(added)
+++ geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/GenericCollectionsTest.java
Sat Mar  8 14:20:49 2008
@@ -0,0 +1,188 @@
+/**
+ * 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.xbean.recipe;
+
+import junit.framework.TestCase;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Collection;
+import java.net.URI;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class GenericCollectionsTest extends TestCase {
+
+    public void test() throws Exception {
+        Something expected = new Something();
+
+        expected.plainList = new ArrayList();
+        expected.plainList.add("red");
+        expected.plainList.add("green");
+        expected.plainList.add("blue");
+
+        expected.plainMap = new LinkedHashMap();
+        expected.plainMap.put("red","rojo");
+        expected.plainMap.put("green","verde");
+        expected.plainMap.put("blue","azul");
+
+        expected.listOfClass = new ArrayList<Class>();
+        expected.listOfClass.add(Red.class);
+        expected.listOfClass.add(Green.class);
+        expected.listOfClass.add(Blue.class);
+
+        expected.listOfURI = new ArrayList<URI>();
+        expected.listOfURI.add(new URI("red://rojo"));
+        expected.listOfURI.add(new URI("green://verde"));
+        expected.listOfURI.add(new URI("blue://azul"));
+
+        expected.mapOfClass = new LinkedHashMap<String, Class>();
+        expected.mapOfClass.put("Rojo", Red.class);
+        expected.mapOfClass.put("Verde", Green.class);
+        expected.mapOfClass.put("Azul", Blue.class);
+
+        expected.mapOfURI = new LinkedHashMap<URI, String>();
+        expected.mapOfURI.put(new URI("red://rojo"), "Rojo");
+        expected.mapOfURI.put(new URI("green://verde"), "Verde");
+        expected.mapOfURI.put(new URI("blue://azul"), "Azul");
+
+        expected.setOfClass = new LinkedHashSet<Class>();
+        expected.setOfClass.add(Red.class);
+        expected.setOfClass.add(Green.class);
+        expected.setOfClass.add(Blue.class);
+
+        expected.setOfURI = new LinkedHashSet();
+        expected.setOfURI.add(new URI("red://rojo"));
+        expected.setOfURI.add(new URI("green://verde"));
+        expected.setOfURI.add(new URI("blue://azul"));
+
+
+        ObjectRecipe recipe = new ObjectRecipe(Something.class);
+        recipe.setProperty("plainList", toString(expected.plainList));
+        recipe.setProperty("plainMap", toString(expected.plainMap));
+        recipe.setProperty("listOfClass", toString(expected.listOfClass));
+        recipe.setProperty("listOfURI", toString(expected.listOfURI));
+        recipe.setProperty("mapOfClass", toString(expected.mapOfClass));
+        recipe.setProperty("mapOfURI", toString(expected.mapOfURI));
+        recipe.setProperty("setOfClass", toString(expected.setOfClass));
+        recipe.setProperty("setOfURI", toString(expected.setOfURI));
+
+        Something actual = (Something) recipe.create();
+
+        assertEquals("PlainList", expected.getPlainList(), actual.getPlainList());
+        assertEquals("PlainMap", expected.getPlainMap(), actual.getPlainMap());
+        assertEquals("ListOfClass", expected.getListOfClass(), actual.getListOfClass());
+        assertEquals("ListOfURI", expected.getListOfURI(), actual.getListOfURI());
+        assertEquals("MapOfClass", expected.getMapOfClass(), actual.getMapOfClass());
+        assertEquals("MapOfURI", expected.getMapOfURI(), actual.getMapOfURI());
+        assertEquals("SetOfClass", expected.getSetOfClass(), actual.getSetOfClass());
+        assertEquals("SetOfURI", expected.getSetOfURI(), actual.getSetOfURI());
+    }
+
+    private String toString(Map m) {
+        Map<Object,Object> map   = m;
+        List<String> pairs = new ArrayList<String>();
+        for (Map.Entry<Object, Object> entry : map.entrySet()) {
+            String key = toString(entry.getKey());
+            key = key.replaceAll(":","\\\\:");
+            String value = toString(entry.getValue());
+            pairs.add(key +"="+value);
+        }
+        return toString(pairs).replace(',', '\n');
+    }
+
+    private String toString(Collection collection) {
+        StringBuilder s = new StringBuilder();
+        for (Object obj : collection) {
+            s.append(toString(obj));
+            s.append(",");
+        }
+
+        s.deleteCharAt(s.length()-1);
+
+        return s.toString();
+    }
+
+    private String toString(Object obj) {
+        if (obj instanceof Class) {
+            return ((Class) obj).getName();
+        } else {
+            return obj.toString();
+        }
+    }
+
+    public static class Something {
+
+        public List plainList;
+
+        public Map plainMap;
+
+        public List<Class> listOfClass;
+
+        public List<URI> listOfURI;
+
+        public Map<String,Class> mapOfClass;
+
+        public Map<URI, String> mapOfURI;
+
+        public Set<Class> setOfClass;
+
+        public Set<URI> setOfURI;
+
+        public List getPlainList() {
+            return plainList;
+        }
+
+        public Map getPlainMap() {
+            return plainMap;
+        }
+
+        public List<Class> getListOfClass() {
+            return listOfClass;
+        }
+
+        public List<URI> getListOfURI() {
+            return listOfURI;
+        }
+
+        public Map<String, Class> getMapOfClass() {
+            return mapOfClass;
+        }
+
+        public Map<URI, String> getMapOfURI() {
+            return mapOfURI;
+        }
+
+        public Set<Class> getSetOfClass() {
+            return setOfClass;
+        }
+
+        public Set<URI> getSetOfURI() {
+            return setOfURI;
+        }
+
+    }
+
+    public static class Red {}
+    public static class Green {}
+    public static class Blue {}
+}



Mime
View raw message