OSDN Git Service

map bind
authorleo <leo@ae02f08e-27ec-0310-ae8c-8ba02fe2eafd>
Thu, 21 May 2009 06:48:49 +0000 (06:48 +0000)
committerleo <leo@ae02f08e-27ec-0310-ae8c-8ba02fe2eafd>
Thu, 21 May 2009 06:48:49 +0000 (06:48 +0000)
git-svn-id: http://www.xerial.org/svn/project/XerialJ/trunk/xerial-core@3327 ae02f08e-27ec-0310-ae8c-8ba02fe2eafd

src/main/java/org/xerial/lens/MapEntry.java [new file with mode: 0644]
src/main/java/org/xerial/lens/ObjectLens.java
src/main/java/org/xerial/lens/ObjectMapper.java
src/main/java/org/xerial/lens/ParameterSetter.java
src/main/java/org/xerial/lens/RelationSetter.java
src/main/java/org/xerial/util/bean/BeanUtil.java
src/test/java/org/xerial/lens/ObjectLensTest.java

diff --git a/src/main/java/org/xerial/lens/MapEntry.java b/src/main/java/org/xerial/lens/MapEntry.java
new file mode 100644 (file)
index 0000000..6ced2eb
--- /dev/null
@@ -0,0 +1,31 @@
+/*--------------------------------------------------------------------------
+ *  Copyright 2009 Taro L. Saito
+ *
+ *  Licensed 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.
+ *--------------------------------------------------------------------------*/
+//--------------------------------------
+// XerialJ
+//
+// MapEntry.java
+// Since: May 21, 2009 2:39:57 PM
+//
+// $URL$
+// $Author$
+//--------------------------------------
+package org.xerial.lens;
+
+public class MapEntry
+{
+    public Object key;
+    public Object value;
+}
index 9c0c8d6..42eaf77 100644 (file)
@@ -42,6 +42,7 @@ import java.util.regex.Pattern;
 import org.xerial.json.JSONString;\r
 import org.xerial.json.JSONWriter;\r
 import org.xerial.util.Pair;\r
+import org.xerial.util.bean.BeanUtil;\r
 import org.xerial.util.bean.TypeInfo;\r
 import org.xerial.util.log.Logger;\r
 import org.xerial.util.reflect.ReflectionUtil;\r
@@ -96,7 +97,7 @@ public class ObjectLens
         return Collections.unmodifiableList(getterContainer);\r
     }\r
 \r
-    public boolean hasParameters()\r
+    public boolean hasAttributes()\r
     {\r
         return !getterContainer.isEmpty();\r
     }\r
