-
Notifications
You must be signed in to change notification settings - Fork 13k
Issue 652 - Parametrized include #331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
f21fb7b
31c477f
bd80dc1
463a4a5
f06a2e4
7d95da4
260abff
80181c8
fd15446
aca6951
4df0298
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,12 +17,16 @@ | |
|
|
||
| import org.apache.ibatis.builder.IncompleteElementException; | ||
| import org.apache.ibatis.builder.MapperBuilderAssistant; | ||
| import org.apache.ibatis.parsing.GenericTokenParser; | ||
| import org.apache.ibatis.parsing.PropertyParser; | ||
| import org.apache.ibatis.parsing.TokenHandler; | ||
| import org.apache.ibatis.parsing.XNode; | ||
| import org.apache.ibatis.session.Configuration; | ||
| import org.w3c.dom.Node; | ||
| import org.w3c.dom.NodeList; | ||
|
|
||
| import java.util.*; | ||
|
|
||
| /** | ||
| * @author Frank D. Martinez [mnesarco] | ||
| */ | ||
|
|
@@ -37,9 +41,42 @@ public XMLIncludeTransformer(Configuration configuration, MapperBuilderAssistant | |
| } | ||
|
|
||
| public void applyIncludes(Node source) { | ||
| Properties variablesContext = new Properties(); | ||
| Properties configurationVariables = configuration.getVariables(); | ||
| if (configurationVariables != null) { | ||
| variablesContext.putAll(configurationVariables); | ||
| } | ||
| applyIncludes(source, variablesContext); | ||
| } | ||
|
|
||
| /** | ||
| * Recursively apply includes through all SQL fragments. | ||
| * @param source Include node in DOM tree | ||
| * @param variablesContext Current context for static variables with values | ||
| */ | ||
| private void applyIncludes(Node source, final Properties variablesContext) { | ||
| if (source.getNodeName().equals("include")) { | ||
| Node toInclude = findSqlFragment(getStringAttribute(source, "refid")); | ||
| applyIncludes(toInclude); | ||
| // new full context for included SQL - contains inherited context and new variables from current include node | ||
| Properties fullContext; | ||
|
|
||
| String refid = getStringAttribute(source, "refid"); | ||
| // replace variables in include refid value | ||
| refid = PropertyParser.parse(refid, variablesContext); | ||
| Node toInclude = findSqlFragment(refid); | ||
| Properties newVariablesContext = getVariablesContext(source); | ||
| if (!newVariablesContext.isEmpty()) { | ||
| // replace variables in variable values too | ||
| for (Object name : newVariablesContext.keySet()) { | ||
| newVariablesContext.put(name, PropertyParser.parse(newVariablesContext.get(name).toString(), variablesContext)); | ||
| } | ||
| // merge new and inherited into new full one | ||
| applyInheritedContext(newVariablesContext, variablesContext); | ||
| fullContext = newVariablesContext; | ||
| } else { | ||
| // no new context - use inherited fully | ||
| fullContext = variablesContext; | ||
| } | ||
| applyIncludes(toInclude, fullContext); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This part could be simpler if replacing variables in the subroutine. Properties fullContext;
Properties childContext = getVariablesContext(source, variablesContext);
if (childContext.isEmpty()) {
fullContext = variablesContext;
} else {
fullContext = new Properties();
fullContext.putAll(variablesContext);
fullContext.putAll(childContext);
}
applyIncludes(toInclude, fullContext);I could be missing something, though.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough, I wanted to save creation of another Properties object but it probably does not make much sense and better to make it simpler. |
||
| if (toInclude.getOwnerDocument() != source.getOwnerDocument()) { | ||
| toInclude = source.getOwnerDocument().importNode(toInclude, true); | ||
| } | ||
|
|
@@ -51,13 +88,18 @@ public void applyIncludes(Node source) { | |
| } else if (source.getNodeType() == Node.ELEMENT_NODE) { | ||
| NodeList children = source.getChildNodes(); | ||
| for (int i=0; i<children.getLength(); i++) { | ||
| applyIncludes(children.item(i)); | ||
| applyIncludes(children.item(i), variablesContext); | ||
| } | ||
| } else if (source.getNodeType() == Node.ATTRIBUTE_NODE && !variablesContext.isEmpty()) { | ||
| // replace variables in all attribute values | ||
| source.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext)); | ||
| } else if (source.getNodeType() == Node.TEXT_NODE && !variablesContext.isEmpty()) { | ||
| // replace variables ins all text nodes | ||
| source.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext)); | ||
| } | ||
| } | ||
|
|
||
| private Node findSqlFragment(String refid) { | ||
| refid = PropertyParser.parse(refid, configuration.getVariables()); | ||
| refid = builderAssistant.applyCurrentNamespace(refid, true); | ||
| try { | ||
| XNode nodeToInclude = configuration.getSqlFragments().get(refid); | ||
|
|
@@ -70,4 +112,58 @@ private Node findSqlFragment(String refid) { | |
| private String getStringAttribute(Node node, String name) { | ||
| return node.getAttributes().getNamedItem(name).getNodeValue(); | ||
| } | ||
|
|
||
| /** | ||
| * Add inherited context into newly created one. | ||
| * @param newContext variables defined current include clause where inherited values will be placed | ||
| * @param inheritedContext all inherited variables values | ||
| */ | ||
| private void applyInheritedContext(Properties newContext, Properties inheritedContext) { | ||
| for (Map.Entry<Object, Object> e : inheritedContext.entrySet()) { | ||
| if (!newContext.containsKey(e.getKey())) { | ||
| newContext.put(e.getKey(), e.getValue()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Read placholders and their values from include node definition. | ||
| * @param node Include node instance | ||
| * @return variables context from include instance (no inherited values) | ||
| */ | ||
| private Properties getVariablesContext(Node node) { | ||
| List<Node> subElements = getSubElements(node); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, I merged it into one method which is shorter. |
||
| if (subElements.isEmpty()) { | ||
| return new Properties(); | ||
| } else { | ||
| Properties variablesContext = new Properties(); | ||
| for (Node variableValue : subElements) { | ||
| String name = getStringAttribute(variableValue, "name"); | ||
| String value = getStringAttribute(variableValue, "value"); | ||
| // Push new value | ||
| Object originalValue = variablesContext.put(name, value); | ||
| if (originalValue != null) { | ||
| throw new IllegalArgumentException("Variable " + name + " defined twice in the same include definition"); | ||
|
||
| } | ||
| } | ||
| return variablesContext; | ||
| } | ||
| } | ||
|
|
||
| private List<Node> getSubElements(Node node) { | ||
| NodeList children = node.getChildNodes(); | ||
| if (children.getLength() == 0) { | ||
| return Collections.emptyList(); | ||
| } else { | ||
| List<Node> elements = new ArrayList<Node>(); | ||
| for (int i = 0; i < children.getLength(); i++) { | ||
| Node n = children.item(i); | ||
| if (n.getNodeType() == Node.ELEMENT_NODE) { | ||
| elements.add(n); | ||
| } | ||
| } | ||
| return elements; | ||
| } | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| -- | ||
| -- Copyright 2009-2015 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. | ||
| -- 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. | ||
| -- | ||
|
|
||
| drop table SomeTable if exists; | ||
|
|
||
| create table SomeTable ( | ||
| id int, | ||
| field1 varchar(20), | ||
| field2 varchar(20), | ||
| field3 varchar(20) | ||
| ); | ||
|
|
||
| insert into SomeTable (id, field1, field2, field3) values(1, 'a', 'b', 'c'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see some other classes for reference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, I have changed IDE configuration to fix that,