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>