You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user-java@ibatis.apache.org by Poitras Christian <Ch...@ircm.qc.ca> on 2006/03/30 18:36:15 UTC

Re: Nested iterate tags

I've in front of this problem myself.
It seems that in a future version of iBatis, this bug will be corrected
by adding a "var" attribute in iterate tag.
 
If you wan't a patch to apply now, here's how I modified the code from
iBatis.
(you most likely downloaded the source code with the binary)
 
I can send a patch to someone who ask (in a .jar file replacing
ibatis-sqlmap-2.jar), but I would prefer that someone makes a real
modification to the framework. I have an idea of how things should be
changed to support nested iterate in a proper way.
 
To use my patch, do the following.
<iterate property="list">
    table.someFiled = #list[].value#
    <iterate property="list[].list">
        table.narrowField = #list[].list[].value#
    </iterate>
</iterate>
 
 
Please note that this modification was made on the iBatis 2.1.7.
A bug still remains in my modifcations. I can make a new patch if anyone
asks. This bug will make iBatis crash in this case.
<iterate property="list">
    <iterate property="list[].list">
        <!-- suppose here you always want the value of element 4 in
first list>
        table.field = #list[4].list[].value#
    </iterate>
</iterate>
 
 
 
// Mofications made to 3 files. Modifcations begin with comment "//
Added code" and ends with "// End of added code". Some code is replaced
to surrunded by "// Replaced code" and "// End of replaced code"
// classes modified :
com.ibatis.sqlmap.engine.mapping.sql.dynamic.DynamicSQL,
com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.IterateTagHandler,
com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.ConditionnalTagHan
dler
 
 
In com.ibatis.sqlmap.engine.mapping.sql.dynamic.DynamicSQL
 
  protected void iteratePropertyReplace(StringBuffer bodyContent,
IterateContext iterate) {
    if(iterate!=null) {
      String find = iterate.getProperty() + "[]";
      // Added code.
      find = find.replaceAll("\\[\\d+\\]", "[]");
      // End of added code.
      String replace = iterate.getProperty() + "[" + iterate.getIndex()
+ "]";
      replace(bodyContent, find, replace);
    }
  }
  private void processBodyChildren(RequestScope request, SqlTagContext
ctx, Object parameterObject, Iterator localChildren, PrintWriter out) {
    while (localChildren.hasNext()) {
      SqlChild child = (SqlChild) localChildren.next();
      if (child instanceof SqlText) {
        SqlText sqlText = (SqlText) child;
        String sqlStatement = sqlText.getText();
        if (sqlText.isWhiteSpace()) {
          out.print(sqlStatement);
        } else if (!sqlText.isPostParseRequired()) {
 
          // BODY OUT
          out.print(sqlStatement);
 
          ParameterMapping[] mappings = sqlText.getParameterMappings();
          if (mappings != null) {
            for (int i = 0, n = mappings.length; i < n; i++) {
              ctx.addParameterMapping(mappings[i]);
            }
          }
        } else {
 
          IterateContext itCtx = ctx.peekIterateContext();
 
          if(null != itCtx && itCtx.isAllowNext()){
            itCtx.next();
            itCtx.setAllowNext(false);
            if(!itCtx.hasNext()) {
              itCtx.setFinal(true);
            }
          }
 
          if(itCtx!=null) {
            StringBuffer sqlStatementBuffer = new
StringBuffer(sqlStatement);
            iteratePropertyReplace(sqlStatementBuffer, itCtx);
            sqlStatement = sqlStatementBuffer.toString();
          }
 
          sqlText =
PARAM_PARSER.parseInlineParameterMap(delegate.getTypeHandlerFactory(),
sqlStatement);
 
          ParameterMapping[] mappings = sqlText.getParameterMappings();
          out.print(sqlText.getText());
          if (mappings != null) {
             for (int i = 0, n = mappings.length; i < n; i++) {
               ctx.addParameterMapping(mappings[i]);
             }
          }
        }
      } else if (child instanceof SqlTag) {
        SqlTag tag = (SqlTag) child;
        SqlTagHandler handler = tag.getHandler();
        int response = SqlTagHandler.INCLUDE_BODY;
        do {
          StringWriter sw = new StringWriter();
          PrintWriter pw = new PrintWriter(sw);
          
          response = handler.doStartFragment(ctx, tag, parameterObject);
          if (response != SqlTagHandler.SKIP_BODY) {
 
            processBodyChildren(request, ctx, parameterObject,
tag.getChildren(), pw);
            pw.flush();
            pw.close();
            StringBuffer body = sw.getBuffer();
            response = handler.doEndFragment(ctx, tag, parameterObject,
body);
            handler.doPrepend(ctx, tag, parameterObject, body);
            
            if (response != SqlTagHandler.SKIP_BODY) {
              if (body.length() > 0) {
                out.print(body.toString());
              }
            }
 
          }
        } while (response == SqlTagHandler.REPEAT_BODY);
 
        ctx.popRemoveFirstPrependMarker(tag);
 
        if(ctx.peekIterateContext()!= null &&
ctx.peekIterateContext().getTag() == tag) {
            // Added code.
            ctx.setAttribute(ctx.peekIterateContext().getTag(), null);
            // End of added code.
          ctx.popIterateContext();
        }
 
      }
    }
  }
 
 
 

