You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ibatis.apache.org by jg...@apache.org on 2006/11/27 17:53:04 UTC

svn commit: r479687 - in /ibatis/trunk/java/mapper/mapper2: build/ src/com/ibatis/common/beans/ src/com/ibatis/sqlmap/engine/exchange/ src/com/ibatis/sqlmap/engine/execution/ src/com/ibatis/sqlmap/engine/mapping/result/

Author: jgbutler
Date: Mon Nov 27 08:53:03 2006
New Revision: 479687

URL: http://svn.apache.org/viewvc?view=rev&rev=479687
Log:
Fixes for IBATIS-366: Use ResultObjectFactory for nested classes

Modified:
    ibatis/trunk/java/mapper/mapper2/build/version.properties
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ComplexBeanProbe.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/exchange/ComplexDataExchange.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/exchange/JavaBeanDataExchange.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/execution/SqlExecutor.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/BasicResultMap.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactory.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactoryUtil.java

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=479687&r1=479686&r2=479687
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/build/version.properties (original)
+++ ibatis/trunk/java/mapper/mapper2/build/version.properties Mon Nov 27 08:53:03 2006
@@ -1,5 +1,5 @@
 #Build version info
-#Mon Nov 20 22:45:11 MST 2006
+#Mon Nov 27 10:29:35 CST 2006
 version=2.3.0
-buildDate=2006/11/20 22\:45
-buildNum=669
+buildDate=2006/11/27 10\:29
+buildNum=671

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=479687&r1=479686&r2=479687
==============================================================================
--- 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 Mon Nov 27 08:53:03 2006
@@ -19,6 +19,8 @@
 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
