Skip to content

Commit

Permalink
Prevent foreach xml tag from polluting the global context
Browse files Browse the repository at this point in the history
  • Loading branch information
nyer committed Apr 20, 2017
1 parent 823cf2a commit 84513f9
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2009-2015 the original author or authors.
* Copyright 2009-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,6 +15,7 @@
*/
package org.apache.ibatis.scripting.xmltags;

import java.util.HashMap;
import java.util.Map;

import org.apache.ibatis.parsing.GenericTokenParser;
Expand Down Expand Up @@ -122,26 +123,32 @@ private static String itemizeItem(String item, int i) {

private static class FilteredDynamicContext extends DynamicContext {
private DynamicContext delegate;
private HierarchyContextMap hierarchyContextMap;
private int index;
private String itemIndex;
private String item;

public FilteredDynamicContext(Configuration configuration,DynamicContext delegate, String itemIndex, String item, int i) {
super(configuration, null);
this.delegate = delegate;
this.hierarchyContextMap = new HierarchyContextMap(delegate);
this.index = i;
this.itemIndex = itemIndex;
this.item = item;
}

@Override
public Map<String, Object> getBindings() {
return delegate.getBindings();
return hierarchyContextMap;
}

@Override
public void bind(String name, Object value) {
delegate.bind(name, value);
if (name.startsWith(ITEM_PREFIX)) {
hierarchyContextMap.putGlobal(name, value);
} else {
hierarchyContextMap.putLocal(name, value);
}
}

@Override
Expand Down Expand Up @@ -175,12 +182,14 @@ public int getUniqueNumber() {

private class PrefixedContext extends DynamicContext {
private DynamicContext delegate;
private HierarchyContextMap hierarchyContextMap;
private String prefix;
private boolean prefixApplied;

public PrefixedContext(DynamicContext delegate, String prefix) {
super(configuration, null);
this.delegate = delegate;
this.hierarchyContextMap = new HierarchyContextMap(delegate);
this.prefix = prefix;
this.prefixApplied = false;
}
Expand All @@ -191,12 +200,16 @@ public boolean isPrefixApplied() {

@Override
public Map<String, Object> getBindings() {
return delegate.getBindings();
return hierarchyContextMap;
}

@Override
public void bind(String name, Object value) {
delegate.bind(name, value);
if (name.startsWith(ITEM_PREFIX)) {
hierarchyContextMap.putGlobal(name, value);
} else {
hierarchyContextMap.putLocal(name, value);
}
}

@Override
Expand All @@ -218,5 +231,32 @@ public int getUniqueNumber() {
return delegate.getUniqueNumber();
}
}

private static class HierarchyContextMap extends HashMap<String, Object> {

private static final long serialVersionUID = -787211846381882154L;
private Map<String, Object> localContextMap = new HashMap<String, Object>();
private DynamicContext delegate;

public HierarchyContextMap(DynamicContext delegate) {
this.delegate = delegate;
}

public void putLocal(String name, Object value) {
localContextMap.put(name, value);
}

public void putGlobal(String name, Object value) {
delegate.bind(name, value);
}

@Override
public Object get(Object key) {
if (localContextMap.containsKey(key)) {
return localContextMap.get(key);
}

return delegate.getBindings().get(key);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2009-2015 the original author or authors.
* Copyright 2009-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -300,6 +300,20 @@ public void shouldTrimNoSetClause() throws Exception {
assertEquals(expected, boundSql.getSql());
}

@Test
public void shouldForeachNotWriteMiddleVariableToGlobalBindings() throws Exception {
final HashMap<String, Integer[]> parameterObject = new HashMap<String, Integer[]>() {{
put("array", new Integer[]{1,2,3,4,5});
}};
final String expected = "SELECT * FROM BLOG WHERE ID in ( ? , ? , ? , ? , ? )";
DynamicSqlSource source = createDynamicSqlSource(
new TextSqlNode("SELECT * FROM BLOG WHERE ID in"),
new ForEachSqlNode(new Configuration(),mixedContents(new TextSqlNode("#{id}")), "array", "index", "id", "(", ")", ","),
new IfSqlNode(new TextSqlNode("AND id = #{id}"), "id != null"));
BoundSql boundSql = source.getBoundSql(parameterObject);
assertEquals(expected, boundSql.getSql());
}

@Test
public void shouldIterateOnceForEachItemInCollection() throws Exception {
final HashMap<String, String[]> parameterObject = new HashMap<String, String[]>() {{
Expand All @@ -316,7 +330,7 @@ public void shouldIterateOnceForEachItemInCollection() throws Exception {
assertEquals("__frch_item_1", boundSql.getParameterMappings().get(1).getProperty());
assertEquals("__frch_item_2", boundSql.getParameterMappings().get(2).getProperty());
}

@Test
public void shouldHandleOgnlExpression() throws Exception {
final HashMap<String, String> parameterObject = new HashMap<String, String>() {{
Expand Down

0 comments on commit 84513f9

Please sign in to comment.