Author: cbegin
Date: Thu Feb  8 23:38:11 2007
New Revision: 505209

URL: http://svn.apache.org/viewvc?view=rev&rev=505209
Log:
Implemented direct-to-field mappings enabled by wrapping round brackets around 
field names.  So "id" is a property, but "(id)" is a field.  It's also possible 
to be mixed within a fully qualified name like:  "account.(address).(street)".  
Works for reads and writes.

Added:
    
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/GetFieldInvoker.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/Invoker.java
    
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/MethodInvoker.java
    
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/SetFieldInvoker.java
    
ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/DirectFieldMappingTest.java
Modified:
    ibatis/trunk/java/mapper/mapper2/build/version.properties
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ClassInfo.java
    
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ComplexBeanProbe.java
    
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/accessplan/BaseAccessPlan.java
    
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/accessplan/PropertyAccessPlan.java
    ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/maps/Account.xml

Modified: ibatis/trunk/java/mapper/mapper2/build/version.properties
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/build/version.properties?view=diff&rev=505209&r1=505208&r2=505209
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/build/version.properties (original)
+++ ibatis/trunk/java/mapper/mapper2/build/version.properties Thu Feb  8 
23:38:11 2007
@@ -1,5 +1,5 @@
 #Build version info
-#Mon Feb 05 16:44:37 CST 2007
+#Fri Feb 09 00:34:05 MST 2007
 version=2.3.1
-buildDate=2007/02/05 16\:44
-buildNum=678
+buildDate=2007/02/09 00\:34
+buildNum=680

Modified: 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ClassInfo.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ClassInfo.java?view=diff&rev=505209&r1=505208&r2=505209
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ClassInfo.java 
(original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ClassInfo.java 
Thu Feb  8 23:38:11 2007
@@ -18,10 +18,7 @@
 import com.ibatis.common.logging.Log;
 import com.ibatis.common.logging.LogFactory;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.UndeclaredThrowableException;
-import java.lang.reflect.ReflectPermission;
+import java.lang.reflect.*;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.*;
@@ -80,10 +77,25 @@
   private ClassInfo(Class clazz) {
     className = clazz.getName();
     addMethods(clazz);
+    addFields (clazz);
     readablePropertyNames = (String[]) getMethods.keySet().toArray(new 
String[getMethods.keySet().size()]);
     writeablePropertyNames = (String[]) setMethods.keySet().toArray(new 
String[setMethods.keySet().size()]);
   }
 
+  private void addFields(Class clazz) {
+    Field[] fields = clazz.getDeclaredFields();
+    for (int i=0; i < fields.length; i++) {
+      fields[i].setAccessible(true);
+      setMethods.put("(" + fields[i].getName() + ")", new 
SetFieldInvoker(fields[i]));
+      setTypes.put("(" + fields[i].getName() + ")", fields[i].getType());
+      getMethods.put("(" + fields[i].getName() + ")", new 
GetFieldInvoker(fields[i]));
+      getTypes.put("(" + fields[i].getName() + ")", fields[i].getType());
+    }
+    if (clazz.getSuperclass() != null) {
+      addFields(clazz.getSuperclass());
+    }
+  }
+
   private void addMethods(Class cls) {
     Method[] methods = getAllMethodsForClass(cls);
     for (int i = 0; i < methods.length; i++) {
@@ -96,19 +108,19 @@
             log.error("Illegal overloaded setter method for property " + name 
+ " in class " + cls.getName() +
                 ".  This breaks the JavaBeans specification and can cause 
unpredicatble results.");
           }
-          setMethods.put(name, methods[i]);
+          setMethods.put(name, new MethodInvoker(methods[i]));
           setTypes.put(name, methods[i].getParameterTypes()[0]);
         }
       } else if (name.startsWith("get") && name.length() > 3) {
         if (methods[i].getParameterTypes().length == 0) {
           name = dropCase(name);
-          getMethods.put(name, methods[i]);
+          getMethods.put(name, new MethodInvoker(methods[i]));
           getTypes.put(name, methods[i].getReturnType());
         }
       } else if (name.startsWith("is") && name.length() > 2) {
         if (methods[i].getParameterTypes().length == 0) {
           name = dropCase(name);
-          getMethods.put(name, methods[i]);
+          getMethods.put(name, new MethodInvoker(methods[i]));
           getTypes.put(name, methods[i].getReturnType());
         }
       }
@@ -240,11 +252,14 @@
    * @return The Method
    */
   public Method getSetter(String propertyName) {
-    Method method = (Method) setMethods.get(propertyName);
+    Invoker method = (Invoker) setMethods.get(propertyName);
     if (method == null) {
       throw new ProbeException("There is no WRITEABLE property named '" + 
propertyName + "' in class '" + className + "'");
     }
-    return method;
+    if (!(method instanceof MethodInvoker)) {
+      throw new ProbeException("Can't get setter method because '" + 
propertyName + "' is a field in class '" + className + "'");    
+    }
+    return ((MethodInvoker)method).getMethod();
   }
 
   /**
@@ -254,7 +269,26 @@
    * @return The Method
    */
   public Method getGetter(String propertyName) {
-    Method method = (Method) getMethods.get(propertyName);
+    Invoker method = (Invoker) getMethods.get(propertyName);
+    if (method == null) {
+      throw new ProbeException("There is no READABLE property named '" + 
propertyName + "' in class '" + className + "'");
+    }
+    if (!(method instanceof MethodInvoker)) {
+      throw new ProbeException("Can't get getter method because '" + 
propertyName + "' is a field in class '" + className + "'");
+    }
+    return ((MethodInvoker)method).getMethod();
+  }
+
+  public Invoker getSetInvoker(String propertyName) {
+    Invoker method = (Invoker) setMethods.get(propertyName);
+    if (method == null) {
+      throw new ProbeException("There is no WRITEABLE property named '" + 
propertyName + "' in class '" + className + "'");
+    }
+    return method;
+  }
+
+  public Invoker getGetInvoker(String propertyName) {
+    Invoker method = (Invoker) getMethods.get(propertyName);
     if (method == null) {
       throw new ProbeException("There is no READABLE property named '" + 
propertyName + "' in class '" + className + "'");
     }
@@ -394,8 +428,7 @@
       }
     }
   }