@@ -171,7 +172,6 @@ public class ObjectLens
         // scan methods\r
         for (Method eachMethod : targetType.getMethods())\r
         {\r
-\r
             String methodName = eachMethod.getName();\r
             String paramName = pickPropertyName(methodName);\r
 \r
@@ -182,6 +182,10 @@ public class ObjectLens
                 {\r
                 case 1:\r
                 {\r
+                    Class< ? > parentOfTheSetter = eachMethod.getDeclaringClass();\r
+                    if (TypeInfo.isCollection(parentOfTheSetter) || TypeInfo.isMap(parentOfTheSetter))\r
+                        break;\r
+\r
                     addNewSetter(setterContainer, paramName, eachMethod);\r
                     break;\r
                 }\r
@@ -192,8 +196,27 @@ public class ObjectLens
                     if (relName == null)\r
                     {\r
                         // infer relation node names\r
-                        relName = new Pair<String, String>(getCanonicalParameterName(argTypes[0].getSimpleName()),\r
-                                getCanonicalParameterName(argTypes[1].getSimpleName()));\r
+                        if (TypeInfo.isMap(eachMethod.getDeclaringClass()))\r
+                        {\r
+\r
+                            Class< ? >[] mapElementType = BeanUtil.resolveActualTypeOfMapElement(targetType, eachMethod\r
+                                    .getParameterTypes());\r
+\r
+                            // map.put(Key, Value)\r
+                            setterContainer\r
+                                    .add(ParameterSetter.newMapEntrySetter(mapElementType[0], mapElementType[1]));\r
+\r
+                            // (entry, key)\r
+                            setterContainer.add(ParameterSetter.newKeySetter(mapElementType[0]));\r
+                            // (entry, value)\r
+                            setterContainer.add(ParameterSetter.newValueSetter(mapElementType[1]));\r
+                            continue;\r
+                        }\r
+                        else\r
+                        {\r
+                            relName = new Pair<String, String>(getCanonicalParameterName(argTypes[0].getSimpleName()),\r
+                                    getCanonicalParameterName(argTypes[1].getSimpleName()));\r
+                        }\r
                     }\r
 \r
                     relationSetterContainer.add(RelationSetter.newRelationSetter(relName.getFirst(), relName\r
@@ -224,7 +247,6 @@ public class ObjectLens
             }\r
 \r
         }\r
-\r
     }\r
 \r
     private static void addNewSetter(List<ParameterSetter> setterContainer, String paramPart, Method m)\r
@@ -278,6 +300,9 @@ public class ObjectLens
 \r
     public static String getCanonicalParameterName(String paramName)\r
     {\r
+        if (paramName == null)\r
+            return paramName;\r
+\r
         Matcher m = paramNameReplacePattern.matcher(paramName);\r
         return m.replaceAll("").toLowerCase();\r
     }\r
@@ -313,43 +338,48 @@ public class ObjectLens
 \r
         if (TypeInfo.isCollection(c))\r
         {\r
-            if (lens.hasParameters())\r
+            Collection< ? > collection = (Collection< ? >) obj;\r
+            boolean hasAttributes = lens.hasAttributes();\r
+\r
+            if (hasAttributes)\r
             {\r
                 json.startObject();\r
                 outputParemters(json, obj);\r
 \r
-                json.startArray("entry");\r
+                if (!collection.isEmpty())\r
+                    json.startArray("entry");\r
             }\r
-            else\r
+            else if (!collection.isEmpty())\r
                 json.startArray();\r
 \r
-            Collection< ? > collection = (Collection< ? >) obj;\r
             for (Object elem : collection)\r
             {\r
                 toJSON(json, elem);\r
             }\r
 \r
-            json.endArray();\r
+            if (!collection.isEmpty())\r
+                json.endArray();\r
 \r
-            if (lens.hasParameters())\r
+            if (hasAttributes)\r
                 json.endObject();\r
 \r
         }\r
         else if (TypeInfo.isMap(c))\r
         {\r
-            if (lens.hasParameters())\r
+            Map< ? , ? > map = (Map< ? , ? >) obj;\r
+            boolean hasAttributes = lens.hasAttributes();\r
+\r
+            if (hasAttributes)\r
             {\r
                 json.startObject();\r
                 outputParemters(json, obj);\r
 \r
-                json.startArray("entry");\r
+                if (!map.isEmpty())\r
+                    json.startArray("entry");\r
             }\r
-            else\r
+            else if (!map.isEmpty())\r
                 json.startArray();\r
 \r
-            Map< ? , ? > map = (Map< ? , ? >) obj;\r
-\r
-            json.startArray();\r
             for (Entry< ? , ? > each : map.entrySet())\r
             {\r
                 json.startObject();\r
@@ -357,10 +387,11 @@ public class ObjectLens
                 json.putObject("value", each.getValue());\r
                 json.endObject();\r
             }\r
-            json.endArray();\r
-            json.endArray();\r
 \r
-            if (lens.hasParameters())\r
+            if (!map.isEmpty())\r
+                json.endArray();\r
+\r
+            if (hasAttributes)\r
                 json.endObject();\r
         }\r
         else\r
index cd912fc..14428a5 100644 (file)
@@ -33,6 +33,7 @@ import java.util.Set;
 import org.xerial.core.XerialError;
 import org.xerial.core.XerialErrorCode;
 import org.xerial.core.XerialException;
+import org.xerial.lens.ParameterSetter.MapEntryBinder;
 import org.xerial.relation.Node;
 import org.xerial.relation.query.AmoebaJoinHandlerBase;
 import org.xerial.relation.query.QuerySet;
@@ -199,7 +200,9 @@ public class ObjectMapper
 
         public void build(Class< ? > targetType, String alias)
         {
-            if (TypeInfo.isBasicType(targetType) || TypeInfo.isCollection(targetType))
+            // TODO use context-based schema -> binder mapping
+
+            if (TypeInfo.isBasicType(targetType) || TypeInfo.isCollection(targetType) || targetType == MapEntry.class)
                 return;
 
             if (processedClasses.contains(targetType))
@@ -213,6 +216,17 @@ public class ObjectMapper
 
             for (ParameterSetter each : lens.getSetterList())
             {
+                if (each.getClass() == MapEntryBinder.class)
+                {
+                    SchemaBuilder builder = new SchemaBuilder();
+                    builder.add("entry");
+                    builder.add(each.getParameterName());
+                    Schema s = builder.build();
+                    qs.addQueryTarget(s);
+                    schema2binder.put(s, new AttributeBinder(MapEntry.class, each));
+                    continue;
+                }
+
                 build(each.getParameterType(), each.getParameterName());
 
                 SchemaBuilder builder = new SchemaBuilder();
index 0a9259e..6db1dcb 100644 (file)
@@ -26,8 +26,12 @@ package org.xerial.lens;
 \r
 import java.lang.reflect.Field;\r
 import java.lang.reflect.Method;\r
+import java.util.Map;\r
 \r
+import org.xerial.core.XerialError;\r
+import org.xerial.core.XerialErrorCode;\r
 import org.xerial.core.XerialException;\r
+import org.xerial.util.log.Logger;\r
 import org.xerial.util.reflect.ReflectionUtil;\r
 \r
 /**\r
@@ -38,6 +42,8 @@ import org.xerial.util.reflect.ReflectionUtil;
  */\r
 public abstract class ParameterSetter\r
 {\r
+    private static Logger _logger = Logger.getLogger(ParameterSetter.class);\r
+\r
     private final Class< ? > parameterType;\r
     private final String parameterName;\r
 \r
@@ -90,6 +96,21 @@ public abstract class ParameterSetter
         return new MethodSetter(parameterType, parameterName, setterMethod);\r
     }\r
 \r
+    public static ParameterSetter newKeySetter(Class< ? > keyType)\r
+    {\r
+        return new MapEntryBinder(keyType, "key");\r
+    }\r
+\r
+    public static ParameterSetter newValueSetter(Class< ? > valueType)\r
+    {\r
+        return new MapEntryBinder(valueType, "value");\r
+    }\r
+\r
+    public static ParameterSetter newMapEntrySetter(Class< ? > keyType, Class< ? > valueType)\r
+    {\r
+        return new MapEntrySetter(keyType, valueType);\r
+    }\r
+\r
     private static class FieldSetter extends ParameterSetter\r
     {\r
         private final Field targetField;\r
@@ -136,4 +157,76 @@ public abstract class ParameterSetter
 \r
     }\r
 \r
+    static class MapEntryBinder extends ParameterSetter\r
+    {\r
+        private final Field targetField;\r
+\r
+        public MapEntryBinder(Class< ? > parameterType, String parameterName)\r
+        {\r
+            super(parameterType, parameterName);\r
+\r
+            try\r
+            {\r
+                targetField = MapEntry.class.getField(parameterName);\r
+            }\r
+            catch (Exception e)\r
+            {\r
+                throw new XerialError(XerialErrorCode.INVALID_STATE, e);\r
+            }\r
+\r
+        }\r
+\r
+        @Override\r
+        public void bind(Object entry, Object key) throws XerialException\r
+        {\r
+            ReflectionUtil.setFieldValue(entry, targetField, key);\r
+        }\r
+\r
+    }\r
+\r
+    private static class MapEntrySetter extends ParameterSetter\r
+    {\r
+        final Class< ? > keyType;\r
+        final Class< ? > valueType;\r
+\r
+        public MapEntrySetter(Class< ? > keyType, Class< ? > valueType)\r
+        {\r
+            super(MapEntry.class, "entry");\r
+\r
+            this.keyType = keyType;\r
+            this.valueType = valueType;\r
+        }\r
+\r
+        @SuppressWarnings("unchecked")\r
+        @Override\r
+        public void bind(Object mapObject, Object entryObject) throws XerialException\r
+        {\r
+            Map map = Map.class.cast(mapObject);\r
+            if (map == null)\r
+            {\r
+                _logger.warn("not a map type: " + mapObject);\r
+                return;\r
+            }\r
+\r
+            MapEntry entry = MapEntry.class.cast(entryObject);\r
+            if (entry == null)\r
+            {\r
+                _logger.warn("not a map entry type: " + entryObject);\r
+                return;\r
+            }\r
+\r
+            try\r
+            {\r
+                if (entry.key != null)\r
+                    map.put(keyType.cast(entry.key), valueType.cast(entry.value));\r
+            }\r
+            catch (ClassCastException e)\r
+            {\r
+                _logger.warn("cannot convert type: " + e);\r
+                return;\r
+            }\r
+        }\r
+\r
+    }\r
+\r
 }\r
index ff0266d..3d4912f 100644 (file)
@@ -140,4 +140,5 @@ public abstract class RelationSetter
 \r
         }\r
     }\r
