Author: gk
Date: Fri Oct 24 08:10:46 2025
New Revision: 1929318

Log:
Merged patch "Thread-safe record mapper speed-ups" from Max Philipp Wriedt, 
cft. Torque-dev mailing list entry
https://lists.apache.org/thread/225tjo3y27n0gdtrt2yj3ntr7z4lx4g5.

Added:
   
db/torque/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/recordmapper/base/mappingStrategyPath.vm
Modified:
   
db/torque/trunk/torque-runtime/src/main/java/org/apache/torque/om/mapper/MappingStrategy.java
   
db/torque/trunk/torque-runtime/src/main/java/org/apache/torque/om/mapper/RecordMapper.java
   
db/torque/trunk/torque-runtime/src/main/java/org/apache/torque/util/ResultsetSpliterator.java
   
db/torque/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/outlets/recordMapper.xml
   
db/torque/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/recordmapper/base/recordMapperBase.vm

Modified: 
db/torque/trunk/torque-runtime/src/main/java/org/apache/torque/om/mapper/MappingStrategy.java
==============================================================================
--- 
db/torque/trunk/torque-runtime/src/main/java/org/apache/torque/om/mapper/MappingStrategy.java
       Fri Oct 24 05:04:10 2025        (r1929317)
+++ 
db/torque/trunk/torque-runtime/src/main/java/org/apache/torque/om/mapper/MappingStrategy.java
       Fri Oct 24 08:10:46 2025        (r1929318)