-
-
+  
 }
 
 

Modified: 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ComplexBeanProbe.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ComplexBeanProbe.java?view=diff&rev=505209&r1=505208&r2=505209
==============================================================================
--- 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ComplexBeanProbe.java
 (original)
+++ 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ComplexBeanProbe.java
 Thu Feb  8 23:38:11 2007
@@ -15,12 +15,12 @@
  */
 package com.ibatis.common.beans;
 
+import com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactoryUtil;
+
 import java.lang.reflect.Method;
 import java.util.Map;
 import java.util.StringTokenizer;
 
-import com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactoryUtil;
-
 /**
  * StaticBeanProbe provides methods that allow simple, reflective access to
  * JavaBeans style properties.  Methods are provided for all simple types as
@@ -301,7 +301,7 @@
         if (object instanceof Map) {
           value = ((Map) object).get(name);
         } else {
-          Method method = classCache.getGetter(name);
+          Invoker method = classCache.getGetInvoker(name);
           if (method == null) {
             throw new NoSuchMethodException("No GET method for property " + 
name + " on instance of " + object.getClass().getName());
           }
@@ -333,7 +333,7 @@
         if (object instanceof Map) {
           ((Map) object).put(name, value);
         } else {
-          Method method = classCache.getSetter(name);
+          Invoker method = classCache.getSetInvoker(name);
           if (method == null) {
             throw new NoSuchMethodException("No SET method for property " + 
name + " on instance of " + object.getClass().getName());
           }

Added: 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/GetFieldInvoker.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/GetFieldInvoker.java?view=auto&rev=505209
==============================================================================
--- 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/GetFieldInvoker.java
 (added)
+++ 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/GetFieldInvoker.java
 Thu Feb  8 23:38:11 2007
@@ -0,0 +1,22 @@
+package com.ibatis.common.beans;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Field;
+
+public class GetFieldInvoker implements Invoker {
+  private Field field;
+  private String name;
+
+  public GetFieldInvoker(Field field) {
+    this.field = field;
+    this.name = "(" + field.getName() + ")";
+  }
+
+  public Object invoke(Object target, Object[] args) throws 
IllegalAccessException, InvocationTargetException {
+    return field.get(target);
+  }
+
+  public String getName() {
+    return name;
+  }
+}

Added: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/Invoker.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/Invoker.java?view=auto&rev=505209
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/Invoker.java 
(added)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/Invoker.java 
Thu Feb  8 23:38:11 2007
@@ -0,0 +1,8 @@
+package com.ibatis.common.beans;
+
+import java.lang.reflect.InvocationTargetException;
+
+public interface Invoker {
+  String getName();
+  Object invoke(Object target, Object[] args) throws IllegalAccessException, 
InvocationTargetException;
+}

Added: 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/MethodInvoker.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/MethodInvoker.java?view=auto&rev=505209
==============================================================================
--- 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/MethodInvoker.java 
(added)
+++ 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/MethodInvoker.java 
Thu Feb  8 23:38:11 2007
@@ -0,0 +1,27 @@
+package com.ibatis.common.beans;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+public class MethodInvoker implements Invoker {
+
+  private Method method;
+  private String name;
+
+  public MethodInvoker(Method method) {
+    this.method = method;
+    this.name = method.getName();
+  }
+
+  public Object invoke(Object target, Object[] args) throws 
IllegalAccessException, InvocationTargetException {
+    return method.invoke(target, args);
+  }
+
+  public Method getMethod() {
+    return method;
+  }
+
+  public String getName() {
+    return name;
+  }
+}

Added: 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/SetFieldInvoker.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/SetFieldInvoker.java?view=auto&rev=505209
==============================================================================
--- 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/SetFieldInvoker.java
 (added)
+++ 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/SetFieldInvoker.java
 Thu Feb  8 23:38:11 2007
@@ -0,0 +1,23 @@
+package com.ibatis.common.beans;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Field;
+
+public class SetFieldInvoker implements Invoker {
+  private Field field;
+  private String name;
+
+  public SetFieldInvoker(Field field) {
+    this.field = field;
+    this.name = "(" + field.getName() + ")";
+  }
+
+  public Object invoke(Object target, Object[] args) throws 
IllegalAccessException, InvocationTargetException {
+    field.set(target, args[0]);
+    return null;
+  }
+
+  public String getName() {
+    return name;
+  }
+}

Modified: 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/accessplan/BaseAccessPlan.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/accessplan/BaseAccessPlan.java?view=diff&rev=505209&r1=505208&r2=505209
==============================================================================
--- 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/accessplan/BaseAccessPlan.java
 (original)
+++ 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/accessplan/BaseAccessPlan.java
 Thu Feb  8 23:38:11 2007
@@ -16,8 +16,7 @@
 package com.ibatis.sqlmap.engine.accessplan;
 
 import com.ibatis.common.beans.ClassInfo;
-
-import java.lang.reflect.Method;
+import com.ibatis.common.beans.Invoker;
 
 /**
  * Base implementation of the AccessPlan interface
@@ -42,18 +41,18 @@
     return types;
   }
 
-  protected Method[] getGetters(String[] propertyNames) {
-    Method[] methods = new Method[propertyNames.length];
+  protected Invoker[] getGetters(String[] propertyNames) {
+    Invoker[] methods = new Invoker[propertyNames.length];
     for (int i = 0; i < propertyNames.length; i++) {
-      methods[i] = info.getGetter(propertyNames[i]);
+      methods[i] = info.getGetInvoker(propertyNames[i]);
     }
     return methods;
   }
 
-  protected Method[] getSetters(String[] propertyNames) {
-    Method[] methods = new Method[propertyNames.length];
+  protected Invoker[] getSetters(String[] propertyNames) {
+    Invoker[] methods = new Invoker[propertyNames.length];
     for (int i = 0; i < propertyNames.length; i++) {
-      methods[i] = info.getSetter(propertyNames[i]);
+      methods[i] = info.getSetInvoker(propertyNames[i]);
     }
     return methods;
   }

Modified: 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/accessplan/PropertyAccessPlan.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/accessplan/PropertyAccessPlan.java?view=diff&rev=505209&r1=505208&r2=505209
==============================================================================
--- 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/accessplan/PropertyAccessPlan.java
 (original)
+++ 
ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/accessplan/PropertyAccessPlan.java
 Thu Feb  8 23:38:11 2007
@@ -16,7 +16,7 @@
 package com.ibatis.sqlmap.engine.accessplan;
 
 import com.ibatis.common.beans.ClassInfo;
-
+import com.ibatis.common.beans.Invoker;
 
 import java.lang.reflect.Method;
 
@@ -27,8 +27,8 @@
 
   protected static final Object[] NO_ARGUMENTS = new Object[0];
 
-  protected Method[] setters;
-  protected Method[] getters;
+  protected Invoker[] setters;
+  protected Invoker[] getters;
 
   PropertyAccessPlan(Class clazz, String[] propertyNames) {
     super(clazz, propertyNames);

Added: 
ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/DirectFieldMappingTest.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/DirectFieldMappingTest.java?view=auto&rev=505209
==============================================================================
--- 
ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/DirectFieldMappingTest.java
 (added)
+++ 
ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/DirectFieldMappingTest.java
 Thu Feb  8 23:38:11 2007
@@ -0,0 +1,26 @@
+package com.ibatis.sqlmap;
+
+import testdomain.Account;
+
+import java.sql.SQLException;
+
+public class DirectFieldMappingTest extends BaseSqlMapTest {
+
+    protected void setUp() throws Exception {
+    initSqlMap("com/ibatis/sqlmap/maps/SqlMapConfig.xml", null);
+    initScript("scripts/account-init.sql");
+  }
+
+  public void testInsertAndSelectDirectToFields() throws SQLException {
+    Account account = newAccount6();
+
+    sqlMap.update("insertAccountFromFields", account);
+
+    account = (Account) sqlMap.queryForObject("getAccountToFields", new 
Integer(6));
+
+    assertAccount6(account);
+    assertAccount6(account.getAccount());
+  }
+  
+
+}

Modified: 
ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/maps/Account.xml
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/maps/Account.xml?view=diff&rev=505209&r1=505208&r2=505209
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/maps/Account.xml 
(original)
+++ ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/maps/Account.xml 
Thu Feb  8 23:38:11 2007
@@ -460,4 +460,37 @@
     where ACC_ID = #value#
   </select>
 
+
+  <insert id="insertAccountFromFields"
+    parameterClass="account"
+    >
+    insert into ACCOUNT (
+      ACC_ID,
+      ACC_FIRST_NAME,
+      ACC_LAST_NAME,
+      ACC_EMAIL)
+    values (
+      #(id)#,
+      #(firstName)#,
+      #(lastName)#,
+      #(emailAddress):VARCHAR:[EMAIL PROTECTED]
+    )
+  </insert>
+
+  <select id="getAccountToFields"
+    parameterClass="int"
+    resultClass="account">
+    select
+      ACC_ID as "(id)",
+      ACC_FIRST_NAME as "(firstName)",
+      ACC_LAST_NAME as "(lastName)",
+      ACC_EMAIL as "(emailAddress)",
+      ACC_ID as "(account).(id)",
+      ACC_FIRST_NAME as "(account).(firstName)",
+      ACC_LAST_NAME as "(account).(lastName)",
+      ACC_EMAIL as "(account).(emailAddress)"
+    from ACCOUNT
+    where ACC_ID = #value#
+  </select>
+
 </sqlMap>


Reply via email to