+\r
 }\r
index 603d1da..1bd00f0 100644 (file)
@@ -450,7 +450,7 @@ public class BeanUtil
         return orig;\r
     }\r
 \r
-    private static Class< ? >[] resolveActualTypeOfMapElement(Type type, Class< ? >[] orig)\r
+    public static Class< ? >[] resolveActualTypeOfMapElement(Type type, Class< ? >[] orig)\r
     {\r
         ParameterizedType pt = getParentParameterizedType(type, Map.class);\r
         if (pt != null)\r
index a849250..953e49d 100644 (file)
@@ -26,6 +26,7 @@ package org.xerial.lens;
 
 import static org.junit.Assert.*;
 
+import java.io.StringReader;
 import java.util.TreeMap;
 
 import org.junit.After;
@@ -90,7 +91,24 @@ public class ObjectLensTest
 
     public static class ExtMap extends TreeMap<Integer, String>
     {
+        /**
+         * 
+         */
+        private static final long serialVersionUID = 1L;
+
         public String name = "ext-map";
+
+        @Override
+        public boolean equals(Object o)
+        {
+            if (!(o instanceof ExtMap))
+                return false;
+
+            ExtMap other = (ExtMap) o;
+
+            return name.equals(other.name) && super.equals(other);
+
+        }
     }
 
     @Test
@@ -99,7 +117,13 @@ public class ObjectLensTest
         ExtMap extMap = new ExtMap();
         extMap.put(1, "hello");
         extMap.put(10, "world");
-        _logger.info(ObjectLens.toJSON(extMap));
+        String json = ObjectLens.toJSON(extMap);
+        _logger.debug(json);
+
+        ExtMap extMap2 = Lens.loadJSON(ExtMap.class, new StringReader(json));
+        _logger.debug(ObjectLens.toJSON(extMap2));
+
+        assertEquals(extMap, extMap2);
     }
 
 }