import java.lang.reflect.Method;\r
import java.lang.reflect.Modifier;\r
import java.util.ArrayList;\r
+import java.util.HashMap;\r
import java.util.List;\r
import java.util.regex.Matcher;\r
import java.util.regex.Pattern;\r
\r
+import org.xerial.util.Pair;\r
import org.xerial.util.bean.TypeInformation;\r
\r
+/**\r
+ * Tree to Object lens\r
+ * \r
+ * @author leo\r
+ * \r
+ */\r
public class ObjectLens\r
{\r
- public ObjectLens(Class< ? > targetType)\r
+ private static HashMap<Class< ? >, ObjectLens> cache = new HashMap<Class< ? >, ObjectLens>();\r
+\r
+ /**\r
+ * Get the lens of the target type\r
+ * \r
+ * @param target\r
+ * @return lens of the target type\r
+ */\r
+ public static ObjectLens getObjectLens(Class< ? > target)\r
{\r
- createBindRules(targetType);\r
+ if (cache.containsKey(target))\r
+ return cache.get(target);\r
+ else\r
+ {\r
+ cache.put(target, new ObjectLens(target));\r
+ return getObjectLens(target);\r
+ }\r
}\r
\r
- private static void createBindRules(Class< ? > targetType)\r
+ private List<ParameterSetter> setterContainer = new ArrayList<ParameterSetter>();\r
+ private List<RelationSetter> relationSetterContainer = new ArrayList<RelationSetter>();\r
+\r
+ protected ObjectLens(Class< ? > targetType)\r
{\r
- List<ParameterSetter> setterContainer = new ArrayList<ParameterSetter>();\r
+ createBindRules(targetType);\r
+ }\r
\r
+ private void createBindRules(Class< ? > targetType)\r
+ {\r
// look for all super classes\r
for (Class< ? > eachClass = targetType; eachClass != null; eachClass = eachClass.getSuperclass())\r
{\r
for (Method eachMethod : eachClass.getMethods())\r
{\r
String methodName = eachMethod.getName();\r
- String parametrName = pickPropertyName(methodName);\r
- if (methodName.startsWith("add"))\r
- {\r
- // adder\r
- String paramName = getCanonicalParameterName(methodName.substring(3));\r
- setterContainer.add(ParameterSetter.newSetter(eachClass, paramName, eachMethod));\r
+ String paramPart = pickPropertyName(methodName);\r
\r
- }\r
- else if (methodName.startsWith("set"))\r
+ if (methodName.startsWith("add") || methodName.startsWith("set") || methodName.startsWith("put"))\r
{\r
- // setter\r
- String paramName = getCanonicalParameterName(methodName.substring(3));\r
-\r
- }\r
- else if (methodName.startsWith("get"))\r
- {\r
- // we cannot use any getter that requires some arguments\r
- Class< ? >[] parameterType = eachMethod.getParameterTypes();\r
- if (parameterType.length != 0)\r
+ Class< ? >[] argTypes = eachMethod.getParameterTypes();\r
+ switch (argTypes.length)\r
+ {\r
+ case 1:\r
+ {\r
+ addNewSetter(eachClass, paramPart, eachMethod);\r
+ break;\r
+ }\r
+ case 2:\r
+ {\r
+ // relation adder\r
+ Pair<String, String> relName = pickRelationName(paramPart);\r
+ relationSetterContainer.add(RelationSetter.newRelationSetter(relName.getFirst(), relName\r
+ .getSecond(), eachMethod));\r
+ break;\r
+ }\r
+ default:\r
continue;\r
-\r
- }\r
- else if (methodName.startsWith("put"))\r
- {\r
+ }\r
\r
}\r
else if (methodName.startsWith("append"))\r
{\r
- // appender for a large text value split into chunks\r
-\r
+ addNewSetter(eachClass, paramPart, eachMethod);\r
}\r
\r
}\r
\r
}\r
\r
+ private void addNewSetter(Class< ? > c, String paramPart, Method m)\r
+ {\r
+ Class< ? >[] argTypes = m.getParameterTypes();\r
+ if (argTypes.length != 1)\r
+ return;\r
+\r
+ assert (argTypes.length == 1);\r
+\r
+ String paramName = getCanonicalParameterName(paramPart);\r
+ if (paramName.length() <= 0)\r
+ {\r
+ // infer parameter name from argument type\r
+ paramName = getCanonicalParameterName(argTypes[0].getName());\r
+ }\r
+ setterContainer.add(ParameterSetter.newSetter(c, paramName, m));\r
+ return;\r
+ }\r
+\r
static private Pattern propertyNamePattern = Pattern.compile("^(set|get|add|put|append)((\\S)(\\S*))?");\r
+ static private Pattern pairedNamePattern = Pattern.compile("([A-Za-z0-9]*)_([A-Za-z0-9]*)");\r
\r
public static String pickPropertyName(String methodName)\r
{\r
else\r
{\r
if (m.group(2) != null)\r
- return getCanonicalParameterName(m.group(3) + m.group(4));\r
+ return getCanonicalParameterName(m.group(2));\r
else\r
return "";\r
}\r
}\r
\r
+ public static Pair<String, String> pickRelationName(String pairedName)\r
+ {\r
+ Matcher m = null;\r
+ m = pairedNamePattern.matcher(pairedName);\r
+ if (!m.matches())\r
+ return null;\r
+ else\r
+ return new Pair<String, String>(getCanonicalParameterName(m.group(1)),\r
+ getCanonicalParameterName(m.group(2)));\r
+ }\r
+\r
public static String getCanonicalParameterName(String paramName)\r
{\r
paramName = paramName.replaceAll("\\s", "");\r
//--------------------------------------\r
package org.xerial.lens;\r
\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+\r
+import org.xerial.core.XerialError;\r
+import org.xerial.core.XerialErrorCode;\r
import org.xerial.core.XerialException;\r
\r
/**\r
*/\r
public abstract class RelationSetter\r
{\r
- public abstract void bind(Object object, Object value) throws XerialException;\r
+ private final Class< ? > coreNodeType;\r
+ private final Class< ? > attributeNodeType;\r
+\r
+ private final String coreNodeName;\r
+ private final String attributeNodeName;\r
+\r
+ protected RelationSetter(Class< ? > coreNodeType, String coreNodeName, Class< ? > attributeNodeType,\r
+ String attributeNodeName)\r
+ {\r
+ this.coreNodeType = coreNodeType;\r
+ this.attributeNodeType = attributeNodeType;\r
+ this.coreNodeName = coreNodeName;\r
+ this.attributeNodeName = attributeNodeName;\r
+ }\r
+\r
+ @Override\r
+ public boolean equals(Object obj)\r
+ {\r
+ RelationSetter other = RelationSetter.class.cast(obj);\r
+ if (other == null)\r
+ return false;\r
+ boolean eq = this.coreNodeName.equals(other.coreNodeName);\r
+ return eq ? this.attributeNodeName.equals(other.attributeNodeName) : false;\r
+ }\r
+\r
+ @Override\r
+ public int hashCode()\r
+ {\r
+ return coreNodeName.hashCode() + attributeNodeName.hashCode();\r
+ }\r
+\r
+ public abstract void bind(Object object, Object coreValue, Object attributeValue) throws XerialException;\r
+\r
+ public static RelationSetter newRelationSetter(String coreNodeName, String attributeNodeName, Method setterMethod)\r
+ {\r
+ Class< ? >[] argType = setterMethod.getParameterTypes();\r
+ if (argType.length != 2)\r
+ throw new XerialError(XerialErrorCode.INVALID_INPUT, setterMethod.toString());\r
+ return new MethodRelationSetter(argType[0], coreNodeName, argType[1], attributeNodeName, setterMethod);\r
+ }\r
+\r
+ private static class MethodRelationSetter extends RelationSetter\r
+ {\r
+ private final Method setter;\r
+\r
+ public MethodRelationSetter(Class< ? > coreNodeType, String coreNodeName, Class< ? > attributeNodeType,\r
+ String attributeNodeName, Method setter)\r
+ {\r
+ super(coreNodeType, coreNodeName, attributeNodeType, attributeNodeName);\r
+ this.setter = setter;\r
+ }\r
+\r
+ @Override\r
+ public void bind(Object object, Object coreValue, Object attributeValue) throws XerialException\r
+ {\r
+ try\r
+ {\r
+ setter.invoke(object, coreValue, attributeValue);\r
+ }\r
+ catch (IllegalArgumentException e)\r
+ {\r
+ throw new XerialException(XerialErrorCode.WRONG_DATA_TYPE, e);\r
+ }\r
+ catch (IllegalAccessException e)\r
+ {\r
+ throw new XerialException(XerialErrorCode.INVALID_INPUT, e);\r
+ }\r
+ catch (InvocationTargetException e)\r
+ {\r
+ throw new XerialError(XerialErrorCode.WRONG_DATA_TYPE, e);\r
+ }\r
\r
+ }\r
+ }\r
}\r
\r
SilkEvent currentEvent = parser.next();\r
\r
+ // update the line count\r
numReadLine = parser.getNumReadLine();\r
\r
if (_logger.isTraceEnabled())\r
--- /dev/null
+/*--------------------------------------------------------------------------
+ * 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
+//
+// ObjectLensTest.java
+// Since: May 19, 2009 12:23:25 PM
+//
+// $URL$
+// $Author$
+//--------------------------------------
+package org.xerial.lens;
+
+import static org.junit.Assert.*;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.xerial.util.Pair;
+
+public class ObjectLensTest
+{
+
+ @Before
+ public void setUp() throws Exception
+ {}
+
+ @After
+ public void tearDown() throws Exception
+ {}
+
+ @Test
+ public void pickPairedName() throws Exception
+ {
+ Pair<String, String> p = ObjectLens.pickRelationName("Invoice_Order");
+ assertEquals("invoice", p.getFirst());
+ assertEquals("order", p.getSecond());
+
+ p = ObjectLens.pickRelationName("LineItem_Order");
+ assertEquals("lineitem", p.getFirst());
+ assertEquals("order", p.getSecond());
+
+ p = ObjectLens.pickRelationName("gene_JSON");
+ assertEquals("gene", p.getFirst());
+ assertEquals("json", p.getSecond());
+
+ }
+
+ @Test
+ public void pickPropertyName() throws Exception
+ {
+ String c = ObjectLens.pickPropertyName("addSomething");
+ assertEquals("something", c);
+
+ c = ObjectLens.pickPropertyName("addSomethingImportant");
+ assertEquals("somethingimportant", c);
+
+ c = ObjectLens.pickPropertyName("add");
+ assertEquals("", c);
+
+ }
+
+}