@@ -219,7 +221,7 @@
             return; // don't instantiate child path if value is null
           } else {
             try {
-              child = type.newInstance();
+              child = ResultObjectFactoryUtil.createObjectThroughFactory(type);
               setObject(parent, property, child);
             } catch (Exception e) {
               throw new ProbeException("Cannot set value of property '" + name + "' because '" + property + "' is null and cannot be instantiated on instance of " + type.getName() + ". Cause:" + e.toString(), e);

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/exchange/ComplexDataExchange.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/exchange/ComplexDataExchange.java?view=diff&rev=479687&r1=479686&r2=479687
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/exchange/ComplexDataExchange.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/exchange/ComplexDataExchange.java Mon Nov 27 08:53:03 2006
@@ -18,7 +18,6 @@
 import com.ibatis.common.beans.Probe;
 import com.ibatis.common.beans.ProbeFactory;
 
-import com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient;
 import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;
 import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMapping;
 import com.ibatis.sqlmap.engine.mapping.result.ResultMap;
@@ -78,9 +77,7 @@
       Object object = resultObject;
       if (object == null) {
         try {
-          ExtendedSqlMapClient client = (ExtendedSqlMapClient) request.getSession().getSqlMapClient();
-          object = ResultObjectFactoryUtil.createObjectThroughFactory(client.getResultObjectFactory(),
-              request.getStatement().getId(), resultMap.getResultClass());
+          object = ResultObjectFactoryUtil.createObjectThroughFactory(resultMap.getResultClass());
         } catch (Exception e) {
           throw new RuntimeException("JavaBeansDataExchange could not instantiate result class.  Cause: " + e, e);
         }
@@ -101,9 +98,7 @@
       Object object = parameterObject;
       if (object == null) {
         try {
-          ExtendedSqlMapClient client = (ExtendedSqlMapClient) request.getSession().getSqlMapClient();
-          object = ResultObjectFactoryUtil.createObjectThroughFactory(client.getResultObjectFactory(),
-              request.getStatement().getId(), parameterMap.getParameterClass());
+          object = ResultObjectFactoryUtil.createObjectThroughFactory(parameterMap.getParameterClass());
         } catch (Exception e) {
           throw new RuntimeException("JavaBeansDataExchange could not instantiate result class.  Cause: " + e, e);
         }

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/exchange/JavaBeanDataExchange.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/exchange/JavaBeanDataExchange.java?view=diff&rev=479687&r1=479686&r2=479687
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/exchange/JavaBeanDataExchange.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/exchange/JavaBeanDataExchange.java Mon Nov 27 08:53:03 2006
@@ -18,7 +18,6 @@
 
 import com.ibatis.sqlmap.engine.accessplan.AccessPlan;
 import com.ibatis.sqlmap.engine.accessplan.AccessPlanFactory;
-import com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient;
 import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;
 import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMapping;
 import com.ibatis.sqlmap.engine.mapping.result.ResultMap;
@@ -104,9 +103,7 @@
       if (object == null) {
         errorContext.setMoreInfo("The error occured while instantiating the result object");
         try {
-          ExtendedSqlMapClient client = (ExtendedSqlMapClient) request.getSession().getSqlMapClient();
-          object = ResultObjectFactoryUtil.createObjectThroughFactory(client.getResultObjectFactory(),
-              request.getStatement().getId(), resultMap.getResultClass());
+          object = ResultObjectFactoryUtil.createObjectThroughFactory(resultMap.getResultClass());
         } catch (Exception e) {
           throw new RuntimeException("JavaBeansDataExchange could not instantiate result class.  Cause: " + e, e);
         }
@@ -125,9 +122,7 @@
       Object object = parameterObject;
       if (object == null) {
         try {
-          ExtendedSqlMapClient client = (ExtendedSqlMapClient) request.getSession().getSqlMapClient();
-          object = ResultObjectFactoryUtil.createObjectThroughFactory(client.getResultObjectFactory(),
-              request.getStatement().getId(), parameterMap.getParameterClass());
+          object = ResultObjectFactoryUtil.createObjectThroughFactory(parameterMap.getParameterClass());
         } catch (Exception e) {
           throw new RuntimeException("JavaBeansDataExchange could not instantiate parameter class. Cause: " + e, e);
         }

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/execution/SqlExecutor.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/execution/SqlExecutor.java?view=diff&rev=479687&r1=479686&r2=479687
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/execution/SqlExecutor.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/execution/SqlExecutor.java Mon Nov 27 08:53:03 2006
@@ -19,6 +19,7 @@
 import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;
 import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMapping;
 import com.ibatis.sqlmap.engine.mapping.result.ResultMap;
+import com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactoryUtil;
 import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
 import com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback;
 import com.ibatis.sqlmap.engine.scope.ErrorContext;
@@ -68,6 +69,7 @@
     errorContext.setActivity("executing update");
     errorContext.setObjectId(sql);
     PreparedStatement ps = null;
+    setupResultObjectFactory(request);
     int rows = 0;
     try {
       errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
@@ -164,6 +166,7 @@
     errorContext.setObjectId(sql);
     PreparedStatement ps = null;
     ResultSet rs = null;
+    setupResultObjectFactory(request);
     try {
       errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
       Integer rsType = request.getStatement().getResultSetType();
@@ -211,6 +214,7 @@
     errorContext.setActivity("executing update procedure");
     errorContext.setObjectId(sql);
     CallableStatement cs = null;
+    setupResultObjectFactory(request);
     int rows = 0;
     try {
       errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
@@ -251,6 +255,7 @@
     errorContext.setObjectId(sql);
     CallableStatement cs = null;
     ResultSet rs = null;
+    setupResultObjectFactory(request);
     try {
       errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
       Integer rsType = request.getStatement().getResultSetType();
@@ -666,4 +671,9 @@
     }
   }
 
+  private void setupResultObjectFactory(RequestScope request) {
+    ExtendedSqlMapClient client = (ExtendedSqlMapClient) request.getSession().getSqlMapClient();
+    ResultObjectFactoryUtil.setResultObjectFactory(client.getResultObjectFactory());
+    ResultObjectFactoryUtil.setStatementId(request.getStatement().getId());
+  }
 }

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/BasicResultMap.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/BasicResultMap.java?view=diff&rev=479687&r1=479686&r2=479687
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/BasicResultMap.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/BasicResultMap.java Mon Nov 27 08:53:03 2006
@@ -436,9 +436,7 @@
           // then we will just set the property to the object created
           // in processing the nested result map
           if (Collection.class.isAssignableFrom(type)) {
-            ExtendedSqlMapClient client = (ExtendedSqlMapClient) request.getSession().getSqlMapClient();
-            obj = ResultObjectFactoryUtil.createObjectThroughFactory(client.getResultObjectFactory(),
-                request.getStatement().getId(), type);
+            obj = ResultObjectFactoryUtil.createObjectThroughFactory(type);
             PROBE.setObject(resultObject, propertyName, obj);
           }
         } catch (Exception e) {
@@ -574,9 +572,7 @@
     if (parameterType == null) {
       parameterObject = new HashMap();
     } else {
-      ExtendedSqlMapClient client = (ExtendedSqlMapClient) request.getSession().getSqlMapClient();
-      parameterObject = ResultObjectFactoryUtil.createObjectThroughFactory(client.getResultObjectFactory(),
-          request.getStatement().getId(), parameterType);
+      parameterObject = ResultObjectFactoryUtil.createObjectThroughFactory(parameterType);
     }
     String complexName = mapping.getColumnName();
 

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactory.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactory.java?view=diff&rev=479687&r1=479686&r2=479687
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactory.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactory.java Mon Nov 27 08:53:03 2006
@@ -21,6 +21,9 @@
  * your implementation class as the type for the "resultObjectFactory"
  * element in the SqlMapConfig.  Any implementation of this interface
  * must have a public no argument constructor.
+ * 
+ * Note that iBATIS makes use of this interface through the
+ * ResultObjectFactoryUtil class.
  *   
  * @author Jeff Butler
  *
@@ -42,7 +45,7 @@
    *   <li>When processing result maps with nested result maps.  iBATIS will
    *     ask the factory to create an instance of the nested object.  If the nested
    *     object is some implementation of <code>java.util.Collection</code>
-   *     then iBATIS will suppliy default implementations of the common interfaces
+   *     then iBATIS will supply default implementations of the common interfaces
    *     if the factory chooses not to create the object.  If the
    *     embedded object is a <code>java.util.List</code> or 
    *     <code>java.util.Collection</code> the default behavior is to

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactoryUtil.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactoryUtil.java?view=diff&rev=479687&r1=479686&r2=479687
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactoryUtil.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactoryUtil.java Mon Nov 27 08:53:03 2006
@@ -24,11 +24,32 @@
 import com.ibatis.common.resources.Resources;
 
 /**
- * @author Jeff Butler
+ * This class is used to create instances of result objects.  It will
+ * use the configured ResultObjectFactory if there is one, otherwise
+ * it will use iBATIS' normal methods.
+ * 
+ * Note that this class is somewhat tightly coupled with
+ * SqlExecuter - SqlExecute must call the setStatementId() and
+ * setResultObjectFactory() methods before executing a statement.
+ * This is a result of using a ThreadLocal to hold the current
+ * configuration for the statement under execution.  Using a
+ * ThreadLocal is a solution for IBATIS-366.  Without a ThreadLocal,
+ * the current factory and statement id would have to be added to 
+ * many method signatures - often in inappropriate places.
  * 
+ * @author Jeff Butler
  */
 public class ResultObjectFactoryUtil {
-
+  
+  /**
+   * Use a ThreadLocal to hold the current statementId and
+   * factory.  This is much easier than passing these
+   * items all over the place, and it has no measurable impact on
+   * performance (I did a test with 100000 result rows and found
+   * no impact - Jeff Butler).
+   */
+  private static ThreadLocal factorySettings = new ThreadLocal();
+  
   /**
    * Utility class - no instances
    */
@@ -64,15 +85,16 @@
    *           Exception, iBATIS will throw a runtime exception in response and
    *           will end.
    */
-  public static Object createObjectThroughFactory(ResultObjectFactory factory,
-      String statementId, Class clazz) throws InstantiationException,
+  public static Object createObjectThroughFactory(Class clazz) throws InstantiationException,
       IllegalAccessException {
     
+    FactorySettings fs = getFactorySettings();
+    
     Object obj;
-    if (factory == null) {
+    if (fs.getResultObjectFactory() == null) {
       obj = createObjectInternally(clazz);
     } else {
-      obj = factory.createInstance(statementId, clazz);
+      obj = fs.getResultObjectFactory().createInstance(fs.getStatementId(), clazz);
       if (obj == null) {
         obj = createObjectInternally(clazz);
       }
@@ -104,5 +126,44 @@
     
     Object obj = Resources.instantiate(classToCreate);
     return obj;
+  }
+  
+  public static void setResultObjectFactory(ResultObjectFactory resultObjectFactory) {
+    getFactorySettings().setResultObjectFactory(resultObjectFactory);
+  }
+  
+  public static void setStatementId(String statementId) {
+    getFactorySettings().setStatementId(statementId);
+  }
+  
+  private static FactorySettings getFactorySettings() {
+    FactorySettings fs = (FactorySettings) factorySettings.get();
+    if (fs == null) {
+      fs = new FactorySettings();
+      factorySettings.set(fs);
+    }
+    
+    return fs;
+  }
+  
+  private static class FactorySettings {
+    private ResultObjectFactory resultObjectFactory;
+    private String statementId;
+    
+    public ResultObjectFactory getResultObjectFactory() {
+      return resultObjectFactory;
+    }
+    
+    public void setResultObjectFactory(ResultObjectFactory resultObjectFactory) {
+      this.resultObjectFactory = resultObjectFactory;
+    }
+    
+    public String getStatementId() {
+      return statementId;
+    }
+    
+    public void setStatementId(String statementId) {
+      this.statementId = statementId;
+    }
   }
 }