Skip to content

Commit 6792d47

Browse files
committed
Optimized <include /> resolution logic.
1 parent f4e9bfe commit 6792d47

File tree

1 file changed

+29
-37
lines changed

1 file changed

+29
-37
lines changed

src/main/java/org/apache/ibatis/builder/xml/XMLIncludeTransformer.java

Lines changed: 29 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
*/
1616
package org.apache.ibatis.builder.xml;
1717

18+
import java.util.HashMap;
19+
import java.util.Map;
20+
import java.util.Properties;
21+
1822
import org.apache.ibatis.builder.BuilderException;
1923
import org.apache.ibatis.builder.IncompleteElementException;
2024
import org.apache.ibatis.builder.MapperBuilderAssistant;
@@ -24,8 +28,6 @@
2428
import org.w3c.dom.Node;
2529
import org.w3c.dom.NodeList;
2630

27-
import java.util.Properties;
28-
2931
/**
3032
* @author Frank D. Martinez [mnesarco]
3133
*/
@@ -45,34 +47,19 @@ public void applyIncludes(Node source) {
4547
if (configurationVariables != null) {
4648
variablesContext.putAll(configurationVariables);
4749
}
48-
applyIncludes(source, variablesContext);
50+
applyIncludes(source, variablesContext, false);
4951
}
5052

5153
/**
5254
* Recursively apply includes through all SQL fragments.
5355
* @param source Include node in DOM tree
5456
* @param variablesContext Current context for static variables with values
5557
*/
56-
private void applyIncludes(Node source, final Properties variablesContext) {
58+
private void applyIncludes(Node source, final Properties variablesContext, boolean included) {
5759
if (source.getNodeName().equals("include")) {
58-
// new full context for included SQL - contains inherited context and new variables from current include node
59-
Properties fullContext;
60-
61-
String refid = getStringAttribute(source, "refid");
62-
// replace variables in include refid value
63-
refid = PropertyParser.parse(refid, variablesContext);
64-
Node toInclude = findSqlFragment(refid);
65-
Properties newVariablesContext = getVariablesContext(source, variablesContext);
66-
if (!newVariablesContext.isEmpty()) {
67-
// merge contexts
68-
fullContext = new Properties();
69-
fullContext.putAll(variablesContext);
70-
fullContext.putAll(newVariablesContext);
71-
} else {
72-
// no new context - use inherited fully
73-
fullContext = variablesContext;
74-
}
75-
applyIncludes(toInclude, fullContext);
60+
Node toInclude = findSqlFragment(getStringAttribute(source, "refid"), variablesContext);
61+
Properties toIncludeContext = getVariablesContext(source, variablesContext);
62+
applyIncludes(toInclude, toIncludeContext, true);
7663
if (toInclude.getOwnerDocument() != source.getOwnerDocument()) {
7764
toInclude = source.getOwnerDocument().importNode(toInclude, true);
7865
}
@@ -83,19 +70,18 @@ private void applyIncludes(Node source, final Properties variablesContext) {
8370
toInclude.getParentNode().removeChild(toInclude);
8471
} else if (source.getNodeType() == Node.ELEMENT_NODE) {
8572
NodeList children = source.getChildNodes();
86-
for (int i=0; i<children.getLength(); i++) {
87-
applyIncludes(children.item(i), variablesContext);
73+
for (int i = 0; i < children.getLength(); i++) {
74+
applyIncludes(children.item(i), variablesContext, included);
8875
}
89-
} else if (source.getNodeType() == Node.ATTRIBUTE_NODE && !variablesContext.isEmpty()) {
90-
// replace variables in all attribute values
91-
source.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext));
92-
} else if (source.getNodeType() == Node.TEXT_NODE && !variablesContext.isEmpty()) {
76+
} else if (included && source.getNodeType() == Node.TEXT_NODE
77+
&& !variablesContext.isEmpty()) {
9378
// replace variables ins all text nodes
9479
source.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext));
9580
}
9681
}
9782

98-
private Node findSqlFragment(String refid) {
83+
private Node findSqlFragment(String refid, Properties variables) {
84+
refid = PropertyParser.parse(refid, variables);
9985
refid = builderAssistant.applyCurrentNamespace(refid, true);
10086
try {
10187
XNode nodeToInclude = configuration.getSqlFragments().get(refid);
@@ -116,23 +102,29 @@ private String getStringAttribute(Node node, String name) {
116102
* @return variables context from include instance (no inherited values)
117103
*/
118104
private Properties getVariablesContext(Node node, Properties inheritedVariablesContext) {
119-
Properties variablesContext = new Properties();
105+
Map<String, String> declaredProperties = null;
120106
NodeList children = node.getChildNodes();
121107
for (int i = 0; i < children.getLength(); i++) {
122108
Node n = children.item(i);
123109
if (n.getNodeType() == Node.ELEMENT_NODE) {
124110
String name = getStringAttribute(n, "name");
125-
String value = getStringAttribute(n, "value");
126111
// Replace variables inside
127-
value = PropertyParser.parse(value, inheritedVariablesContext);
128-
// Push new value
129-
Object originalValue = variablesContext.put(name, value);
130-
if (originalValue != null) {
112+
String value = PropertyParser.parse(getStringAttribute(n, "value"), inheritedVariablesContext);
113+
if (declaredProperties == null) {
114+
declaredProperties = new HashMap<String, String>();
115+
}
116+
if (declaredProperties.put(name, value) != null) {
131117
throw new BuilderException("Variable " + name + " defined twice in the same include definition");
132118
}
133119
}
134120
}
135-
return variablesContext;
121+
if (declaredProperties == null) {
122+
return inheritedVariablesContext;
123+
} else {
124+
Properties newProperties = new Properties();
125+
newProperties.putAll(inheritedVariablesContext);
126+
newProperties.putAll(declaredProperties);
127+
return newProperties;
128+
}
136129
}
137-
138130
}

0 commit comments

Comments
 (0)