AbstractXmlMapperElementGenerator.java
/*
* Copyright 2006-2026 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.mybatis.generator.runtime.mybatis3.xmlmapper.elements;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.dom.OutputUtilities;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.GeneratedKey;
import org.mybatis.generator.runtime.AbstractXmlElementGenerator;
import org.mybatis.generator.runtime.mybatis3.ListUtilities;
import org.mybatis.generator.runtime.mybatis3.MyBatis3FormattingUtilities;
public abstract class AbstractXmlMapperElementGenerator extends AbstractXmlElementGenerator {
protected AbstractXmlMapperElementGenerator(AbstractGeneratorBuilder<?> builder) {
super(builder);
}
/**
* This method should return an XmlElement for the select key used to
* automatically generate keys.
*
* @param introspectedColumn
* the column related to the select key statement
* @param generatedKey
* the generated key for the current table
*
* @return the selectKey element
*/
protected XmlElement getSelectKey(IntrospectedColumn introspectedColumn,
GeneratedKey generatedKey) {
String identityColumnType = introspectedColumn.getFullyQualifiedJavaType().getFullyQualifiedName();
XmlElement answer = new XmlElement("selectKey"); //$NON-NLS-1$
answer.addAttribute(new Attribute("resultType", identityColumnType)); //$NON-NLS-1$
answer.addAttribute(new Attribute(
"keyProperty", introspectedColumn.getJavaProperty())); //$NON-NLS-1$
answer.addAttribute(new Attribute("order", generatedKey.getMyBatis3Order())); //$NON-NLS-1$
answer.addElement(new TextElement(generatedKey.getRuntimeSqlStatement()));
return answer;
}
protected XmlElement getBaseColumnListElement() {
XmlElement answer = new XmlElement("include"); //$NON-NLS-1$
answer.addAttribute(new Attribute("refid", introspectedTable.getBaseColumnListId())); //$NON-NLS-1$
return answer;
}
protected XmlElement getBlobColumnListElement() {
XmlElement answer = new XmlElement("include"); //$NON-NLS-1$
answer.addAttribute(new Attribute("refid", introspectedTable.getBlobColumnListId())); //$NON-NLS-1$
return answer;
}
protected XmlElement getExampleIncludeElement() {
XmlElement ifElement = new XmlElement("if"); //$NON-NLS-1$
ifElement.addAttribute(new Attribute("test", "_parameter != null")); //$NON-NLS-1$ //$NON-NLS-2$
XmlElement includeElement = new XmlElement("include"); //$NON-NLS-1$
includeElement.addAttribute(new Attribute("refid", introspectedTable.getExampleWhereClauseId())); //$NON-NLS-1$
ifElement.addElement(includeElement);
return ifElement;
}
protected XmlElement getUpdateByExampleIncludeElement() {
XmlElement ifElement = new XmlElement("if"); //$NON-NLS-1$
ifElement.addAttribute(new Attribute("test", "example != null")); //$NON-NLS-1$ //$NON-NLS-2$
XmlElement includeElement = new XmlElement("include"); //$NON-NLS-1$
includeElement.addAttribute(new Attribute("refid", //$NON-NLS-1$
introspectedTable.getMyBatis3UpdateByExampleWhereClauseId()));
ifElement.addElement(includeElement);
return ifElement;
}
protected List<TextElement> buildSelectList(List<IntrospectedColumn> columns) {
return buildSelectList("", columns); //$NON-NLS-1$
}
protected List<TextElement> buildSelectList(String initial, List<IntrospectedColumn> columns) {
List<TextElement> answer = new ArrayList<>();
StringBuilder sb = new StringBuilder(initial);
Iterator<IntrospectedColumn> iter = columns.iterator();
while (iter.hasNext()) {
sb.append(MyBatis3FormattingUtilities.getSelectListPhrase(iter.next()));
if (iter.hasNext()) {
sb.append(", "); //$NON-NLS-1$
}
if (sb.length() > 80) {
answer.add(new TextElement(sb.toString()));
sb.setLength(0);
}
}
if (!sb.isEmpty()) {
answer.add(new TextElement(sb.toString()));
}
return answer;
}
protected List<TextElement> buildPrimaryKeyWhereClause() {
List<TextElement> answer = new ArrayList<>();
boolean first = true;
for (IntrospectedColumn introspectedColumn : introspectedTable.getPrimaryKeyColumns()) {
String line;
if (first) {
line = "where "; //$NON-NLS-1$
first = false;
} else {
line = " and "; //$NON-NLS-1$
}
line += MyBatis3FormattingUtilities.getEscapedColumnName(introspectedColumn);
line += " = "; //$NON-NLS-1$
line += MyBatis3FormattingUtilities.getParameterClause(introspectedColumn);
answer.add(new TextElement(line));
}
return answer;
}
protected XmlElement buildInitialInsert(String statementId, FullyQualifiedJavaType parameterType) {
XmlElement answer = new XmlElement("insert"); //$NON-NLS-1$
answer.addAttribute(new Attribute("id", statementId)); //$NON-NLS-1$
answer.addAttribute(new Attribute("parameterType", parameterType.getFullyQualifiedName())); //$NON-NLS-1$
commentGenerator.addComment(answer);
introspectedTable.getGeneratedKey().ifPresent(gk ->
introspectedTable.getColumn(gk.getColumn()).ifPresent(introspectedColumn -> {
// if the column is null, then it's a configuration error. The
// warning has already been reported
if (gk.isJdbcStandard()) {
answer.addAttribute(new Attribute("useGeneratedKeys", "true")); //$NON-NLS-1$ //$NON-NLS-2$
answer.addAttribute(
new Attribute("keyProperty", introspectedColumn.getJavaProperty())); //$NON-NLS-1$
answer.addAttribute(
new Attribute("keyColumn", introspectedColumn.getActualColumnName())); //$NON-NLS-1$
} else {
answer.addElement(getSelectKey(introspectedColumn, gk));
}
})
);
return answer;
}
protected enum ResultElementType {
ID("id"), //$NON-NLS-1$
RESULT("result"); //$NON-NLS-1$
private final String value;
ResultElementType(String value) {
this.value = value;
}
}
protected List<XmlElement> buildResultMapItems(ResultElementType elementType, List<IntrospectedColumn> columns) {
List<XmlElement> answer = new ArrayList<>();
for (IntrospectedColumn introspectedColumn : columns) {
XmlElement resultElement = new XmlElement(elementType.value);
resultElement.addAttribute(buildColumnAttribute(introspectedColumn));
resultElement.addAttribute(new Attribute("property", introspectedColumn.getJavaProperty())); //$NON-NLS-1$
resultElement.addAttribute(new Attribute("jdbcType", introspectedColumn.getJdbcTypeName())); //$NON-NLS-1$
introspectedColumn.getTypeHandler().ifPresent(
th -> resultElement.addAttribute(new Attribute("typeHandler", th))); //$NON-NLS-1$
answer.add(resultElement);
}
return answer;
}
protected XmlElement buildConstructorElement(boolean includeBlobColumns) {
XmlElement constructor = new XmlElement("constructor"); //$NON-NLS-1$
for (IntrospectedColumn introspectedColumn : introspectedTable.getPrimaryKeyColumns()) {
XmlElement resultElement = new XmlElement("idArg"); //$NON-NLS-1$
resultElement.addAttribute(buildColumnAttribute(introspectedColumn));
resultElement.addAttribute(new Attribute("jdbcType", //$NON-NLS-1$
introspectedColumn.getJdbcTypeName()));
resultElement.addAttribute(new Attribute("javaType", //$NON-NLS-1$
introspectedColumn.getFullyQualifiedJavaType().getFullyQualifiedName()));
introspectedColumn.getTypeHandler().ifPresent(
th -> resultElement.addAttribute(new Attribute("typeHandler", th))); //$NON-NLS-1$
constructor.addElement(resultElement);
}
List<IntrospectedColumn> columns;
if (includeBlobColumns) {
columns = introspectedTable.getNonPrimaryKeyColumns();
} else {
columns = introspectedTable.getBaseColumns();
}
for (IntrospectedColumn introspectedColumn : columns) {
XmlElement resultElement = new XmlElement("arg"); //$NON-NLS-1$
resultElement.addAttribute(buildColumnAttribute(introspectedColumn));
resultElement.addAttribute(new Attribute("jdbcType", //$NON-NLS-1$
introspectedColumn.getJdbcTypeName()));
if (introspectedColumn.getFullyQualifiedJavaType().isPrimitive()) {
// need to use the MyBatis type alias for a primitive byte
String s = '_'
+ introspectedColumn.getFullyQualifiedJavaType().getShortName();
resultElement.addAttribute(new Attribute("javaType", s)); //$NON-NLS-1$
} else if ("byte[]".equals(introspectedColumn.getFullyQualifiedJavaType() //$NON-NLS-1$
.getFullyQualifiedName())) {
// need to use the MyBatis type alias for a primitive byte arry
resultElement.addAttribute(new Attribute("javaType", //$NON-NLS-1$
"_byte[]")); //$NON-NLS-1$
} else {
resultElement.addAttribute(new Attribute("javaType", //$NON-NLS-1$
introspectedColumn.getFullyQualifiedJavaType().getFullyQualifiedName()));
}
introspectedColumn.getTypeHandler().ifPresent(
th -> resultElement.addAttribute(new Attribute("typeHandler", th))); //$NON-NLS-1$
constructor.addElement(resultElement);
}
return constructor;
}
protected Attribute buildColumnAttribute(IntrospectedColumn introspectedColumn) {
return new Attribute("column", //$NON-NLS-1$
MyBatis3FormattingUtilities.getRenamedColumnNameForResultMap(introspectedColumn));
}
protected XmlElement buildUpdateByExampleElement(String statementId, List<IntrospectedColumn> columns) {
XmlElement answer = new XmlElement("update"); //$NON-NLS-1$
answer.addAttribute(new Attribute("id", statementId)); //$NON-NLS-1$
answer.addAttribute(new Attribute("parameterType", "map")); //$NON-NLS-1$ //$NON-NLS-2$
commentGenerator.addComment(answer);
StringBuilder sb = new StringBuilder();
sb.append("update "); //$NON-NLS-1$
sb.append(introspectedTable.getAliasedFullyQualifiedRuntimeTableName());
answer.addElement(new TextElement(sb.toString()));
// set up for first column
sb.setLength(0);
sb.append("set "); //$NON-NLS-1$
Iterator<IntrospectedColumn> iter = ListUtilities.filterColumnsForUpdate(columns).iterator();
while (iter.hasNext()) {
IntrospectedColumn introspectedColumn = iter.next();
sb.append(MyBatis3FormattingUtilities.getAliasedEscapedColumnName(introspectedColumn));
sb.append(" = "); //$NON-NLS-1$
sb.append(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn, "row.")); //$NON-NLS-1$
if (iter.hasNext()) {
sb.append(',');
}
answer.addElement(new TextElement(sb.toString()));
// set up for the next column
if (iter.hasNext()) {
sb.setLength(0);
OutputUtilities.xmlIndent(sb, 1);
}
}
answer.addElement(getUpdateByExampleIncludeElement());
return answer;
}
protected XmlElement buildUpdateByPrimaryKeyElement(String statementId, String parameterType,
List<IntrospectedColumn> columns) {
XmlElement answer = new XmlElement("update"); //$NON-NLS-1$
answer.addAttribute(new Attribute("id", statementId)); //$NON-NLS-1$
answer.addAttribute(new Attribute("parameterType", parameterType)); //$NON-NLS-1$
commentGenerator.addComment(answer);
StringBuilder sb = new StringBuilder();
sb.append("update "); //$NON-NLS-1$
sb.append(introspectedTable.getFullyQualifiedTableNameAtRuntime());
answer.addElement(new TextElement(sb.toString()));
// set up for first column
sb.setLength(0);
sb.append("set "); //$NON-NLS-1$
Iterator<IntrospectedColumn> iter = ListUtilities.filterColumnsForUpdate(columns).iterator();
while (iter.hasNext()) {
IntrospectedColumn introspectedColumn = iter.next();
sb.append(MyBatis3FormattingUtilities.getEscapedColumnName(introspectedColumn));
sb.append(" = "); //$NON-NLS-1$
sb.append(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn));
if (iter.hasNext()) {
sb.append(',');
}
answer.addElement(new TextElement(sb.toString()));
// set up for the next column
if (iter.hasNext()) {
sb.setLength(0);
OutputUtilities.xmlIndent(sb, 1);
}
}
buildPrimaryKeyWhereClause().forEach(answer::addElement);
return answer;
}
protected XmlElement generateSelectByExample(boolean forBlobs) {
String statementId;
String resultMapId;
if (forBlobs) {
statementId = introspectedTable.getSelectByExampleWithBLOBsStatementId();
resultMapId = introspectedTable.getResultMapWithBLOBsId();
} else {
statementId = introspectedTable.getSelectByExampleStatementId();
resultMapId = introspectedTable.getBaseResultMapId();
}
XmlElement answer = new XmlElement("select"); //$NON-NLS-1$
answer.addAttribute(new Attribute("id", statementId)); //$NON-NLS-1$
answer.addAttribute(new Attribute("resultMap", resultMapId)); //$NON-NLS-1$
answer.addAttribute(new Attribute("parameterType", introspectedTable.getExampleType())); //$NON-NLS-1$
commentGenerator.addComment(answer);
answer.addElement(new TextElement("select")); //$NON-NLS-1$
XmlElement ifElement = new XmlElement("if"); //$NON-NLS-1$
ifElement.addAttribute(new Attribute("test", "distinct")); //$NON-NLS-1$ //$NON-NLS-2$
ifElement.addElement(new TextElement("distinct")); //$NON-NLS-1$
answer.addElement(ifElement);
answer.addElement(getBaseColumnListElement());
if (forBlobs) {
answer.addElement(new TextElement(",")); //$NON-NLS-1$
answer.addElement(getBlobColumnListElement());
}
String fromLine = "from " + introspectedTable.getAliasedFullyQualifiedRuntimeTableName(); //$NON-NLS-1$
answer.addElement(new TextElement(fromLine));
answer.addElement(getExampleIncludeElement());
ifElement = new XmlElement("if"); //$NON-NLS-1$
ifElement.addAttribute(new Attribute("test", "orderByClause != null")); //$NON-NLS-1$ //$NON-NLS-2$
ifElement.addElement(new TextElement("order by ${orderByClause}")); //$NON-NLS-1$
answer.addElement(ifElement);
return answer;
}
}