In
com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.IterateTagHandler
 
  public int doStartFragment(SqlTagContext ctx, SqlTag tag, Object
parameterObject) {
    IterateContext iterate = (IterateContext) ctx.getAttribute(tag);
    if (iterate == null) {
      
      ctx.pushRemoveFirstPrependMarker(tag);
      
      Object collection;
      String prop = tag.getPropertyAttr();
      if (prop != null) {
          // Added code.
          {
              // Increase index if the first tag is another iterate.
              IterateContext itCtx = ctx.peekIterateContext();
              if(null != itCtx && itCtx.isAllowNext()){
                  itCtx.next();
                  itCtx.setAllowNext(false);
                  if(!itCtx.hasNext()) {
                      itCtx.setFinal(true);
                  }
              }
          }
          SqlTag parentTag = tag.getParent();
          int listIndex = prop.lastIndexOf('[');
          while (listIndex > -1) {
              if (Character.isDigit(prop.charAt(listIndex + 1))) {
                  // Skip to next list.
                  if (listIndex > 0) {
                      listIndex = prop.lastIndexOf('[', listIndex - 1);
                  }
                  else {
                      listIndex = -1;
                  }
              }
              else {
                  // Add iteration number to property.
                  Object parentContext = ctx.getAttribute(parentTag);
                  while (!(parentContext instanceof IterateContext)) {
                      parentTag = parentTag.getParent();
                      parentContext = ctx.getAttribute(parentTag);
                  }
                  IterateContext parentIterateContext = (IterateContext)
parentContext;
                  prop = prop.substring(0, listIndex + 1) +
parentIterateContext.getIndex() + prop.substring(listIndex + 1);
                  // Skip to next list.
                  if (listIndex > 0) {
                      listIndex = prop.lastIndexOf('[', listIndex - 1);
                  }
                  else {
                      listIndex = -1;
                  }
                  parentTag = parentTag.getParent();
              }
          }
          // End of added code.
        collection = PROBE.getObject(parameterObject, prop);
      } else {
        collection = parameterObject;
      }
      iterate = new IterateContext(collection,tag);
      
      iterate.setProperty( null == prop ? "" : prop );
      
      ctx.setAttribute(tag, iterate);
      ctx.pushIterateContext(iterate);
    }
    if (iterate != null && iterate.hasNext()) {
      return INCLUDE_BODY;
    } else {
      return SKIP_BODY;
    }
  }
 
 
 

