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.");
> }
> }
>
>
>