XMLStatementBuilder.java
- /*
- * Copyright 2009-2024 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
- *
- * https://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.
- */
- package org.apache.ibatis.builder.xml;
- import java.util.List;
- import java.util.Locale;
- import org.apache.ibatis.builder.BaseBuilder;
- import org.apache.ibatis.builder.MapperBuilderAssistant;
- import org.apache.ibatis.builder.annotation.MapperAnnotationBuilder;
- import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
- import org.apache.ibatis.executor.keygen.KeyGenerator;
- import org.apache.ibatis.executor.keygen.NoKeyGenerator;
- import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
- import org.apache.ibatis.mapping.MappedStatement;
- import org.apache.ibatis.mapping.ResultSetType;
- import org.apache.ibatis.mapping.SqlCommandType;
- import org.apache.ibatis.mapping.SqlSource;
- import org.apache.ibatis.mapping.StatementType;
- import org.apache.ibatis.parsing.XNode;
- import org.apache.ibatis.scripting.LanguageDriver;
- import org.apache.ibatis.session.Configuration;
- /**
- * @author Clinton Begin
- */
- public class XMLStatementBuilder extends BaseBuilder {
- private final MapperBuilderAssistant builderAssistant;
- private final XNode context;
- private final String requiredDatabaseId;
- public XMLStatementBuilder(Configuration configuration, MapperBuilderAssistant builderAssistant, XNode context) {
- this(configuration, builderAssistant, context, null);
- }
- public XMLStatementBuilder(Configuration configuration, MapperBuilderAssistant builderAssistant, XNode context,
- String databaseId) {
- super(configuration);
- this.builderAssistant = builderAssistant;
- this.context = context;
- this.requiredDatabaseId = databaseId;
- }
- public void parseStatementNode() {
- String id = context.getStringAttribute("id");
- String databaseId = context.getStringAttribute("databaseId");
- if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
- return;
- }
- String nodeName = context.getNode().getNodeName();
- SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
- boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
- boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
- boolean useCache = context.getBooleanAttribute("useCache", isSelect);
- boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
- // Include Fragments before parsing
- XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
- includeParser.applyIncludes(context.getNode());
- String parameterType = context.getStringAttribute("parameterType");
- Class<?> parameterTypeClass = resolveClass(parameterType);
- String lang = context.getStringAttribute("lang");
- LanguageDriver langDriver = getLanguageDriver(lang);
- // Parse selectKey after includes and remove them.
- processSelectKeyNodes(id, parameterTypeClass, langDriver);
- // Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
- KeyGenerator keyGenerator;
- String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
- keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
- if (configuration.hasKeyGenerator(keyStatementId)) {
- keyGenerator = configuration.getKeyGenerator(keyStatementId);
- } else {
- keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
- configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
- ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
- }
- SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
- StatementType statementType = StatementType
- .valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
- Integer fetchSize = context.getIntAttribute("fetchSize");
- Integer timeout = context.getIntAttribute("timeout");
- String parameterMap = context.getStringAttribute("parameterMap");
- String resultType = context.getStringAttribute("resultType");
- Class<?> resultTypeClass = resolveClass(resultType);
- String resultMap = context.getStringAttribute("resultMap");
- if (resultTypeClass == null && resultMap == null) {
- resultTypeClass = MapperAnnotationBuilder.getMethodReturnType(builderAssistant.getCurrentNamespace(), id);
- }
- String resultSetType = context.getStringAttribute("resultSetType");
- ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
- if (resultSetTypeEnum == null) {
- resultSetTypeEnum = configuration.getDefaultResultSetType();
- }
- String keyProperty = context.getStringAttribute("keyProperty");
- String keyColumn = context.getStringAttribute("keyColumn");
- String resultSets = context.getStringAttribute("resultSets");
- boolean dirtySelect = context.getBooleanAttribute("affectData", Boolean.FALSE);
- builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap,
- parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered,
- keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets, dirtySelect);
- }
- private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) {
- List<XNode> selectKeyNodes = context.evalNodes("selectKey");
- if (configuration.getDatabaseId() != null) {
- parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId());
- }
- parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null);
- removeSelectKeyNodes(selectKeyNodes);
- }
- private void parseSelectKeyNodes(String parentId, List<XNode> list, Class<?> parameterTypeClass,
- LanguageDriver langDriver, String skRequiredDatabaseId) {
- for (XNode nodeToHandle : list) {
- String id = parentId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
- String databaseId = nodeToHandle.getStringAttribute("databaseId");
- if (databaseIdMatchesCurrent(id, databaseId, skRequiredDatabaseId)) {
- parseSelectKeyNode(id, nodeToHandle, parameterTypeClass, langDriver, databaseId);
- }
- }
- }
- private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver,
- String databaseId) {
- String resultType = nodeToHandle.getStringAttribute("resultType");
- Class<?> resultTypeClass = resolveClass(resultType);
- StatementType statementType = StatementType
- .valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString()));
- String keyProperty = nodeToHandle.getStringAttribute("keyProperty");
- String keyColumn = nodeToHandle.getStringAttribute("keyColumn");
- boolean executeBefore = "BEFORE".equals(nodeToHandle.getStringAttribute("order", "AFTER"));
- // defaults
- boolean useCache = false;
- boolean resultOrdered = false;
- KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
- Integer fetchSize = null;
- Integer timeout = null;
- boolean flushCache = false;
- String parameterMap = null;
- String resultMap = null;
- ResultSetType resultSetTypeEnum = null;
- SqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass);
- SqlCommandType sqlCommandType = SqlCommandType.SELECT;
- builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap,
- parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered,
- keyGenerator, keyProperty, keyColumn, databaseId, langDriver, null, false);
- id = builderAssistant.applyCurrentNamespace(id, false);
- MappedStatement keyStatement = configuration.getMappedStatement(id, false);
- configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));
- }
- private void removeSelectKeyNodes(List<XNode> selectKeyNodes) {
- for (XNode nodeToHandle : selectKeyNodes) {
- nodeToHandle.getParent().getNode().removeChild(nodeToHandle.getNode());
- }
- }
- private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
- if (requiredDatabaseId != null) {
- return requiredDatabaseId.equals(databaseId);
- }
- if (databaseId != null) {
- return false;
- }
- id = builderAssistant.applyCurrentNamespace(id, false);
- if (!this.configuration.hasStatement(id, false)) {
- return true;
- }
- // skip this statement if there is a previous one with a not null databaseId
- MappedStatement previous = this.configuration.getMappedStatement(id, false); // issue #2
- return previous.getDatabaseId() == null;
- }
- private LanguageDriver getLanguageDriver(String lang) {
- Class<? extends LanguageDriver> langClass = null;
- if (lang != null) {
- langClass = resolveClass(lang);
- }
- return configuration.getLanguageDriver(langClass);
- }
- }