In
com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.ConditionnalTagHan
dler
  protected long compare(SqlTagContext ctx, SqlTag tag, Object
parameterObject) {
    String propertyName = tag.getPropertyAttr();
    String comparePropertyName = tag.getComparePropertyAttr();
    String compareValue = tag.getCompareValueAttr();
 
    String prop = tag.getPropertyAttr();
    Object value1;
    Class type;
    IterateContext itCtx = ctx.peekIterateContext();
 
    if (prop != null) {
 
      if(null != itCtx && itCtx.isAllowNext()){
        itCtx.next();
        itCtx.setAllowNext(false);
        if(!itCtx.hasNext()) {
          itCtx.setFinal(true);
        }
      }
 
      if(prop.indexOf(START_INDEX) > -1) {
          // Replaced code.
          propertyName = new StringBuffer(propertyName).insert(
 
propertyName.lastIndexOf(END_INDEX),itCtx.getIndex()).toString();
          // End of replaced code.
          // Added code.
          SqlTag parentTag = itCtx.getTag().getParent();
          int listIndex = propertyName.lastIndexOf('[');
          while (listIndex > -1) {
              if (Character.isDigit(propertyName.charAt(listIndex + 1)))
{
                  // Skip to next list.
                  if (listIndex > 0) {
                      listIndex = propertyName.lastIndexOf('[',
listIndex - 1);
                  }
                  else {
                      listIndex = -1;
                  }
              }
              else {
                  // Add iteration number to property.
                  Object parentContext = ctx.getAttribute(parentTag);
                  while (!(parentContext instanceof IterateContext)) {
                      parentTag = parentTag.getParent();
                      parentContext = ctx.getAttribute(parentTag);
                  }
                  IterateContext parentIterateContext = (IterateContext)
parentContext;
                  propertyName = propertyName.substring(0, listIndex +
1) + parentIterateContext.getIndex() + propertyName.substring(listIndex
+ 1);
                  // Skip to next list.
                  if (listIndex > 0) {
                      listIndex = propertyName.lastIndexOf('[',
listIndex - 1);
                  }
                  else {
                      listIndex = -1;
                  }
                  parentTag = parentTag.getParent();
              }
          }
          // End of added code.
      }
 
      value1 = PROBE.getObject(parameterObject, propertyName);
      type = PROBE.getPropertyTypeForGetter(parameterObject,
propertyName);
    } else {
      value1 = parameterObject;
      if (value1 != null) {
        type = parameterObject.getClass();
      } else {
        type = Object.class;
      }
    }
    if (comparePropertyName != null) {
      Object value2 = PROBE.getObject(parameterObject,
comparePropertyName);
      return compareValues(type, value1, value2);
    } else if (compareValue != null) {
      return compareValues(type, value1, compareValue);
    } else {
      throw new NestedRuntimeException("Error comparing in conditional
fragment.  Uknown 'compare to' values.");
    }
  }


Re: Nested iterate tags

Posted by Brandon Goodin <br...@gmail.com>.
Is there a JIRA issue associated with this? I'll be happy to look at
it over the weekend.

On 3/30/06, Poitras Christian <Ch...@ircm.qc.ca> wrote:
> I've in front of this problem myself.
> It seems that in a future version of iBatis, this bug will be corrected
> by adding a "var" attribute in iterate tag.
>
> If you wan't a patch to apply now, here's how I modified the code from
> iBatis.
> (you most likely downloaded the source code with the binary)
>
> I can send a patch to someone who ask (in a .jar file replacing
> ibatis-sqlmap-2.jar), but I would prefer that someone makes a real
> modification to the framework. I have an idea of how things should be
> changed to support nested iterate in a proper way.
>
> To use my patch, do the following.
> <iterate property="list">
>     table.someFiled = #list[].value#
>     <iterate property="list[].list">
>         table.narrowField = #list[].list[].value#
>     </iterate>
> </iterate>
>
>
> Please note that this modification was made on the iBatis 2.1.7.
> A bug still remains in my modifcations. I can make a new patch if anyone
> asks. This bug will make iBatis crash in this case.
> <iterate property="list">
>     <iterate property="list[].list">
>         <!-- suppose here you always want the value of element 4 in
> first list>
>         table.field = #list[4].list[].value#
>     </iterate>
> </iterate>
>
>
>
> // Mofications made to 3 files. Modifcations begin with comment "//
> Added code" and ends with "// End of added code". Some code is replaced
> to surrunded by "// Replaced code" and "// End of replaced code"
> // classes modified :
> com.ibatis.sqlmap.engine.mapping.sql.dynamic.DynamicSQL,
> com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.IterateTagHandler,
> com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.ConditionnalTagHan
> dler
>
>
> In com.ibatis.sqlmap.engine.mapping.sql.dynamic.DynamicSQL
>
>   protected void iteratePropertyReplace(StringBuffer bodyContent,
> IterateContext iterate) {
>     if(iterate!=null) {
>       String find = iterate.getProperty() + "[]";
>       // Added code.
>       find = find.replaceAll("\\[\\d+\\]", "[]");
>       // End of added code.
>       String replace = iterate.getProperty() + "[" + iterate.getIndex()
> + "]";
>       replace(bodyContent, find, replace);
>     }
>   }
>   private void processBodyChildren(RequestScope request, SqlTagContext
> ctx, Object parameterObject, Iterator localChildren, PrintWriter out) {
>     while (localChildren.hasNext()) {
>       SqlChild child = (SqlChild) localChildren.next();
>       if (child instanceof SqlText) {
>         SqlText sqlText = (SqlText) child;
>         String sqlStatement = sqlText.getText();
>         if (sqlText.isWhiteSpace()) {
>           out.print(sqlStatement);
>         } else if (!sqlText.isPostParseRequired()) {
>
>           // BODY OUT
>           out.print(sqlStatement);
>
>           ParameterMapping[] mappings = sqlText.getParameterMappings();
>           if (mappings != null) {
>             for (int i = 0, n = mappings.length; i < n; i++) {
>               ctx.addParameterMapping(mappings[i]);
>             }
>           }
>         } else {
>
>           IterateContext itCtx = ctx.peekIterateContext();
>
>           if(null != itCtx && itCtx.isAllowNext()){
>             itCtx.next();
>             itCtx.setAllowNext(false);
>             if(!itCtx.hasNext()) {
>               itCtx.setFinal(true);
>             }
>           }
>
>           if(itCtx!=null) {
>             StringBuffer sqlStatementBuffer = new
> StringBuffer(sqlStatement);
>             iteratePropertyReplace(sqlStatementBuffer, itCtx);
>             sqlStatement = sqlStatementBuffer.toString();
>           }
>
>           sqlText =
> PARAM_PARSER.parseInlineParameterMap(delegate.getTypeHandlerFactory(),
> sqlStatement);
>
>           ParameterMapping[] mappings = sqlText.getParameterMappings();
>           out.print(sqlText.getText());
>           if (mappings != null) {
>              for (int i = 0, n = mappings.length; i < n; i++) {
>                ctx.addParameterMapping(mappings[i]);
>              }
>           }
>         }
>       } else if (child instanceof SqlTag) {
>         SqlTag tag = (SqlTag) child;
>         SqlTagHandler handler = tag.getHandler();
>         int response = SqlTagHandler.INCLUDE_BODY;
>         do {
>           StringWriter sw = new StringWriter();
>           PrintWriter pw = new PrintWriter(sw);
>
>           response = handler.doStartFragment(ctx, tag, parameterObject);
>           if (response != SqlTagHandler.SKIP_BODY) {
>
>             processBodyChildren(request, ctx, parameterObject,
> tag.getChildren(), pw);
>             pw.flush();
>             pw.close();
>             StringBuffer body = sw.getBuffer();
>             response = handler.doEndFragment(ctx, tag, parameterObject,
> body);
>             handler.doPrepend(ctx, tag, parameterObject, body);
>
>             if (response != SqlTagHandler.SKIP_BODY) {
>               if (body.length() > 0) {
>                 out.print(body.toString());
>               }
>             }
>
>           }
>         } while (response == SqlTagHandler.REPEAT_BODY);
>
>         ctx.popRemoveFirstPrependMarker(tag);
>
>         if(ctx.peekIterateContext()!= null &&
> ctx.peekIterateContext().getTag() == tag) {
>             // Added code.
>             ctx.setAttribute(ctx.peekIterateContext().getTag(), null);
>             // End of added code.
>           ctx.popIterateContext();
>         }
>
>       }
>     }
>   }
>
>
>
>
> In
> com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.IterateTagHandler
>
>   public int doStartFragment(SqlTagContext ctx, SqlTag tag, Object
> parameterObject) {
>     IterateContext iterate = (IterateContext) ctx.getAttribute(tag);
>     if (iterate == null) {
>
>       ctx.pushRemoveFirstPrependMarker(tag);
>
>       Object collection;
>       String prop = tag.getPropertyAttr();
>       if (prop != null) {
>           // Added code.
>           {
>               // Increase index if the first tag is another iterate.
>               IterateContext itCtx = ctx.peekIterateContext();
>               if(null != itCtx && itCtx.isAllowNext()){
>                   itCtx.next();
>                   itCtx.setAllowNext(false);
>                   if(!itCtx.hasNext()) {
>                       itCtx.setFinal(true);
>                   }
>               }
>           }
>           SqlTag parentTag = tag.getParent();
>           int listIndex = prop.lastIndexOf('[');
>           while (listIndex > -1) {
>               if (Character.isDigit(prop.charAt(listIndex + 1))) {
>                   // Skip to next list.
>                   if (listIndex > 0) {
>                       listIndex = prop.lastIndexOf('[', listIndex - 1);
>                   }
>                   else {
>                       listIndex = -1;
>                   }
>               }
>               else {
>                   // Add iteration number to property.
>                   Object parentContext = ctx.getAttribute(parentTag);
>                   while (!(parentContext instanceof IterateContext)) {
>                       parentTag = parentTag.getParent();
>                       parentContext = ctx.getAttribute(parentTag);
>                   }
>                   IterateContext parentIterateContext = (IterateContext)
> parentContext;
>                   prop = prop.substring(0, listIndex + 1) +
> parentIterateContext.getIndex() + prop.substring(listIndex + 1);
>                   // Skip to next list.
>                   if (listIndex > 0) {
>                       listIndex = prop.lastIndexOf('[', listIndex - 1);
>                   }
>                   else {
>                       listIndex = -1;
>                   }
>                   parentTag = parentTag.getParent();
>               }
>           }
>           // End of added code.
>         collection = PROBE.getObject(parameterObject, prop);
>       } else {
>         collection = parameterObject;
>       }
>       iterate = new IterateContext(collection,tag);
>
>       iterate.setProperty( null == prop ? "" : prop );
>
>       ctx.setAttribute(tag, iterate);
>       ctx.pushIterateContext(iterate);
>     }
>     if (iterate != null && iterate.hasNext()) {
>       return INCLUDE_BODY;
>     } else {
>       return SKIP_BODY;
>     }
>   }
>
>
>
>
> In
> com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.ConditionnalTagHan
> dler
>   protected long compare(SqlTagContext ctx, SqlTag tag, Object
> parameterObject) {
>     String propertyName = tag.getPropertyAttr();
>     String comparePropertyName = tag.getComparePropertyAttr();
>     String compareValue = tag.getCompareValueAttr();
>
>     String prop = tag.getPropertyAttr();
>     Object value1;
>     Class type;
>     IterateContext itCtx = ctx.peekIterateContext();
>
>     if (prop != null) {
>
>       if(null != itCtx && itCtx.isAllowNext()){
>         itCtx.next();
>         itCtx.setAllowNext(false);
>         if(!itCtx.hasNext()) {
>           itCtx.setFinal(true);
>         }
>       }
>
>       if(prop.indexOf(START_INDEX) > -1) {
>           // Replaced code.
>           propertyName = new StringBuffer(propertyName).insert(
>
> propertyName.lastIndexOf(END_INDEX),itCtx.getIndex()).toString();
>           // End of replaced code.
>           // Added code.
>           SqlTag parentTag = itCtx.getTag().getParent();
>           int listIndex = propertyName.lastIndexOf('[');
>           while (listIndex > -1) {
>               if (Character.isDigit(propertyName.charAt(listIndex + 1)))
> {
>                   // Skip to next list.
>                   if (listIndex > 0) {
>                       listIndex = propertyName.lastIndexOf('[',
> listIndex - 1);
>                   }
>                   else {
>                       listIndex = -1;
>                   }
>               }
>               else {
>                   // Add iteration number to property.
>                   Object parentContext = ctx.getAttribute(parentTag);
>                   while (!(parentContext instanceof IterateContext)) {
>                       parentTag = parentTag.getParent();
>                       parentContext = ctx.getAttribute(parentTag);
>                   }
>                   IterateContext parentIterateContext = (IterateContext)
> parentContext;
>                   propertyName = propertyName.substring(0, listIndex +
> 1) + parentIterateContext.getIndex() + propertyName.substring(listIndex
> + 1);
>                   // Skip to next list.
>                   if (listIndex > 0) {
>                       listIndex = propertyName.lastIndexOf('[',
> listIndex - 1);
>                   }
>                   else {
>                       listIndex = -1;
>                   }
>                   parentTag = parentTag.getParent();
>               }
>           }
>           // End of added code.
>       }
>
>       value1 = PROBE.getObject(parameterObject, propertyName);
>       type = PROBE.getPropertyTypeForGetter(parameterObject,
> propertyName);
>     } else {
>       value1 = parameterObject;
>       if (value1 != null) {
>         type = parameterObject.getClass();
>       } else {
>         type = Object.class;
>       }
>     }
>     if (comparePropertyName != null) {
>       Object value2 = PROBE.getObject(parameterObject,
> comparePropertyName);
>       return compareValues(type, value1, value2);
>     } else if (compareValue != null) {
>       return compareValues(type, value1, compareValue);
>     } else {
>       throw new NestedRuntimeException("Error comparing in conditional
> fragment.  Uknown 'compare to' values.");
>     }
>   }
>
>
>