@@ -28,78 +28,73 @@ import org.apache.commons.lang3.function
 
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.torque.TorqueException;
-
-/**
- * Mapping strategy used in processRow method of generated mappers.
- * 
- * @param <T>
- */
-public class MappingStrategy<T> {
-    
-    /**
-     * The {@link Pair#getLeft()} is to allow lazy sorting, {@link 
Pair#getRight()} contains the object to be mapped 
-     */
-    private final List<Pair<Integer, FailableBiConsumer<ResultSet, T, 
TorqueException>>> tasks;
-    
-    private boolean allSet;
-
-    public MappingStrategy()
-    {
-        this.tasks = new ArrayList<>();
-        this.allSet = false;
-    }
-
-    public void addColumn(int offset, FailableBiConsumer<ResultSet, T, 
TorqueException> setter)
-    {
-        this.tasks.add(Pair.of(offset, setter));
-    }
-
-    /**
-     * Last finishing steps before execute.
-     * 
-     * @param num_fields the total column size of the object
-     * @param sort <code>true</code> explicitely sort with {@link 
Pair#getLeft()} of the {@link #tasks}.
-     */
-    public void finish(int num_fields, boolean sort)
-    {
-        // The list should already be in the correct order because Criteria 
loops through the columns
-        // in the same order in which they are added to the SQL statement but 
just in case something weird
+
+/**
+ * Mapping strategy used in processRow method of generated mappers.
+ *
+ * @param <T>
+ */
+public class MappingStrategy<T> {
+
+    /**
+     * The {@link Pair#getLeft()} is to allow lazy sorting, {@link 
Pair#getRight()} contains the object to be mapped
+     */
+    private final List<Pair<Long, FailableBiConsumer<ResultSet, T, 
TorqueException>>> tasks;
+
+    public MappingStrategy() {
+        this.tasks = new ArrayList<>();
+    }
+
+    /**
+     * Add a column to be set at the given offset (column).
+     * @param offset the column offset inside a Resultset at which the value 
can be found.
+     * @param setter a method or lambda which actually sets the value.
+     */
+    public void addColumn(long offset, FailableBiConsumer<ResultSet, T, 
TorqueException> setter)
+    {
+        this.tasks.add(Pair.of(offset, setter));
+    }
+
+    /**
+     * Last finishing steps before this strategy can be executed.
+     *
+     * @param sort <code>true</code> explicitly sort with {@link 
Pair#getLeft()} of the {@link #tasks}.
+     */
+    public void finish(boolean sort)
+    {
+        // The list should already be in the correct order because Criteria 
loops through the columns
+        // in the same order in which they are added to the SQL statement but 
just in case something weird
         // is being done this gets us closer to the desired contract of 
ResultSet of looping over monotonically
         // increasing indices of columns only.
-        if (sort) {
-            this.tasks.sort(Comparator.comparing(Pair::getLeft));
-        }
-        this.allSet = this.tasks.size() == num_fields;
-    }
-
-    public boolean isEmpty()
-    {
-        return this.tasks.isEmpty();
-    }
-
-    public boolean isAllSet() {
-        return this.allSet;
-    }
-    
-    public void reset()
-    {
-        // to use this and to use only a single strategy we might need to 
Collections.sync(ArrayList).
+        if (sort) {
+            this.tasks.sort(Comparator.comparing(Pair::getLeft));
+        }
+    }
+
+    public boolean isEmpty()
+    {
+        return this.tasks.isEmpty();
+    }
+
+    public void reset()
+    {
+        // to use this and to use only a single strategy we might need to 
Collections.sync(ArrayList).
         this.tasks.clear();
     }
-
-    /**
-     * Iterates through the {@link #tasks} list and executes each task.
-     * 
-     * @param result Resultset
-     * @param instance target object
-     * 
-     */
-    public void execute(ResultSet result, T instance)
-    {
-        this.tasks.stream().forEach( strategy ->
-           {
-            try
-            {
+
+    /**
+     * Iterates through the {@link #tasks} list and executes each task.
+     *
+     * @param result Resultset
+     * @param instance target object
+     *
+     */
+    public void execute(ResultSet result, T instance)
+    {
+        this.tasks.forEach( strategy ->
+           {
+            try
+            {
                 strategy.getRight().accept( result, instance );
             } catch (TorqueException e)
             {

Modified: 
db/torque/trunk/torque-runtime/src/main/java/org/apache/torque/om/mapper/RecordMapper.java
==============================================================================
--- 
db/torque/trunk/torque-runtime/src/main/java/org/apache/torque/om/mapper/RecordMapper.java
  Fri Oct 24 05:04:10 2025        (r1929317)
+++ 
db/torque/trunk/torque-runtime/src/main/java/org/apache/torque/om/mapper/RecordMapper.java
  Fri Oct 24 08:10:46 2025        (r1929318)
@@ -62,4 +62,43 @@ public interface RecordMapper<T> extends
             int rowOffset,
             Criteria criteria)
                     throws TorqueException;
+
+    /**
+     * Constructs the object from the current row in the resultSet.
+     * Implementing methods can be sure that the resultSet contains a row,
+     * but they must only operate on the current row, i.e they must not call
+     * resultSet.next().
+     * This version may also receive a MappingStrategy object to speed up
+     * the processing. However, the default implementation disregards any
+     * passed strategy and simply forwards to processRow(ResultSet, int, 
Criteria).
+     *
+     * @param resultSet the resultSet to operate on, already pointing
+     *        to the correct row. Not null.
+     * @param rowOffset a possible offset in the columns to be considered
+     *        (if previous columns contain other objects), or 0 for no offset.
+     * @param criteria the Criteria which contains the query to process,
+     *        or null if not known or the query was not produced by a Criteria.
+     *        Can be used by the RecordMapper to determine the columns
+     *        contained in the result set.
+     * @param strategy the MappingStrategy which tells the RecordMapper which
+     *        offsets in the resultSet correspond to which fields of T.
+     *        Nay be null if not known.
+     *
+     * @return the mapped object, not null.
+     *
+     * @throws TorqueException when the mapping fails.
+     */
+    default T processRow(
+            ResultSet resultSet,
+            int rowOffset,
+            Criteria criteria,
+            MappingStrategy<T> strategy)
+                    throws TorqueException {
+        return this.processRow(resultSet, rowOffset, criteria);
+    }
+
+    default MappingStrategy<T> generateStrategy(long rowOffset, Criteria 
criteria)
+    {
+        return null;
+    }
 }

Modified: 
db/torque/trunk/torque-runtime/src/main/java/org/apache/torque/util/ResultsetSpliterator.java
==============================================================================
--- 
db/torque/trunk/torque-runtime/src/main/java/org/apache/torque/util/ResultsetSpliterator.java
       Fri Oct 24 05:04:10 2025        (r1929317)
+++ 
db/torque/trunk/torque-runtime/src/main/java/org/apache/torque/util/ResultsetSpliterator.java
       Fri Oct 24 08:10:46 2025        (r1929318)
@@ -28,48 +28,53 @@ import java.util.function.Consumer;
 
 import org.apache.torque.Database;
 import org.apache.torque.Torque;
-import org.apache.torque.TorqueException;
-import org.apache.torque.TorqueRuntimeException;
-import org.apache.torque.criteria.Criteria;
-import org.apache.torque.om.mapper.RecordMapper;
-
-/**
+import org.apache.torque.TorqueException;
+import org.apache.torque.TorqueRuntimeException;
+import org.apache.torque.criteria.Criteria;
+import org.apache.torque.om.mapper.MappingStrategy;
+import org.apache.torque.om.mapper.RecordMapper;
+
+/**
  * Stream support: Encapsulate iteration over a JDBC ResultSet
  *
  * @author <a href="mailto:[email protected]";>Thomas Vandahl</a>
  */
-public class ResultsetSpliterator<T> extends AbstractSpliterator<T> implements 
Runnable
-{
-    private final RecordMapper<T> recordMapper;
-    private final Criteria criteria;
-    private final Statement statement;
-    private final ResultSet resultSet;
+public class ResultsetSpliterator<T> extends AbstractSpliterator<T> implements 
Runnable
+{
+    private final RecordMapper<T> recordMapper;
+    private final MappingStrategy<T> mappingStrategy;
+    private final Criteria criteria;
+    private final Statement statement;
+    private final ResultSet resultSet;
 
     private long offset;
     private long limit;
-    private long rowNumber;
-
-    /**
-     * Constructor
-     *
-     * @param recordMapper a RecordMapper to map ResultSet rows to entities of 
type T
-     * @param criteria     a Criteria
-     * @param statement    the statement that created the ResultSet
-     * @param resultSet    the JDBC result set
-     * @throws TorqueException backend database exception
-     */
-    public ResultsetSpliterator(RecordMapper<T> recordMapper, Criteria 
criteria,
-            Statement statement, ResultSet resultSet) throws TorqueException
-    {
-        super(Long.MAX_VALUE, Spliterator.ORDERED);
-
+    private long rowNumber;
+
+    /**
+     * Constructor with an explicit MappingStrategy.
+     *
+     * @param recordMapper a RecordMapper to map ResultSet rows to entities of 
type T
+     * @param criteria     a Criteria
+     * @param statement    the statement that created the ResultSet
+     * @param resultSet    the JDBC result set
+     * @param mappingStrategy     a MappingStrategy to use
+     * @throws TorqueException backend database exception
+     */
+    public ResultsetSpliterator(RecordMapper<T> recordMapper, Criteria 
criteria,
+            Statement statement, ResultSet resultSet, MappingStrategy<T> 
mappingStrategy) throws TorqueException
+    {
+        super(Long.MAX_VALUE, Spliterator.ORDERED);
+
         this.recordMapper = recordMapper;
-        this.criteria = criteria;
-        this.statement = statement;
-        this.resultSet = resultSet;
-        this.offset = 0; //database takes care of offset
-        this.limit = -1; //database takes care of limit
-        this.rowNumber = 0;
+        this.criteria = criteria;
+        this.statement = statement;
+        this.resultSet = resultSet;
+        MappingStrategy<T> myMappingStrategy = mappingStrategy;
+
+        this.offset = 0; //database takes care of offset
+        this.limit = -1; //database takes care of limit
+        this.rowNumber = 0;
 
         // Set offset and limit
         if (criteria != null)
@@ -88,13 +93,34 @@ public class ResultsetSpliterator<T> ext
                 }
                 else if (criteria.getLimit() != -1)
                 {
-                    limit = offset + criteria.getLimit();
-                }
-            }
-        }
-    }
-
-    /* (non-Javadoc)
+                    limit = offset + criteria.getLimit();
+                }
+            }
+
+            // generate a strategy, if not already provided
+            if (mappingStrategy == null) {
+                myMappingStrategy = recordMapper.generateStrategy(offset, 
criteria);
+            }
+        }
+        this.mappingStrategy = myMappingStrategy;
+    }
+
+    /**
+     * Constructor
+     *
+     * @param recordMapper a RecordMapper to map ResultSet rows to entities of 
type T
+     * @param criteria     a Criteria
+     * @param statement    the statement that created the ResultSet
+     * @param resultSet    the JDBC result set
+     * @throws TorqueException backend database exception
+     */
+    public ResultsetSpliterator(RecordMapper<T> recordMapper, Criteria 
criteria,
+                                Statement statement, ResultSet resultSet) 
throws TorqueException
+    {
+        this(recordMapper, criteria, statement, resultSet, null);
+    }
+
+    /* (non-Javadoc)
      * @see java.util.Spliterator#tryAdvance(java.util.function.Consumer)
      *
      * Advance ResultSet and map row to entity &lt;T&gt;
@@ -114,13 +140,13 @@ public class ResultsetSpliterator<T> ext
                 if (limit >= 0 && rowNumber >= limit)
                 {
                     return false;
-                }
-
-                rowNumber++;
-                T result = recordMapper.processRow(resultSet, 0, criteria);
-                action.accept(result);
-                return true;
-            }
+                }
+
+                rowNumber++;
+                T result = recordMapper.processRow(resultSet, 0, criteria, 
mappingStrategy);
+                action.accept(result);
+                return true;
+            }
         }
         catch (SQLException e)
         {

Modified: 
db/torque/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/outlets/recordMapper.xml
==============================================================================
--- 
db/torque/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/outlets/recordMapper.xml
 Fri Oct 24 05:04:10 2025        (r1929317)
+++ 
db/torque/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/outlets/recordMapper.xml
 Fri Oct 24 08:10:46 2025        (r1929318)
@@ -48,6 +48,10 @@
           element="column"
           outlet="torque.om.recordmapper.base.dbObjectFieldGetter"/>
     </mergepoint>
+    <mergepoint name="mappingStrategyPath">
+        <action xsi:type="applyAction"
+                outlet="torque.om.recordmapper.base.mappingStrategyPath"/>
+    </mergepoint>
   </outlet>
 
   <outlet name="torque.om.recordmapper.base.dbObjectFieldGetter"
@@ -59,4 +63,18 @@
       xsi:type="velocityOutlet"
       path="recordmapper/base/createDbObjectInstanceFromInheritance.vm">
   </outlet>
+
+  <outlet name="torque.om.recordmapper.base.mappingStrategyPath"
+      xsi:type="velocityOutlet"
+      path="recordmapper/base/mappingStrategyPath.vm">
+      <mergepoint name="createDbObjectInstance">
+          <action xsi:type="applyAction"
+                  outlet="torque.om.createDbObjectInstance"/>
+      </mergepoint>
+      <mergepoint name="createDbObjectInstanceFromInheritance">
+          <action xsi:type="traverseAllAction"
+                  element="inheritance-column"
+                  
outlet="torque.om.recordmapper.basecreateDbObjectInstanceFromInheritance"/>
+      </mergepoint>
+  </outlet>
 </outlets>
\ No newline at end of file

Added: 
db/torque/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/recordmapper/base/mappingStrategyPath.vm
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ 
db/torque/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/recordmapper/base/mappingStrategyPath.vm
       Fri Oct 24 08:10:46 2025        (r1929318)
@@ -0,0 +1,133 @@
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  The ASF licenses this file
+## to you 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.
+##
+######
+##
+## version $Id: mappingStrategyPath.vm TIMESTAMP mwriedt $
+##
+## Creates the MappingStrategy flow for a RecordMapper.
+##
+## This template expects the current source element to be a "table" element
+## from the torque schema.
+## The schema needs to be processed by the OMTransformer.
+## The attributes of the current source element must be set
+## as velocity variables.
+##
+
+    @Override
+    public MappingStrategy<$dbObjectClassName> generateStrategy(long 
rowOffset, Criteria criteria) {
+        if (criteria == null || criteria.isComposite())
+        {
+            return null;
+        }
+        List<Column> selectColumns = criteria.getSelectColumns();
+        List<Column> columnsWithoutOffset = 
selectColumns.stream().skip(rowOffset).toList();
+        ## The selectColumns should not be empty here if we are called by the 
usual ResultsetSpliterator.
+        if (columnsWithoutOffset.isEmpty())
+        {
+            return null;
+        }
+        MappingStrategy<$dbObjectClassName> strategy = new MappingStrategy<>();
+
+        Set<String> columnsMapped = new HashSet<>();
+        long physicalColumnIndex = rowOffset + 1;
+        for (Column column : columnsWithoutOffset)
+        {
+            #set ( $else = "" )
+            #foreach ($columnElement in $torqueGen.getChildren("column"))
+                #set ( $setter = $columnElement.getAttribute("setter") )
+                #set ( $getter = $columnElement.getAttribute("getter") )
+                #set ( $peerColumnName = 
$columnElement.getAttribute("peerColumnName") )
+                ${else}if 
(!columnsMapped.contains(${peerColumnName}_EXPRESSION ) && 
${peerColumnName}_EXPRESSION.equals(
+                    column.getSqlExpression()))
+            {
+                int currentIndex = Math.toIntExact(physicalColumnIndex);
+                strategy.addColumn(physicalColumnIndex,
+                        (res, inst) -> inst.${setter}(${getter}(res, 
currentIndex)));
+                columnsMapped.add( ${peerColumnName}_EXPRESSION );
+            }
+                #set ( $else = "else " )
+            #end
+            physicalColumnIndex++;
+        }
+        if (columnsMapped.isEmpty())
+        {
+            return null;
+        }
+        return strategy;
+    }
+
+    /**
+    * Constructs the object from the current row in the resultSet.
+    * Implementing methods can be sure that the resultSet contains a row,
+    * but they must only operate on the current row, i.e they must not call
+    * resultSet.next().
+    * This version may also receive a MappingStrategy object to speed up
+    * the processing. However, the default implementation disregards any
+    * passed strategy and simply forwards to processRow(ResultSet, int, 
Criteria). //FIXME: Fix doclink!
+    *
+    * @param resultSet the resultSet to operate on, already pointing
+    *        to the correct row. Not null.
+    * @param offset a possible offset in the columns to be considered
+    *        (if previous columns contain other objects), or 0 for no offset.
+    * @param criteria the Criteria which contains the query to process,
+    *        or null if not known or the query was not produced by a Criteria.
+    *        Can be used by the RecordMapper to determine the columns
+    *        contained in the result set.
+    * @param strategy the MappingStrategy which tells the RecordMapper which
+    *        offsets in the resultSet correspond to which fields of T.
+    *        Nay be null if not known.
+    *
+    * @return the mapped object, not null.
+    *
+    * @throws TorqueException when the mapping fails.
+    */
+    @Override
+    public ${dbObjectClassName} processRow(
+        ResultSet resultSet,
+        int offset,
+        Criteria criteria,
+        MappingStrategy<${dbObjectClassName}> strategy)
+            throws TorqueException {
+        if (strategy != null)
+        {
+#set ( $inheritanceBaseColumnElement = 
$torqueGen.getChild("inheritance-column") )
+#if ($inheritanceBaseColumnElement)
+    $torqueGen.mergepoint("createDbObjectInstanceFromInheritance")
+#else
+    $torqueGen.mergepoint("createDbObjectInstance")
+#end
+
+#if ($torqueGen.booleanOption("torque.om.trackLoading"))
+            try
+            {
+            ${field}.setLoading(true);
+#end
+            strategy.execute(resultSet, ${field});
+            ${field}.setNew(false);
+            ${field}.setModified(false);
+#if ($torqueGen.booleanOption("torque.om.trackLoading"))
+            }
+            finally
+            {
+                ${field}.setLoading(false);
+            }
+#end
+            return ${field};
+        }
+        return this.processRow(resultSet, offset, criteria);
+    }
\ No newline at end of file

Modified: 
db/torque/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/recordmapper/base/recordMapperBase.vm
==============================================================================
--- 
db/torque/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/recordmapper/base/recordMapperBase.vm
  Fri Oct 24 05:04:10 2025        (r1929317)
+++ 
db/torque/trunk/torque-templates/src/main/resources/org/apache/torque/templates/om/templates/recordmapper/base/recordMapperBase.vm
  Fri Oct 24 08:10:46 2025        (r1929318)
@@ -16,42 +16,44 @@
 ## under the License.
 ##
 ######
-##
-## version $Id$
-##
-## Creates the base peer's mapper class. 
-## 
-## This template expects the current source element to be a "table" element 
-## from the torque schema.
-## The schema needs to be processed by the OMTransformer.
-## The attributes of the current source element must be set
-## as velocity variables.  
-##
-package ${baseRecordMapperPackage};
-
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+##
+## version $Id$
+##
+## Creates the base peer's mapper class.
+##
+## This template expects the current source element to be a "table" element
+## from the torque schema.
+## The schema needs to be processed by the OMTransformer.
+## The attributes of the current source element must be set
+## as velocity variables.
+##
+package ${baseRecordMapperPackage};
+
+import java.io.Serial;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.torque.Column;
 import org.apache.torque.TorqueException;
 import org.apache.torque.criteria.Criteria;
 import org.apache.torque.om.mapper.RecordMapper;
-import org.apache.torque.om.mapper.MappingStrategy;
-
-#foreach ($columnElement in 
$torqueGen.getSourceElement().getChildren("column"))
-  #set ($colEnumPackage = $columnElement.getAttribute("enumPackage"))
-  #set ($colEnumClassName = $columnElement.getAttribute("enumClassName"))
-  #if ($columnElement.getAttribute("isEnum") == "true" && $colEnumPackage != 
$baseRecordMapperPackage) 
-import ${colEnumPackage}.${colEnumClassName};
-  #end
-#end
-#if (${baseRecordMapperPackage} != $dbObjectPackage)
-import ${dbObjectPackage}.${dbObjectClassName};
+import org.apache.torque.om.mapper.MappingStrategy;
+
+#foreach ($columnElement in 
$torqueGen.getSourceElement().getChildren("column"))
+    #set ($colEnumPackage = $columnElement.getAttribute("enumPackage"))
+    #set ($colEnumClassName = $columnElement.getAttribute("enumClassName"))
+    #if ($columnElement.getAttribute("isEnum") == "true" && $colEnumPackage != 
$baseRecordMapperPackage)
+    import ${colEnumPackage}.${colEnumClassName};
+    #end
+#end
+#if (${baseRecordMapperPackage} != $dbObjectPackage)
+import ${dbObjectPackage}.${dbObjectClassName};
 #end
 #if (${baseRecordMapperPackage} != $peerPackage)
 import ${peerPackage}.${peerClassName};
@@ -60,179 +62,126 @@ import ${peerPackage}.${peerClassName};
 import ${basePeerPackage}.${basePeerClassName};
 #end
 
-#set ( $inheritanceBaseColumnElements = 
$torqueGen.getChildren("inheritance-column"))
-## there should at most be one inheritance-column in each table
-#foreach ($inheritanceBaseColumnElement in $inheritanceBaseColumnElements)
-  #set ( $columnElement = $inheritanceBaseColumnElement.getChild("column") )
-  #set ( $inheritanceElements = $columnElement.getChildren("inheritance"))
-  #if ($inheritanceElements.size() > 0)
-    #if (${baseRecordMapperPackage} != $dbObjectPackage)
-      #foreach ($inheritanceElement in $inheritanceElements)
-        #set ( $inheritanceClassName = 
$inheritanceElement.getAttribute("className") )
-import ${dbObjectPackage}.${inheritanceClassName};
-      #end
-    #end
-  #end
-#end
-/**
- * Maps ResultSet rows into ${dbObjectClassName} objects.
- *
-#if ($torqueGen.booleanOption("torque.om.addTimeStamp"))
- * The skeleton for this class was autogenerated by Torque on:
- *
- * [${torqueGen.now()}]
- *
-#end
- */
-@SuppressWarnings("unused")
-public class ${baseRecordMapperClassName} implements 
RecordMapper<${dbObjectClassName}>
-{
-#if ($torqueGen.booleanOption("torque.om.addTimeStamp"))
-    /** Serial version */
-    private static final long serialVersionUID = ${torqueGen.now().Time}L;
-
-#else
-    /** Serial version */
-    private static final long serialVersionUID = 1L;
-
-#end
-    /** The class log. */
-    private static Log log
-            = LogFactory.getLog(${baseRecordMapperClassName}.class);
-            
-    ## TORQUE-364: Cached SQL expressions to speed up looking for columns 
selected by a given Criteria
-#foreach ($columnElement in $torqueGen.getChildren("column"))
-    #set ( $peerColumnName = $columnElement.getAttribute("peerColumnName") )
-    private static final String ${peerColumnName}_EXPRESSION = 
${basePeerClassName}.${peerColumnName}.getSqlExpression();
-#end
-
-    ## TORQUE-364: Removed strategy instance variable as this be cached per 
RecordMapper (Thread safety/Multi query safety?)
-    
-    ## TORQUE-364: init a new Strategy implementation
-    ## TORQUE-372: init is not Thread save cause Array 
ConcurrentModificationException
-    public MappingStrategy<${dbObjectClassName}> initStrategy()
-    {
-        #if("${useMappingStrategy}" == "true")
-        return new MappingStrategy<${dbObjectClassName}>();
-        #else
-        // no MappingStrategy since useMappingStrategy not set
-        return null;
-        #end
-    }
-#if("${simpleMapping}" == "true") #set( $useSimpleMapping=1 ) #end
-
-    /**
-     * Constructs the object from the current row in the resultSet.
-     *
-     * @param resultSet the resultSet to operate on, already pointing
-     *        to the correct row. Not null.
-     * @param offset a possible offset in the columns to be considered
-     *        (if previous columns contain other objects),
-     *        or 0 for no offset.
-     * @param criteria The criteria which created the result set.
-     *        If set, the attributes to set in the data object
-     *        are determined from the select columns in the criteria;
-     *        if no matching column can be found, null is returned.
-     *        If not set, all of the table's columns are read from the
-     *        result set in the order defined in the table definition.
-     *
-     * @return the mapped object, not null.
-     *
-     * @throws TorqueException when reading fields from the RecordSet fails
-     *         or if a Criteria is passed which contains select columns other
-     *         than the columns in the ${name} table.
-     */
-    public $dbObjectClassName processRow(
-                ResultSet resultSet,
-                int offset,
-                Criteria criteria)
-            throws TorqueException
-    {
-#set ( $inheritanceBaseColumnElement = 
$torqueGen.getChild("inheritance-column") )
-#if ($inheritanceBaseColumnElement)
-$torqueGen.mergepoint("createDbObjectInstanceFromInheritance")
-#else
-$torqueGen.mergepoint("createDbObjectInstance")
-#end
-#if ($torqueGen.booleanOption("torque.om.trackLoading"))
-        try 
-        {
-            ${field}.setLoading(true);
-#end
-        ## TORQUE-364 - simple mapping if we got the exact column size we 
assume the full table is used in criteria - skipping the mapping of every column
-        if (criteria == null #if ($useSimpleMapping) || 
(criteria.getJoins().isEmpty() && criteria.getSelectColumns().size() - offset 
==  ${basePeerClassName}.numColumns) #end)
-        {
-#set ( $n = 1 )
-#foreach ($columnElement in $torqueGen.getChildren("column"))
-  #set ( $setter = $columnElement.getAttribute("setter") )
-  #set ( $getter = $columnElement.getAttribute("getter") )
-                ${field}.${setter}(
-                        ${getter}(resultSet, offset + $n));
-  #set ( $n = $n + 1 )
-#end
-            }
-            else
-            {
-                ## TORQUE-372: thread save
-                MappingStrategy<${dbObjectClassName}> strategyLoc= 
initStrategy(); 
-
-                // try to get columns to be mapped
-                // from criteria's select columns
-                int totalOffset = offset + 1;
-                List<Column> selectColumns = criteria.getSelectColumns();
-                List<Column> columnsWithoutOffset = selectColumns.subList(
-                        offset, 
-                        selectColumns.size());
-                Set<String> columnsMapped = new HashSet<String>();
-                for (Column column : columnsWithoutOffset)
-                {
-                    final int nextOffset = totalOffset; ## leaking assignment
-#set ( $else = "" )
-#foreach ($columnElement in $torqueGen.getChildren("column"))
-  #set ( $setter = $columnElement.getAttribute("setter") )
-  #set ( $getter = $columnElement.getAttribute("getter") )
-  #set ( $peerColumnName = $columnElement.getAttribute("peerColumnName") )
-                    ${else}
-                    if (!columnsMapped.contains(${peerColumnName}_EXPRESSION ) 
&& ${peerColumnName}_EXPRESSION.equals(
-                            column.getSqlExpression()))
-                    {
-                        if (strategyLoc!=null) 
-                        {
-                            strategyLoc.addColumn(nextOffset, 
-                                (res, inst) -> inst.${setter}( ${getter}(res, 
nextOffset)));
-                        } else
-                        {
-                            ${field}.${setter}( ${getter}(resultSet, 
totalOffset));
-                        }
-                        columnsMapped.add( ${peerColumnName}_EXPRESSION );
-                    }
-  #set ( $else = "else ")
-#end
-                    totalOffset++;
-                }
-                if (columnsMapped.isEmpty())
-                {
-                    log.debug("no columns to map found in criteria, "
-                        + "returning null");
-                    return null;
-                }
-                if (strategyLoc!=null)
-                {
-                  strategyLoc.finish($torqueGen.getChildren("column").size(), 
#if("${mappingStrategySort}"=="true")true#{else}false#end);
-                  strategyLoc.execute(resultSet, $field);
-                }
-            }
-            ${field}.setNew(false);
-            ${field}.setModified(false);
-#if ($torqueGen.booleanOption("torque.om.trackLoading"))
-        }
-        finally
-        {
-            ${field}.setLoading(false);
-        }
-#end
-        return ${field};
-    }
-
-$torqueGen.mergepoint("dbObjectFieldGetters")
-}
+#set ( $inheritanceBaseColumnElements = 
$torqueGen.getChildren("inheritance-column"))
+## there should at most be one inheritance-column in each table
+#foreach ($inheritanceBaseColumnElement in $inheritanceBaseColumnElements)
+    #set ( $columnElement = $inheritanceBaseColumnElement.getChild("column") )
+    #set ( $inheritanceElements = $columnElement.getChildren("inheritance"))
+    #if ($inheritanceElements.size() > 0)
+        #if (${baseRecordMapperPackage} != $dbObjectPackage)
+            #foreach ($inheritanceElement in $inheritanceElements)
+                #set ( $inheritanceClassName = 
$inheritanceElement.getAttribute("className") )
+            import ${dbObjectPackage}.${inheritanceClassName};
+            #end
+        #end
+    #end
+#end
+/**
+ * Maps ResultSet rows into ${dbObjectClassName} objects.
+ *
+    #if ($torqueGen.booleanOption("torque.om.addTimeStamp"))
+     * The skeleton for this class was autogenerated by Torque on:
+     *
+     * [${torqueGen.now()}]
+     *
+    #end
+ */
+@SuppressWarnings("unused")
+public class ${baseRecordMapperClassName} implements 
RecordMapper<${dbObjectClassName}>
+{
+    /** Serial version */
+@Serial
+    #if ($torqueGen.booleanOption("torque.om.addTimeStamp"))
+    private static final long serialVersionUID = ${torqueGen.now().Time}L;
+
+    #else
+        private static final long serialVersionUID = 1L;
+
+    #end
+    /** The class log. */
+    private static final Log log
+            = LogFactory.getLog(${baseRecordMapperClassName}.class);
+
+    ## TORQUE-364: Cached SQL expressions to speed up looking for columns 
selected by a given Criteria
+    #foreach ($columnElement in $torqueGen.getChildren("column"))
+        #set ( $peerColumnName = $columnElement.getAttribute("peerColumnName") 
)
+        private static final String ${peerColumnName}_EXPRESSION = 
${basePeerClassName}.${peerColumnName}.getSqlExpression();
+    #end
+
+    /**
+     * Constructs the object from the current row in the resultSet.
+     *
+     * @param resultSet the resultSet to operate on, already pointing
+     * to the correct row. Not null.
+     * @param offset a possible offset in the columns to be considered
+     * (if previous columns contain other objects),
+     * or 0 for no offset.
+     * @param criteria The criteria which created the result set.
+     * If set, the attributes to set in the data object
+     * are determined from the select columns in the criteria;
+     * if no matching column can be found, null is returned.
+     * If not set, all of the table's columns are read from the
+     * result set in the order defined in the table definition.
+     *
+     * @return the mapped object, not null.
+     *
+     * @throws TorqueException when reading fields from the RecordSet fails
+     * or if a Criteria is passed which contains select columns other
+     * than the columns in the ${name} table.
+     */
+    public $dbObjectClassName processRow(
+        ResultSet resultSet,
+    int offset,
+    Criteria criteria)
+            throws TorqueException
+    {
+        #set ( $inheritanceBaseColumnElement = 
$torqueGen.getChild("inheritance-column") )
+        #if ($inheritanceBaseColumnElement)
+            $torqueGen.mergepoint("createDbObjectInstanceFromInheritance")
+        #else
+            $torqueGen.mergepoint("createDbObjectInstance")
+        #end
+        #if ($torqueGen.booleanOption("torque.om.trackLoading"))
+        try
+        {
+            ${field}.setLoading(true);
+        #end
+        if (criteria == null)
+        {
+            #set ( $n = 1 )
+            #foreach ($columnElement in $torqueGen.getChildren("column"))
+                #set ( $setter = $columnElement.getAttribute("setter") )
+                #set ( $getter = $columnElement.getAttribute("getter") )
+                ${field}.${setter}(
+                ${getter}(resultSet, offset + $n));
+                #set ( $n = $n + 1 )
+            #end
+        }
+        else
+        {
+            ## This is the slow path, but we can reuse the strategy generation 
logic
+            ## to avoid duplicating the mapping code.
+            MappingStrategy<${dbObjectClassName}> strategy = 
generateStrategy(offset, criteria);
+            if (strategy == null)
+            {
+                log.debug("Could not generate a mapping strategy for the given 
criteria, "
+                        + "returning null");
+                return null;
+            }
+            strategy.execute(resultSet, ${field});
+        }
+        ${field}.setNew(false);
+        ${field}.setModified(false);
+        #if ($torqueGen.booleanOption("torque.om.trackLoading"))
+        }
+        finally
+        {
+            ${field}.setLoading(false);
+        }
+        #end
+        return ${field};
+    }
+
+    $torqueGen.mergepoint("mappingStrategyPath")
+    $torqueGen.mergepoint("dbObjectFieldGetters")
+}
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to