├── .gitignore ├── .travis.yml ├── src ├── test │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── dcendents │ │ │ └── mybatis │ │ │ └── generator │ │ │ └── plugin │ │ │ ├── wrap │ │ │ ├── BaseClassDTO.java │ │ │ ├── ClassDTO.java │ │ │ └── WrapObjectPluginTest.java │ │ │ ├── annotation │ │ │ └── AddClassAnnotationsPluginTest.java │ │ │ ├── dynamic │ │ │ └── sql │ │ │ │ └── DynamicSqlPluginTest.java │ │ │ ├── model │ │ │ └── AlterModelPluginTest.java │ │ │ ├── subpackage │ │ │ ├── RenamePropertiesTest.java │ │ │ └── CreateSubPackagePluginTest.java │ │ │ ├── locking │ │ │ └── OptimisticLockingPluginTest.java │ │ │ └── client │ │ │ ├── AlterResultMapPluginTest.java │ │ │ └── CreateGenericInterfacePluginTest.java │ └── resources │ │ ├── log4j.xml │ │ └── log4j.dtd └── main │ └── java │ └── com │ └── github │ └── dcendents │ └── mybatis │ └── generator │ └── plugin │ ├── annotation │ └── AddClassAnnotationsPlugin.java │ ├── model │ └── AlterModelPlugin.java │ ├── dynamic │ └── sql │ │ ├── DynamicSqlPlugin.java │ │ └── DynamicSqlSupportClassGenerator.java │ ├── subpackage │ ├── RenameProperties.java │ └── CreateSubPackagePlugin.java │ ├── locking │ └── OptimisticLockingPlugin.java │ ├── client │ ├── AlterResultMapPlugin.java │ └── CreateGenericInterfacePlugin.java │ ├── wrap │ └── WrapObjectPlugin.java │ └── rename │ └── RenameExampleClassAndMethodsPlugin.java ├── .github └── dependabot.yml ├── pom.xml ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .project 3 | .settings 4 | target 5 | /target-eclipse/ 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: 4 | - openjdk8 5 | 6 | script: mvn clean verify 7 | 8 | after_success: 9 | - bash <(curl -s https://codecov.io/bash) 10 | -------------------------------------------------------------------------------- /src/test/java/com/github/dcendents/mybatis/generator/plugin/wrap/BaseClassDTO.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.wrap; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | public class BaseClassDTO { 7 | 8 | @Getter 9 | @Setter 10 | private String name; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: maven 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | target-branch: develop 9 | ignore: 10 | - dependency-name: org.mockito:mockito-core 11 | versions: 12 | - 3.7.7 13 | - 3.8.0 14 | - dependency-name: junit:junit 15 | versions: 16 | - 4.13.1 17 | - dependency-name: org.codehaus.mojo:animal-sniffer-maven-plugin 18 | versions: 19 | - "1.19" 20 | -------------------------------------------------------------------------------- /src/test/java/com/github/dcendents/mybatis/generator/plugin/wrap/ClassDTO.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.wrap; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | public class ClassDTO extends BaseClassDTO { 7 | 8 | private String address; 9 | 10 | @Getter 11 | private String street; 12 | 13 | @Getter 14 | @Setter 15 | private String city; 16 | 17 | @Getter 18 | @Setter 19 | private String postCode; 20 | 21 | private String country; 22 | 23 | @Getter 24 | @Setter 25 | private boolean homeAddress; 26 | 27 | @Getter 28 | @Setter 29 | private Boolean workAddress; 30 | } 31 | -------------------------------------------------------------------------------- /src/test/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/dcendents/mybatis/generator/plugin/annotation/AddClassAnnotationsPlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.annotation; 2 | 3 | import java.util.List; 4 | 5 | import lombok.NoArgsConstructor; 6 | 7 | import org.mybatis.generator.api.IntrospectedTable; 8 | import org.mybatis.generator.api.PluginAdapter; 9 | import org.mybatis.generator.api.dom.java.TopLevelClass; 10 | 11 | import static org.mybatis.generator.internal.util.StringUtility.stringHasValue; 12 | 13 | /** 14 | * Mybatis generator plugin to add annotations at the class level. 15 | */ 16 | @NoArgsConstructor 17 | public class AddClassAnnotationsPlugin extends PluginAdapter { 18 | public static final String ANNOTATION_CLASS = "annotationClass"; 19 | public static final String ANNOTATION_STRING = "annotationString"; 20 | 21 | private String annotationClass; 22 | private String annotationString; 23 | 24 | @Override 25 | public boolean validate(List warnings) { 26 | annotationClass = properties.getProperty(ANNOTATION_CLASS); 27 | annotationString = properties.getProperty(ANNOTATION_STRING); 28 | 29 | String warning = "Property %s not set for plugin %s"; 30 | if (!stringHasValue(annotationClass)) { 31 | warnings.add(String.format(warning, ANNOTATION_CLASS, this.getClass().getSimpleName())); 32 | } 33 | if (!stringHasValue(annotationString)) { 34 | warnings.add(String.format(warning, ANNOTATION_STRING, this.getClass().getSimpleName())); 35 | } 36 | 37 | return stringHasValue(annotationClass) && stringHasValue(annotationString); 38 | } 39 | 40 | @Override 41 | public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 42 | topLevelClass.addImportedType(annotationClass); 43 | topLevelClass.addAnnotation(annotationString); 44 | 45 | return true; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/github/dcendents/mybatis/generator/plugin/model/AlterModelPlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.model; 2 | 3 | import java.util.List; 4 | import java.util.regex.Pattern; 5 | 6 | import lombok.NoArgsConstructor; 7 | 8 | import org.mybatis.generator.api.IntrospectedTable; 9 | import org.mybatis.generator.api.PluginAdapter; 10 | import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; 11 | import org.mybatis.generator.api.dom.java.TopLevelClass; 12 | 13 | import static org.mybatis.generator.internal.util.StringUtility.stringHasValue; 14 | 15 | /** 16 | * Mybatis generator plugin to modify the generated model. 17 | */ 18 | @NoArgsConstructor 19 | public class AlterModelPlugin extends PluginAdapter { 20 | public static final String TABLE_NAME = "fullyQualifiedTableName"; 21 | public static final String ADD_INTERFACES = "addInterfaces"; 22 | 23 | private String tableName; 24 | private String[] addInterfaces; 25 | 26 | @Override 27 | public boolean validate(List warnings) { 28 | tableName = properties.getProperty(TABLE_NAME); 29 | String interfacesString = properties.getProperty(ADD_INTERFACES); 30 | 31 | String warning = "Property %s not set for plugin %s"; 32 | if (!stringHasValue(tableName)) { 33 | warnings.add(String.format(warning, TABLE_NAME, this.getClass().getSimpleName())); 34 | } 35 | if (!stringHasValue(interfacesString)) { 36 | warnings.add(String.format(warning, ADD_INTERFACES, this.getClass().getSimpleName())); 37 | } else { 38 | addInterfaces = interfacesString.split(","); 39 | } 40 | 41 | return stringHasValue(tableName) && addInterfaces != null; 42 | } 43 | 44 | private boolean tableMatches(IntrospectedTable introspectedTable) { 45 | return tableName.equals(introspectedTable.getFullyQualifiedTableNameAtRuntime()) 46 | || Pattern.matches(tableName, introspectedTable.getFullyQualifiedTableNameAtRuntime()); 47 | } 48 | 49 | @Override 50 | public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 51 | if (tableMatches(introspectedTable)) { 52 | for (String theInterface : addInterfaces) { 53 | FullyQualifiedJavaType type = new FullyQualifiedJavaType(theInterface); 54 | topLevelClass.addImportedType(type); 55 | topLevelClass.addSuperInterface(type); 56 | } 57 | } 58 | 59 | return true; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/github/dcendents/mybatis/generator/plugin/dynamic/sql/DynamicSqlPlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.dynamic.sql; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import lombok.NoArgsConstructor; 7 | 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.mybatis.generator.api.GeneratedJavaFile; 10 | import org.mybatis.generator.api.IntrospectedTable; 11 | import org.mybatis.generator.api.PluginAdapter; 12 | import org.mybatis.generator.api.dom.DefaultJavaFormatter; 13 | import org.mybatis.generator.api.dom.java.CompilationUnit; 14 | 15 | /** 16 | * Mybatis generator plugin to add dynamic sql table definitions. 17 | */ 18 | @NoArgsConstructor 19 | public class DynamicSqlPlugin extends PluginAdapter { 20 | public static final String TABLE_CLASS_SUFFIX = "tableClassSuffix"; 21 | public static final String ADD_ALIASED_COLUMNS = "addAliasedColumns"; 22 | public static final String ADD_TABLE_ALIAS = "addTableAlias"; 23 | public static final String TABLE_ALIAS_FIELD_NAME = "tableAliasFieldName"; 24 | 25 | public static final String DEFAULT_TABLE_ALIAS_FIELD = "tableAlias"; 26 | 27 | private String tableClassSuffix; 28 | private boolean addAliasedColumns; 29 | private boolean addTableAlias; 30 | private String tableAliasFieldName; 31 | 32 | @Override 33 | public boolean validate(List warnings) { 34 | tableClassSuffix = properties.getProperty(TABLE_CLASS_SUFFIX); 35 | String addAliasedColumnsString = properties.getProperty(ADD_ALIASED_COLUMNS); 36 | String addTableAliasString = properties.getProperty(ADD_TABLE_ALIAS); 37 | tableAliasFieldName = properties.getProperty(TABLE_ALIAS_FIELD_NAME); 38 | 39 | tableClassSuffix = tableClassSuffix == null ? "" : tableClassSuffix.trim(); 40 | addAliasedColumns = Boolean.parseBoolean(addAliasedColumnsString); 41 | addTableAlias = Boolean.parseBoolean(addTableAliasString); 42 | if (StringUtils.isBlank(tableAliasFieldName)) { 43 | tableAliasFieldName = DEFAULT_TABLE_ALIAS_FIELD; 44 | } 45 | 46 | return true; 47 | } 48 | 49 | @Override 50 | public List contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) { 51 | List models = new ArrayList<>(); 52 | 53 | CompilationUnit unit = DynamicSqlSupportClassGenerator 54 | .of(introspectedTable, context.getCommentGenerator(), tableClassSuffix, addAliasedColumns, addTableAlias, tableAliasFieldName, properties) 55 | .generate(); 56 | 57 | GeneratedJavaFile dynamicSqlModel = 58 | new GeneratedJavaFile(unit, context.getJavaClientGeneratorConfiguration().getTargetProject(), new DefaultJavaFormatter()); 59 | 60 | models.add(dynamicSqlModel); 61 | 62 | return models; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/github/dcendents/mybatis/generator/plugin/subpackage/RenameProperties.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.subpackage; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.commons.lang3.StringUtils; 6 | import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; 7 | import org.mybatis.generator.api.dom.xml.Attribute; 8 | 9 | import lombok.AccessLevel; 10 | import lombok.Getter; 11 | import lombok.NoArgsConstructor; 12 | import lombok.Setter; 13 | import lombok.extern.slf4j.Slf4j; 14 | 15 | @NoArgsConstructor 16 | @Getter(AccessLevel.PACKAGE) 17 | @Setter(AccessLevel.PACKAGE) 18 | @Slf4j 19 | public class RenameProperties { 20 | 21 | private static final String DOT = "."; 22 | 23 | private boolean enabled; 24 | 25 | private String subPpackage; 26 | private String classSuffix; 27 | 28 | private String originalType; 29 | private String newType; 30 | 31 | public void validate(String theSubPpackage, String theClassSuffix) { 32 | enabled = theSubPpackage != null || theClassSuffix != null; 33 | 34 | if (enabled) { 35 | if (theSubPpackage == null) { 36 | subPpackage = StringUtils.EMPTY; 37 | } else if (!theSubPpackage.startsWith(DOT)) { 38 | subPpackage = DOT + theSubPpackage; 39 | } else { 40 | subPpackage = theSubPpackage; 41 | } 42 | 43 | classSuffix = theClassSuffix == null ? StringUtils.EMPTY : theClassSuffix; 44 | } 45 | } 46 | 47 | public String setTypes(String theOriginalType) { 48 | if (enabled) { 49 | this.originalType = theOriginalType; 50 | int lastDot = originalType.lastIndexOf(DOT); 51 | newType = originalType.substring(0, lastDot) + subPpackage + originalType.substring(lastDot) + classSuffix; 52 | log.debug("replace type [{}][{}]", originalType, newType); 53 | return newType; 54 | } 55 | 56 | return theOriginalType; 57 | } 58 | 59 | public FullyQualifiedJavaType renameType(FullyQualifiedJavaType theJavaType) { 60 | if (theJavaType.getFullyQualifiedName().contains(newType)) { 61 | log.debug("set new return type: [{}][{}]", newType, originalType); 62 | return new FullyQualifiedJavaType(theJavaType.getFullyQualifiedName().replace(newType, originalType)); 63 | } else { 64 | return theJavaType; 65 | } 66 | } 67 | 68 | public Attribute renameAttribute(Attribute attribute) { 69 | if (newType.equals(attribute.getValue())) { 70 | log.debug("set new model attribute: [{}][{}][{}]", attribute.getName(), newType, originalType); 71 | return new Attribute(attribute.getName(), originalType); 72 | } else { 73 | return attribute; 74 | } 75 | } 76 | 77 | public void renameAnnotations(List lines) { 78 | if (lines != null) { 79 | for (int i = 0; i < lines.size(); i++) { 80 | String line = lines.get(i); 81 | while (line.contains(newType)) { 82 | line = line.replace(newType, originalType); 83 | log.debug("set new annotation line: [{}] -> [{}]", lines.get(i), line); 84 | lines.set(i, line); 85 | } 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/test/java/com/github/dcendents/mybatis/generator/plugin/annotation/AddClassAnnotationsPluginTest.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.annotation; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.Matchers.eq; 5 | import static org.mockito.Mockito.verify; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.mockito.Mock; 14 | import org.mockito.runners.MockitoJUnitRunner; 15 | import org.mybatis.generator.api.dom.java.TopLevelClass; 16 | 17 | /** 18 | * Tests for the class AddClassAnnotationsPlugin. 19 | */ 20 | @RunWith(MockitoJUnitRunner.class) 21 | public class AddClassAnnotationsPluginTest { 22 | 23 | private AddClassAnnotationsPlugin plugin; 24 | 25 | @Mock 26 | private TopLevelClass topLevelClass; 27 | 28 | @Before 29 | public void init() { 30 | plugin = new AddClassAnnotationsPlugin(); 31 | } 32 | 33 | @Test 34 | public void shouldBeInvalidWithoutAnyPropertyConfigured() { 35 | // Given 36 | 37 | // When 38 | List warnings = new ArrayList<>(); 39 | boolean ok = plugin.validate(warnings); 40 | 41 | // Then 42 | assertThat(ok).isFalse(); 43 | assertThat(warnings).hasSize(2); 44 | } 45 | 46 | @Test 47 | public void shouldBeInvalidWithOnlyTheClassConfigured() { 48 | // Given 49 | plugin.getProperties().put(AddClassAnnotationsPlugin.ANNOTATION_CLASS, Test.class.getName()); 50 | 51 | // When 52 | List warnings = new ArrayList<>(); 53 | boolean ok = plugin.validate(warnings); 54 | 55 | // Then 56 | assertThat(ok).isFalse(); 57 | assertThat(warnings).hasSize(1); 58 | } 59 | 60 | @Test 61 | public void shouldBeInvalidWithOnlyTheAnnotationConfigured() { 62 | // Given 63 | plugin.getProperties().put(AddClassAnnotationsPlugin.ANNOTATION_STRING, "@Test"); 64 | 65 | // When 66 | List warnings = new ArrayList<>(); 67 | boolean ok = plugin.validate(warnings); 68 | 69 | // Then 70 | assertThat(ok).isFalse(); 71 | assertThat(warnings).hasSize(1); 72 | } 73 | 74 | @Test 75 | public void shouldBeValidWhenBothPropertiesAreConfigured() { 76 | // Given 77 | plugin.getProperties().put(AddClassAnnotationsPlugin.ANNOTATION_CLASS, Test.class.getName()); 78 | plugin.getProperties().put(AddClassAnnotationsPlugin.ANNOTATION_STRING, "@Test"); 79 | 80 | // When 81 | List warnings = new ArrayList<>(); 82 | boolean ok = plugin.validate(warnings); 83 | 84 | // Then 85 | assertThat(ok).isTrue(); 86 | assertThat(warnings).isEmpty(); 87 | } 88 | 89 | @Test 90 | public void shouldAddTheAnnotation() { 91 | // Given 92 | plugin.getProperties().put(AddClassAnnotationsPlugin.ANNOTATION_CLASS, Test.class.getName()); 93 | plugin.getProperties().put(AddClassAnnotationsPlugin.ANNOTATION_STRING, "@Test"); 94 | 95 | List warnings = new ArrayList<>(); 96 | plugin.validate(warnings); 97 | 98 | // When 99 | boolean ok = plugin.modelBaseRecordClassGenerated(topLevelClass, null); 100 | 101 | // Then 102 | assertThat(ok).isTrue(); 103 | verify(topLevelClass).addImportedType(eq(plugin.getProperties().get(AddClassAnnotationsPlugin.ANNOTATION_CLASS).toString())); 104 | verify(topLevelClass).addAnnotation(eq(plugin.getProperties().get(AddClassAnnotationsPlugin.ANNOTATION_STRING).toString())); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/github/dcendents/mybatis/generator/plugin/locking/OptimisticLockingPlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.locking; 2 | 3 | import java.util.List; 4 | import java.util.regex.Pattern; 5 | 6 | import lombok.NoArgsConstructor; 7 | 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.mybatis.generator.api.IntrospectedColumn; 10 | import org.mybatis.generator.api.IntrospectedTable; 11 | import org.mybatis.generator.api.PluginAdapter; 12 | import org.mybatis.generator.api.dom.java.Interface; 13 | import org.mybatis.generator.api.dom.java.Method; 14 | import org.mybatis.generator.api.dom.java.TopLevelClass; 15 | 16 | import static org.mybatis.generator.internal.util.StringUtility.stringHasValue; 17 | 18 | /** 19 | * Mybatis generator plugin to add update statements with optimistic locking. 20 | */ 21 | @NoArgsConstructor 22 | public class OptimisticLockingPlugin extends PluginAdapter { 23 | public static final String TABLE_NAME = "fullyQualifiedTableName"; 24 | public static final String LOCK_COLUMN = "lockColumn"; 25 | public static final String LOCK_COLUMN_FUNCTION = "lockColumnFunction"; 26 | 27 | private String tableName; 28 | private String lockColumn; 29 | private String lockColumnFunction; 30 | 31 | static final String METHOD_SUFFIX = "WithOptimisticLocking"; 32 | 33 | @Override 34 | public boolean validate(List warnings) { 35 | tableName = properties.getProperty(TABLE_NAME); 36 | lockColumn = properties.getProperty(LOCK_COLUMN); 37 | lockColumnFunction = properties.getProperty(LOCK_COLUMN_FUNCTION); 38 | 39 | String warning = "Property %s not set for plugin %s"; 40 | if (!stringHasValue(tableName)) { 41 | warnings.add(String.format(warning, TABLE_NAME, this.getClass().getSimpleName())); 42 | } 43 | if (!stringHasValue(lockColumn)) { 44 | warnings.add(String.format(warning, LOCK_COLUMN, this.getClass().getSimpleName())); 45 | } 46 | 47 | if (StringUtils.isBlank(lockColumnFunction)) { 48 | lockColumnFunction = lockColumn; 49 | } 50 | 51 | return stringHasValue(tableName) && stringHasValue(lockColumn); 52 | } 53 | 54 | boolean tableMatches(IntrospectedTable introspectedTable) { 55 | return tableName.equals(introspectedTable.getFullyQualifiedTableNameAtRuntime()) 56 | || Pattern.matches(tableName, introspectedTable.getFullyQualifiedTableNameAtRuntime()); 57 | } 58 | 59 | @Override 60 | public boolean clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 61 | if (tableMatches(introspectedTable)) { 62 | Method withLock = addMethod(method, introspectedTable); 63 | interfaze.addMethod(withLock); 64 | } 65 | 66 | return true; 67 | } 68 | 69 | @Override 70 | public boolean clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 71 | if (tableMatches(introspectedTable)) { 72 | Method withLock = addMethod(method, introspectedTable); 73 | topLevelClass.addMethod(withLock); 74 | } 75 | 76 | return true; 77 | } 78 | 79 | Method addMethod(Method method, IntrospectedTable introspectedTable) { 80 | IntrospectedColumn column = getColumn(introspectedTable); 81 | 82 | Method withLock = new Method(method); 83 | withLock.setName(method.getName() + METHOD_SUFFIX); 84 | 85 | withLock.getAnnotations().clear(); 86 | 87 | for (String line : method.getAnnotations()) { 88 | if (line.matches("\\s*\".*\"\\s*")) { 89 | withLock.getAnnotations().add(line + ","); 90 | 91 | String typeHandler = column.getTypeHandler() != null ? String.format(",typeHandler=%s", column.getTypeHandler()) : ""; 92 | withLock.getAnnotations().add(String.format(" \"and %1$s = #{%2$s,jdbcType=%3$s%4$s}\"", lockColumnFunction, 93 | column.getJavaProperty(), column.getJdbcTypeName(), typeHandler)); 94 | } else { 95 | withLock.getAnnotations().add(line); 96 | } 97 | } 98 | 99 | return withLock; 100 | } 101 | 102 | IntrospectedColumn getColumn(IntrospectedTable introspectedTable) { 103 | for (IntrospectedColumn column : introspectedTable.getAllColumns()) { 104 | if (lockColumn.equals(column.getActualColumnName())) { 105 | return column; 106 | } 107 | } 108 | 109 | return null; 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/test/java/com/github/dcendents/mybatis/generator/plugin/dynamic/sql/DynamicSqlPluginTest.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.dynamic.sql; 2 | 3 | import static org.assertj.core.api.BDDAssertions.then; 4 | import static org.mockito.BDDMockito.given; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.List; 9 | import java.util.Properties; 10 | 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | import org.junit.runner.RunWith; 14 | import org.mockito.Mock; 15 | import org.mockito.runners.MockitoJUnitRunner; 16 | import org.mybatis.generator.api.CommentGenerator; 17 | import org.mybatis.generator.api.FullyQualifiedTable; 18 | import org.mybatis.generator.api.GeneratedJavaFile; 19 | import org.mybatis.generator.api.IntrospectedColumn; 20 | import org.mybatis.generator.api.IntrospectedTable; 21 | import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; 22 | import org.mybatis.generator.config.Context; 23 | import org.mybatis.generator.config.JavaClientGeneratorConfiguration; 24 | 25 | /** 26 | * Tests for the class DynamicSqlPlugin. 27 | */ 28 | @RunWith(MockitoJUnitRunner.class) 29 | public class DynamicSqlPluginTest { 30 | 31 | private DynamicSqlPlugin plugin; 32 | 33 | @Mock 34 | private IntrospectedTable table; 35 | @Mock 36 | private FullyQualifiedTable tableName; 37 | 38 | @Mock 39 | private IntrospectedColumn column1; 40 | @Mock 41 | private IntrospectedColumn column2; 42 | 43 | @Mock 44 | private Context context; 45 | @Mock 46 | private CommentGenerator commentGenerator; 47 | @Mock 48 | private JavaClientGeneratorConfiguration javaClientGeneratorConfiguration; 49 | 50 | @Before 51 | public void init() { 52 | given(context.getCommentGenerator()).willReturn(commentGenerator); 53 | given(context.getJavaClientGeneratorConfiguration()).willReturn(javaClientGeneratorConfiguration); 54 | 55 | given(javaClientGeneratorConfiguration.getTargetProject()).willReturn("src/main/java"); 56 | 57 | given(tableName.getAlias()).willReturn("alias"); 58 | 59 | given(table.getFullyQualifiedTable()).willReturn(tableName); 60 | given(table.getFullyQualifiedTableNameAtRuntime()).willReturn("table_name"); 61 | given(table.getMyBatis3JavaMapperType()).willReturn("some.package.JavaMapperType"); 62 | given(table.getBaseRecordType()).willReturn("some.package.BaseRecordType"); 63 | given(table.getAllColumns()).willReturn(Arrays.asList(column1, column2)); 64 | 65 | given(column1.getFullyQualifiedJavaType()).willReturn(new FullyQualifiedJavaType("int")); 66 | given(column1.getTableAlias()).willReturn("a"); 67 | 68 | given(column2.getFullyQualifiedJavaType()).willReturn(new FullyQualifiedJavaType("java.util.Calendar")); 69 | given(column2.getTypeHandler()).willReturn("type.Handler"); 70 | 71 | plugin = new DynamicSqlPlugin(); 72 | plugin.setContext(context); 73 | 74 | Properties properties = new Properties(); 75 | properties.put(DynamicSqlPlugin.TABLE_CLASS_SUFFIX, "Table"); 76 | properties.put(DynamicSqlPlugin.ADD_ALIASED_COLUMNS, "true"); 77 | properties.put(DynamicSqlPlugin.ADD_TABLE_ALIAS, "true"); 78 | properties.put("table_name.otherAlias", "ot"); 79 | plugin.setProperties(properties); 80 | plugin.validate(new ArrayList()); 81 | } 82 | 83 | @Test 84 | public void shouldBeValidWithoutAnyPropertyConfigured() { 85 | // Given 86 | plugin = new DynamicSqlPlugin(); 87 | 88 | // When 89 | List warnings = new ArrayList<>(); 90 | boolean ok = plugin.validate(warnings); 91 | 92 | // Then 93 | then(ok).isTrue(); 94 | then(warnings).isEmpty(); 95 | } 96 | 97 | @Test 98 | public void shouldBeValidWithPropertiesConfigured() { 99 | // Given 100 | 101 | // When 102 | List warnings = new ArrayList<>(); 103 | boolean ok = plugin.validate(warnings); 104 | 105 | // Then 106 | then(ok).isTrue(); 107 | then(warnings).isEmpty(); 108 | } 109 | 110 | @Test 111 | public void shouldGenerateAdditionalFile() throws Exception { 112 | // Given 113 | 114 | // When 115 | List files = plugin.contextGenerateAdditionalJavaFiles(table); 116 | 117 | // Then 118 | then(files).hasSize(1); 119 | } 120 | 121 | @Test 122 | public void shouldGenerateAdditionalFileEvenWhenTableHasNoColumns() throws Exception { 123 | // Given 124 | given(table.getAllColumns()).willReturn(new ArrayList()); 125 | 126 | // When 127 | List files = plugin.contextGenerateAdditionalJavaFiles(table); 128 | 129 | // Then 130 | then(files).hasSize(1); 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/test/java/com/github/dcendents/mybatis/generator/plugin/model/AlterModelPluginTest.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.model; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.BDDMockito.given; 5 | import static org.mockito.Matchers.any; 6 | import static org.mockito.Mockito.times; 7 | import static org.mockito.Mockito.verify; 8 | 9 | import java.io.Serializable; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | import org.junit.runner.RunWith; 16 | import org.mockito.ArgumentCaptor; 17 | import org.mockito.Mock; 18 | import org.mockito.runners.MockitoJUnitRunner; 19 | import org.mybatis.generator.api.IntrospectedTable; 20 | import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; 21 | import org.mybatis.generator.api.dom.java.TopLevelClass; 22 | 23 | /** 24 | * Tests for the class AlterModelPlugin. 25 | */ 26 | @RunWith(MockitoJUnitRunner.class) 27 | public class AlterModelPluginTest { 28 | 29 | private AlterModelPlugin plugin; 30 | 31 | @Mock 32 | private IntrospectedTable introspectedTable; 33 | @Mock 34 | private TopLevelClass topLevelClass; 35 | 36 | private static final String TABLE_NAME = "table_name"; 37 | 38 | @Before 39 | public void init() throws Exception { 40 | plugin = new AlterModelPlugin(); 41 | plugin.getProperties().put(AlterModelPlugin.TABLE_NAME, TABLE_NAME); 42 | plugin.getProperties().put(AlterModelPlugin.ADD_INTERFACES, Serializable.class.getName()); 43 | plugin.validate(new ArrayList()); 44 | } 45 | 46 | @Test 47 | public void shouldBeInvalidWithoutAnyPropertyConfigured() { 48 | // Given 49 | AlterModelPlugin instance = new AlterModelPlugin(); 50 | 51 | // When 52 | List warnings = new ArrayList<>(); 53 | boolean ok = instance.validate(warnings); 54 | 55 | // Then 56 | assertThat(ok).isFalse(); 57 | assertThat(warnings).hasSize(2); 58 | } 59 | 60 | @Test 61 | public void shouldBeInvalidWithOnlyTheTableNameConfigured() { 62 | // Given 63 | AlterModelPlugin instance = new AlterModelPlugin(); 64 | instance.getProperties().put(AlterModelPlugin.TABLE_NAME, TABLE_NAME); 65 | 66 | // When 67 | List warnings = new ArrayList<>(); 68 | boolean ok = instance.validate(warnings); 69 | 70 | // Then 71 | assertThat(ok).isFalse(); 72 | assertThat(warnings).hasSize(1); 73 | } 74 | 75 | @Test 76 | public void shouldBeInvalidWithOnlyTheInterfacesConfigured() { 77 | // Given 78 | AlterModelPlugin instance = new AlterModelPlugin(); 79 | instance.getProperties().put(AlterModelPlugin.ADD_INTERFACES, Serializable.class.getName()); 80 | 81 | // When 82 | List warnings = new ArrayList<>(); 83 | boolean ok = instance.validate(warnings); 84 | 85 | // Then 86 | assertThat(ok).isFalse(); 87 | assertThat(warnings).hasSize(1); 88 | } 89 | 90 | @Test 91 | public void shouldBeValidWhenBothPropertiesAreConfigured() { 92 | // Given 93 | AlterModelPlugin instance = new AlterModelPlugin(); 94 | instance.getProperties().put(AlterModelPlugin.TABLE_NAME, TABLE_NAME); 95 | instance.getProperties().put(AlterModelPlugin.ADD_INTERFACES, Serializable.class.getName()); 96 | 97 | // When 98 | List warnings = new ArrayList<>(); 99 | boolean ok = instance.validate(warnings); 100 | 101 | // Then 102 | assertThat(ok).isTrue(); 103 | assertThat(warnings).isEmpty(); 104 | } 105 | 106 | @Test 107 | public void shouldNotModifyModelBaseRecordClassIfTableDoesNotMatch() throws Exception { 108 | // Given 109 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn("wrong_name"); 110 | 111 | // When 112 | boolean ok = plugin.modelBaseRecordClassGenerated(topLevelClass, introspectedTable); 113 | 114 | // Then 115 | assertThat(ok).isTrue(); 116 | verify(topLevelClass, times(0)).addImportedType(any(FullyQualifiedJavaType.class)); 117 | verify(topLevelClass, times(0)).addSuperInterface(any(FullyQualifiedJavaType.class)); 118 | } 119 | 120 | @Test 121 | public void shouldAddInterfacesToModelBaseRecordClass() throws Exception { 122 | // Given 123 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 124 | 125 | // When 126 | boolean ok = plugin.modelBaseRecordClassGenerated(topLevelClass, introspectedTable); 127 | 128 | // Then 129 | assertThat(ok).isTrue(); 130 | 131 | ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(FullyQualifiedJavaType.class); 132 | 133 | verify(topLevelClass).addImportedType(typeCaptor.capture()); 134 | FullyQualifiedJavaType importedType = typeCaptor.getValue(); 135 | verify(topLevelClass).addSuperInterface(typeCaptor.capture()); 136 | FullyQualifiedJavaType interfaceType = typeCaptor.getValue(); 137 | 138 | assertThat(importedType).isNotNull(); 139 | assertThat(interfaceType).isNotNull(); 140 | 141 | assertThat(importedType).isSameAs(interfaceType); 142 | assertThat(importedType.getFullyQualifiedName()).isEqualTo(Serializable.class.getName()); 143 | } 144 | 145 | @Test 146 | public void shouldAcceptRegexValueForTableName() throws Exception { 147 | // Given 148 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 149 | plugin.getProperties().put(AlterModelPlugin.TABLE_NAME, TABLE_NAME.substring(0, 3) + ".*"); 150 | plugin.validate(new ArrayList()); 151 | 152 | // When 153 | boolean ok = plugin.modelBaseRecordClassGenerated(topLevelClass, introspectedTable); 154 | 155 | // Then 156 | assertThat(ok).isTrue(); 157 | verify(topLevelClass).addImportedType(any(FullyQualifiedJavaType.class)); 158 | verify(topLevelClass).addSuperInterface(any(FullyQualifiedJavaType.class)); 159 | } 160 | 161 | } 162 | -------------------------------------------------------------------------------- /src/main/java/com/github/dcendents/mybatis/generator/plugin/client/AlterResultMapPlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.client; 2 | 3 | import java.util.List; 4 | import java.util.regex.Pattern; 5 | 6 | import lombok.NoArgsConstructor; 7 | 8 | import org.mybatis.generator.api.IntrospectedTable; 9 | import org.mybatis.generator.api.PluginAdapter; 10 | import org.mybatis.generator.api.dom.java.Interface; 11 | import org.mybatis.generator.api.dom.java.Method; 12 | import org.mybatis.generator.api.dom.java.TopLevelClass; 13 | import org.mybatis.generator.api.dom.xml.Attribute; 14 | import org.mybatis.generator.api.dom.xml.XmlElement; 15 | 16 | import static org.mybatis.generator.internal.util.StringUtility.stringHasValue; 17 | 18 | /** 19 | * Mybatis generator plugin to alter the id of the result map returned by all the select methods. 20 | */ 21 | @NoArgsConstructor 22 | public class AlterResultMapPlugin extends PluginAdapter { 23 | public static final String TABLE_NAME = "fullyQualifiedTableName"; 24 | public static final String RESULT_MAP_ID = "resultMapId"; 25 | 26 | private String tableName; 27 | private String resultMapId; 28 | 29 | static final String RESULT_MAP_ATTRIBUTE = "resultMap"; 30 | static final Pattern ANNOTATION_PATTERN = Pattern.compile("@ResultMap\\(\".*\"\\)"); 31 | static final String ANNOTATION_FORMAT = "@ResultMap(\"%s\")"; 32 | 33 | @Override 34 | public boolean validate(List warnings) { 35 | tableName = properties.getProperty(TABLE_NAME); 36 | resultMapId = properties.getProperty(RESULT_MAP_ID); 37 | 38 | String warning = "Property %s not set for plugin %s"; 39 | if (!stringHasValue(tableName)) { 40 | warnings.add(String.format(warning, TABLE_NAME, this.getClass().getSimpleName())); 41 | } 42 | if (!stringHasValue(resultMapId)) { 43 | warnings.add(String.format(warning, RESULT_MAP_ID, this.getClass().getSimpleName())); 44 | } 45 | 46 | return stringHasValue(tableName) && stringHasValue(resultMapId); 47 | } 48 | 49 | private boolean tableMatches(IntrospectedTable introspectedTable) { 50 | return tableName.equals(introspectedTable.getFullyQualifiedTableNameAtRuntime()); 51 | } 52 | 53 | void renameResultMapAttribute(XmlElement element, IntrospectedTable introspectedTable) { 54 | if (tableMatches(introspectedTable)) { 55 | List attributes = element.getAttributes(); 56 | 57 | for (int i = 0; i < attributes.size(); i++) { 58 | Attribute attribute = attributes.get(i); 59 | if (RESULT_MAP_ATTRIBUTE.equals(attribute.getName())) { 60 | Attribute newAtt = new Attribute(RESULT_MAP_ATTRIBUTE, resultMapId); 61 | attributes.remove(i); 62 | attributes.add(newAtt); 63 | break; 64 | } 65 | } 66 | } 67 | } 68 | 69 | void renameResultMapAttribute(Method method, IntrospectedTable introspectedTable) { 70 | if (tableMatches(introspectedTable)) { 71 | List annotations = method.getAnnotations(); 72 | 73 | for (int i = 0; i < annotations.size(); i++) { 74 | String annotation = annotations.get(i); 75 | if (ANNOTATION_PATTERN.matcher(annotation).matches()) { 76 | String newAnnotation = String.format(ANNOTATION_FORMAT, resultMapId); 77 | annotations.remove(i); 78 | annotations.add(newAnnotation); 79 | break; 80 | } 81 | } 82 | } 83 | } 84 | 85 | @Override 86 | public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element, 87 | IntrospectedTable introspectedTable) { 88 | renameResultMapAttribute(element, introspectedTable); 89 | 90 | return true; 91 | } 92 | 93 | @Override 94 | public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(XmlElement element, 95 | IntrospectedTable introspectedTable) { 96 | renameResultMapAttribute(element, introspectedTable); 97 | 98 | return true; 99 | } 100 | 101 | @Override 102 | public boolean sqlMapSelectByPrimaryKeyElementGenerated(XmlElement element, IntrospectedTable introspectedTable) { 103 | renameResultMapAttribute(element, introspectedTable); 104 | 105 | return true; 106 | } 107 | 108 | @Override 109 | public boolean sqlMapSelectAllElementGenerated(XmlElement element, IntrospectedTable introspectedTable) { 110 | renameResultMapAttribute(element, introspectedTable); 111 | 112 | return true; 113 | } 114 | 115 | @Override 116 | public boolean clientSelectByExampleWithBLOBsMethodGenerated(Method method, Interface interfaze, 117 | IntrospectedTable introspectedTable) { 118 | renameResultMapAttribute(method, introspectedTable); 119 | 120 | return true; 121 | } 122 | 123 | @Override 124 | public boolean clientSelectByExampleWithBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, 125 | IntrospectedTable introspectedTable) { 126 | renameResultMapAttribute(method, introspectedTable); 127 | 128 | return true; 129 | } 130 | 131 | @Override 132 | public boolean clientSelectByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, 133 | IntrospectedTable introspectedTable) { 134 | renameResultMapAttribute(method, introspectedTable); 135 | 136 | return true; 137 | } 138 | 139 | @Override 140 | public boolean clientSelectByExampleWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, 141 | IntrospectedTable introspectedTable) { 142 | renameResultMapAttribute(method, introspectedTable); 143 | 144 | return true; 145 | } 146 | 147 | @Override 148 | public boolean clientSelectByPrimaryKeyMethodGenerated(Method method, Interface interfaze, 149 | IntrospectedTable introspectedTable) { 150 | renameResultMapAttribute(method, introspectedTable); 151 | 152 | return true; 153 | } 154 | 155 | @Override 156 | public boolean clientSelectByPrimaryKeyMethodGenerated(Method method, TopLevelClass topLevelClass, 157 | IntrospectedTable introspectedTable) { 158 | renameResultMapAttribute(method, introspectedTable); 159 | 160 | return true; 161 | } 162 | 163 | @Override 164 | public boolean clientSelectAllMethodGenerated(Method method, Interface interfaze, 165 | IntrospectedTable introspectedTable) { 166 | renameResultMapAttribute(method, introspectedTable); 167 | 168 | return true; 169 | } 170 | 171 | @Override 172 | public boolean clientSelectAllMethodGenerated(Method method, TopLevelClass topLevelClass, 173 | IntrospectedTable introspectedTable) { 174 | renameResultMapAttribute(method, introspectedTable); 175 | 176 | return true; 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /src/test/java/com/github/dcendents/mybatis/generator/plugin/subpackage/RenamePropertiesTest.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.subpackage; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | import org.junit.runner.RunWith; 12 | import org.mockito.runners.MockitoJUnitRunner; 13 | import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; 14 | import org.mybatis.generator.api.dom.xml.Attribute; 15 | 16 | /** 17 | * Tests for the class RenameProperties. 18 | */ 19 | @RunWith(MockitoJUnitRunner.class) 20 | public class RenamePropertiesTest { 21 | 22 | private static final String SUB_PACKAGE = ".sub"; 23 | private static final String SUFFIX = "Suffix"; 24 | private static final String ORIGINAL_TYPE = "some.package.Type"; 25 | private static final String NEW_TYPE = "some.package.sub.TypeSuffix"; 26 | 27 | private RenameProperties brandNew; 28 | private RenameProperties disabled; 29 | private RenameProperties initializedBoth; 30 | private RenameProperties allSet; 31 | 32 | @Before 33 | public void init() throws Exception { 34 | brandNew = new RenameProperties(); 35 | 36 | disabled = new RenameProperties(); 37 | disabled.setEnabled(false); 38 | 39 | initializedBoth = new RenameProperties(); 40 | initializedBoth.setEnabled(true); 41 | initializedBoth.setSubPpackage(SUB_PACKAGE); 42 | initializedBoth.setClassSuffix(SUFFIX); 43 | 44 | allSet = new RenameProperties(); 45 | allSet.setEnabled(true); 46 | allSet.setSubPpackage(SUB_PACKAGE); 47 | allSet.setClassSuffix(SUFFIX); 48 | allSet.setOriginalType(ORIGINAL_TYPE); 49 | allSet.setNewType(NEW_TYPE); 50 | } 51 | 52 | @Test 53 | public void shouldBeDisabledWhenBothParametersAreNull() throws Exception { 54 | // Given 55 | 56 | // When 57 | brandNew.validate(null, null); 58 | 59 | // Then 60 | assertThat(brandNew.isEnabled()).isFalse(); 61 | } 62 | 63 | @Test 64 | public void shouldInitializeSubPAckageToEmptyStringWhenNull() throws Exception { 65 | // Given 66 | 67 | // When 68 | brandNew.validate(null, "suffix"); 69 | 70 | // Then 71 | assertThat(brandNew.isEnabled()).isTrue(); 72 | assertThat(brandNew.getSubPpackage()).isEqualTo(StringUtils.EMPTY); 73 | } 74 | 75 | @Test 76 | public void shouldInitializeClassSuffixToEmptyStringWhenNull() throws Exception { 77 | RenameProperties props = new RenameProperties(); 78 | 79 | // Given 80 | 81 | // When 82 | props.validate("package", null); 83 | 84 | // Then 85 | assertThat(props.isEnabled()).isTrue(); 86 | assertThat(props.getClassSuffix()).isEqualTo(StringUtils.EMPTY); 87 | } 88 | 89 | @Test 90 | public void shouldPrefixSubPAckageWithDotWhenMissing() throws Exception { 91 | // Given 92 | 93 | // When 94 | brandNew.validate("package", "suffix"); 95 | 96 | // Then 97 | assertThat(brandNew.isEnabled()).isTrue(); 98 | assertThat(brandNew.getSubPpackage()).isEqualTo(".package"); 99 | } 100 | 101 | @Test 102 | public void shouldNotPrefixSubPAckageWithDotWhenPresent() throws Exception { 103 | // Given 104 | 105 | // When 106 | brandNew.validate(".package", "suffix"); 107 | 108 | // Then 109 | assertThat(brandNew.isEnabled()).isTrue(); 110 | assertThat(brandNew.getSubPpackage()).isEqualTo(".package"); 111 | } 112 | 113 | @Test 114 | public void shouldReturnOriginalTypeWhenDisabled() throws Exception { 115 | // Given 116 | String type = "type"; 117 | 118 | // When 119 | String renamed = disabled.setTypes(type); 120 | 121 | // Then 122 | assertThat(renamed).isSameAs(type); 123 | } 124 | 125 | @Test 126 | public void shouldRenameType() throws Exception { 127 | // Given 128 | 129 | // When 130 | String renamed = initializedBoth.setTypes(ORIGINAL_TYPE); 131 | 132 | // Then 133 | assertThat(renamed).isEqualTo(NEW_TYPE); 134 | assertThat(initializedBoth.getOriginalType()).isEqualTo(ORIGINAL_TYPE); 135 | assertThat(initializedBoth.getNewType()).isEqualTo(renamed); 136 | } 137 | 138 | @Test 139 | public void shouldNotRenameTypesThatDontMatch() throws Exception { 140 | // Given 141 | String type = "some.other.Type"; 142 | FullyQualifiedJavaType javaType = new FullyQualifiedJavaType(type); 143 | 144 | // When 145 | FullyQualifiedJavaType renamed = allSet.renameType(javaType); 146 | 147 | // Then 148 | assertThat(renamed).isSameAs(javaType); 149 | } 150 | 151 | @Test 152 | public void shouldRenameTypeThatMatch() throws Exception { 153 | // Given 154 | FullyQualifiedJavaType javaType = new FullyQualifiedJavaType(NEW_TYPE); 155 | 156 | // When 157 | FullyQualifiedJavaType renamed = allSet.renameType(javaType); 158 | 159 | // Then 160 | assertThat(renamed).isNotNull(); 161 | assertThat(renamed.getFullyQualifiedName()).isEqualTo(ORIGINAL_TYPE); 162 | } 163 | 164 | @Test 165 | public void shouldNotRenameAttributesThatDontMatch() throws Exception { 166 | // Given 167 | String type = "some.other.Type"; 168 | Attribute attribute = new Attribute("name", type); 169 | 170 | // When 171 | Attribute renamed = allSet.renameAttribute(attribute); 172 | 173 | // Then 174 | assertThat(renamed).isSameAs(attribute); 175 | } 176 | 177 | @Test 178 | public void shouldRenameAttributeThatMatch() throws Exception { 179 | // Given 180 | Attribute attribute = new Attribute("name", NEW_TYPE); 181 | 182 | // When 183 | Attribute renamed = allSet.renameAttribute(attribute); 184 | 185 | // Then 186 | assertThat(renamed).isNotNull(); 187 | assertThat(renamed.getValue()).isEqualTo(ORIGINAL_TYPE); 188 | } 189 | 190 | @Test 191 | public void shouldNotRenameNullAnnotations() throws Exception { 192 | // Given 193 | List annotations = null; 194 | 195 | // When 196 | allSet.renameAnnotations(annotations); 197 | 198 | // Then 199 | } 200 | 201 | @Test 202 | public void shouldNotRenameAnnotationsThatDontMatch() throws Exception { 203 | // Given 204 | String type = "some.other.Type"; 205 | List annotations = new ArrayList<>(); 206 | annotations.add("@MultiLine({"); 207 | annotations.add("\" line1\","); 208 | annotations.add("\" line2 " + type + "\","); 209 | annotations.add("\" line3\","); 210 | annotations.add("})"); 211 | annotations.add("@SingleLine(\"" + type + "\")"); 212 | final int annotationsSize = annotations.size(); 213 | 214 | // When 215 | allSet.renameAnnotations(annotations); 216 | 217 | // Then 218 | assertThat(annotations).hasSize(annotationsSize); 219 | for (String annotation : annotations) { 220 | assertThat(annotation).doesNotContain(ORIGINAL_TYPE); 221 | } 222 | assertThat(annotations.get(2)).contains(type); 223 | assertThat(annotations.get(5)).contains(type); 224 | } 225 | 226 | @Test 227 | public void shouldRenameAnnotationsThatMatch() throws Exception { 228 | // Given 229 | List annotations = new ArrayList<>(); 230 | annotations.add("@MultiLine({"); 231 | annotations.add("\" line1\","); 232 | annotations.add("\" line2 " + NEW_TYPE + "\","); 233 | annotations.add("\" line3\","); 234 | annotations.add("})"); 235 | annotations.add("@SingleLine(\"" + NEW_TYPE + "\")"); 236 | final int annotationsSize = annotations.size(); 237 | 238 | // When 239 | allSet.renameAnnotations(annotations); 240 | 241 | // Then 242 | assertThat(annotations).hasSize(annotationsSize); 243 | for (String annotation : annotations) { 244 | assertThat(annotation).doesNotContain(NEW_TYPE); 245 | } 246 | assertThat(annotations.get(2)).contains(ORIGINAL_TYPE); 247 | assertThat(annotations.get(5)).contains(ORIGINAL_TYPE); 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /src/main/java/com/github/dcendents/mybatis/generator/plugin/wrap/WrapObjectPlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.wrap; 2 | 3 | import static org.mybatis.generator.internal.util.StringUtility.stringHasValue; 4 | 5 | import java.util.HashMap; 6 | import java.util.HashSet; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | import lombok.AccessLevel; 12 | import lombok.Getter; 13 | import lombok.NoArgsConstructor; 14 | 15 | import org.apache.commons.lang3.StringUtils; 16 | import org.mybatis.generator.api.IntrospectedColumn; 17 | import org.mybatis.generator.api.IntrospectedTable; 18 | import org.mybatis.generator.api.PluginAdapter; 19 | import org.mybatis.generator.api.dom.java.Field; 20 | import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; 21 | import org.mybatis.generator.api.dom.java.JavaVisibility; 22 | import org.mybatis.generator.api.dom.java.Method; 23 | import org.mybatis.generator.api.dom.java.TopLevelClass; 24 | 25 | @NoArgsConstructor 26 | public class WrapObjectPlugin extends PluginAdapter { 27 | public static final String TABLE_NAME = "fullyQualifiedTableName"; 28 | public static final String OBJECT_CLASS = "objectClass"; 29 | public static final String OBJECT_FIELD_NAME = "objectFieldName"; 30 | public static final String INCLUDES = "includes"; 31 | public static final String EXCLUDES = "excludes"; 32 | 33 | private String tableName; 34 | private Class objectClass; 35 | 36 | @Getter(AccessLevel.PACKAGE) 37 | private Set includes = new HashSet<>(); 38 | @Getter(AccessLevel.PACKAGE) 39 | private Set excludes = new HashSet<>(); 40 | 41 | @Getter(AccessLevel.PACKAGE) 42 | private String objectFieldName; 43 | 44 | @Getter(AccessLevel.PACKAGE) 45 | private Set gettersToWrap = new HashSet<>(); 46 | @Getter(AccessLevel.PACKAGE) 47 | private Set settersToWrap = new HashSet<>(); 48 | 49 | @Getter(AccessLevel.PACKAGE) 50 | private Map wrappedGetters = new HashMap<>(); 51 | 52 | @Override 53 | public boolean validate(List warnings) { 54 | tableName = properties.getProperty(TABLE_NAME); 55 | String objectClassName = properties.getProperty(OBJECT_CLASS); 56 | 57 | String warning = "Property %s not set for plugin %s"; 58 | if (!stringHasValue(tableName)) { 59 | warnings.add(String.format(warning, TABLE_NAME, this.getClass().getSimpleName())); 60 | } 61 | if (!stringHasValue(objectClassName)) { 62 | warnings.add(String.format(warning, OBJECT_CLASS, this.getClass().getSimpleName())); 63 | } else { 64 | try { 65 | objectClass = Class.forName(objectClassName); 66 | } catch (ClassNotFoundException ex) { 67 | warnings.add(String.format("Could not load class %s in plugin %s", objectClassName, this.getClass() 68 | .getSimpleName())); 69 | } 70 | } 71 | 72 | String includesString = properties.getProperty(INCLUDES); 73 | if (stringHasValue(includesString)) { 74 | for (String include : includesString.split(",")) { 75 | includes.add(include.trim()); 76 | } 77 | } 78 | 79 | String excludesString = properties.getProperty(EXCLUDES); 80 | if (stringHasValue(excludesString)) { 81 | for (String exclude : excludesString.split(",")) { 82 | excludes.add(exclude.trim()); 83 | } 84 | } 85 | 86 | objectFieldName = properties.getProperty(OBJECT_FIELD_NAME); 87 | if (!stringHasValue(objectFieldName) && objectClass != null) { 88 | objectFieldName = StringUtils.uncapitalize(objectClass.getSimpleName()); 89 | } 90 | 91 | return stringHasValue(tableName) && objectClass != null; 92 | } 93 | 94 | private boolean tableMatches(IntrospectedTable introspectedTable) { 95 | return tableName.equals(introspectedTable.getFullyQualifiedTableNameAtRuntime()); 96 | } 97 | 98 | @Override 99 | public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 100 | if (tableMatches(introspectedTable)) { 101 | FullyQualifiedJavaType type = new FullyQualifiedJavaType(objectClass.getName()); 102 | Field field = new Field(objectFieldName, type); 103 | field.setVisibility(JavaVisibility.PROTECTED); 104 | field.setInitializationString(String.format("new %s()", objectClass.getSimpleName())); 105 | 106 | field.addJavaDocLine("/**"); 107 | field.addJavaDocLine(" * This field was generated by MyBatis Generator."); 108 | field.addJavaDocLine(" * This field corresponds to the wrapped object."); 109 | field.addJavaDocLine(" *"); 110 | field.addJavaDocLine(" * @mbggenerated"); 111 | field.addJavaDocLine(" */"); 112 | 113 | topLevelClass.addField(field); 114 | topLevelClass.addImportedType(type); 115 | } 116 | 117 | return true; 118 | } 119 | 120 | @Override 121 | public boolean modelFieldGenerated(Field field, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, 122 | IntrospectedTable introspectedTable, ModelClassType modelClassType) { 123 | if (tableMatches(introspectedTable) && wrapField(field)) { 124 | topLevelClass.addImportedType(field.getType()); 125 | return false; 126 | } 127 | 128 | return true; 129 | } 130 | 131 | private boolean wrapField(Field field) { 132 | if (includes.contains(field.getName()) || (includes.isEmpty() && !excludes.contains(field.getName()))) { 133 | return objectClassHasFieldGetter(field); 134 | } 135 | 136 | return false; 137 | } 138 | 139 | private boolean objectClassHasFieldGetter(Field field) { 140 | FullyQualifiedJavaType type = field.getType(); 141 | String prefix = type.isPrimitive() && type.getShortName().equals("boolean") ? "is" : "get"; 142 | 143 | String capitalized = StringUtils.capitalize(field.getName()); 144 | String getterName = prefix + capitalized; 145 | String setterName = "set" + capitalized; 146 | String wrappedGetter = getterName; 147 | 148 | if (hasGetter(getterName)) { 149 | gettersToWrap.add(getterName); 150 | settersToWrap.add(setterName); 151 | wrappedGetters.put(getterName, wrappedGetter); 152 | return true; 153 | } 154 | 155 | // Check for possibility of boolean mismatch field (Boolean/boolean) 156 | if (type.isPrimitive() && type.getShortName().equals("boolean") && hasGetter("get" + capitalized)) { 157 | gettersToWrap.add(getterName); 158 | settersToWrap.add(setterName); 159 | wrappedGetters.put(getterName, "get" + capitalized); 160 | return true; 161 | } else if (!type.isPrimitive() && type.getFullyQualifiedName().equals("java.lang.Boolean") && hasGetter("is" + capitalized)) { 162 | gettersToWrap.add(getterName); 163 | settersToWrap.add(setterName); 164 | wrappedGetters.put(getterName, "is" + capitalized); 165 | return true; 166 | } 167 | 168 | return false; 169 | } 170 | 171 | private boolean hasGetter(String getterName) { 172 | try { 173 | objectClass.getMethod(getterName); 174 | return true; 175 | } catch (NoSuchMethodException ex) { 176 | return false; 177 | } 178 | } 179 | 180 | @Override 181 | public boolean modelGetterMethodGenerated(Method method, TopLevelClass topLevelClass, 182 | IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) { 183 | if (tableMatches(introspectedTable) && gettersToWrap.contains(method.getName())) { 184 | method.getBodyLines().clear(); 185 | method.addBodyLine(String.format("return this.%s.%s();", objectFieldName, wrappedGetters.get(method.getName()))); 186 | } 187 | 188 | return true; 189 | } 190 | 191 | @Override 192 | public boolean modelSetterMethodGenerated(Method method, TopLevelClass topLevelClass, 193 | IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) { 194 | if (tableMatches(introspectedTable) && settersToWrap.contains(method.getName())) { 195 | method.getBodyLines().clear(); 196 | method.addBodyLine(String.format("this.%s.%s(%s);", objectFieldName, method.getName(), method 197 | .getParameters().get(0).getName())); 198 | } 199 | 200 | return true; 201 | } 202 | 203 | } 204 | -------------------------------------------------------------------------------- /src/test/resources/log4j.dtd: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | 69 | 70 | 71 | 74 | 78 | 79 | 80 | 83 | 84 | 85 | 88 | 89 | 90 | 91 | 92 | 93 | 96 | 97 | 98 | 99 | 100 | 103 | 104 | 105 | 109 | 110 | 111 | 112 | 113 | 117 | 118 | 119 | 120 | 124 | 125 | 126 | 127 | 128 | 129 | 134 | 135 | 136 | 137 | 138 | 143 | 144 | 145 | 146 | 148 | 149 | 150 | 152 | 153 | 154 | 157 | 158 | 159 | 160 | 164 | 165 | 166 | 169 | 170 | 171 | 174 | 175 | 176 | 180 | 181 | 182 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 203 | 204 | 205 | 206 | 208 | 209 | 210 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 230 | 231 | 232 | 233 | 234 | 238 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | com.github.dcendents 4 | mybatis-generator-plugins 5 | 1.4-SNAPSHOT 6 | MyBatis Generator Plugins 7 | Set of plugins for the mybatis-generator to further tweak the generated code. 8 | https://github.com/dcendents/mybatis-generator-plugins 9 | 2015 10 | 11 | 12 | Apache License, Version 2.0 13 | http://www.apache.org/licenses/LICENSE-2.0.html 14 | 15 | 16 | 17 | scm:git:https://github.com/dcendents/mybatis-generator-plugins.git 18 | https://github.com/dcendents/mybatis-generator-plugins 19 | HEAD 20 | 21 | 22 | 23 | dcendents 24 | Daniel Beland 25 | dcendents@gmail.com 26 | 27 | 28 | 29 | 1.7.25 30 | 31 | 32 | 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-surefire-plugin 37 | 2.20.1 38 | 39 | 40 | 41 | 42 | 43 | org.apache.maven.plugins 44 | maven-compiler-plugin 45 | 3.7.0 46 | 47 | 1.8 48 | 1.8 49 | 50 | 51 | 52 | org.codehaus.mojo 53 | animal-sniffer-maven-plugin 54 | 1.16 55 | 56 | 57 | check 58 | 59 | check 60 | 61 | 62 | 63 | org.codehaus.mojo.signature 64 | java18 65 | 1.0 66 | 67 | 68 | 69 | 70 | 71 | 72 | org.jacoco 73 | jacoco-maven-plugin 74 | 0.8.0 75 | 76 | 77 | prepare-agent 78 | 79 | prepare-agent 80 | 81 | 82 | 83 | report 84 | 85 | report 86 | 87 | 88 | 89 | 90 | 91 | org.apache.maven.plugins 92 | maven-release-plugin 93 | 2.5.3 94 | 95 | v@{project.version} 96 | false 97 | deploy 98 | true 99 | true 100 | release 101 | 102 | pom.xml 103 | 104 | 105 | 106 | 107 | org.apache.maven.plugins 108 | maven-javadoc-plugin 109 | 3.0.0 110 | 111 | 112 | org.apache.maven.plugins 113 | maven-source-plugin 114 | 3.0.1 115 | 116 | 117 | org.apache.maven.plugins 118 | maven-deploy-plugin 119 | 2.8.2 120 | 121 | 122 | 123 | 124 | 125 | org.mybatis.generator 126 | mybatis-generator-core 127 | 1.3.6 128 | true 129 | 130 | 131 | org.projectlombok 132 | lombok 133 | 1.16.18 134 | provided 135 | 136 | 137 | org.slf4j 138 | slf4j-api 139 | ${slf4j.version} 140 | 141 | 142 | org.slf4j 143 | slf4j-log4j12 144 | ${slf4j.version} 145 | test 146 | 147 | 148 | org.apache.commons 149 | commons-lang3 150 | 3.7 151 | 152 | 153 | junit 154 | junit 155 | 4.12 156 | test 157 | 158 | 159 | org.mockito 160 | mockito-core 161 | 1.10.19 162 | test 163 | 164 | 165 | org.assertj 166 | assertj-core 167 | 2.9.0 168 | test 169 | 170 | 171 | 172 | 173 | bintray 174 | https://api.bintray.com/maven/dcendents/maven/com.github.dcendents:mybatis-generator-plugins 175 | 176 | 177 | 178 | 179 | release 180 | 181 | 182 | 183 | org.apache.maven.plugins 184 | maven-surefire-plugin 185 | 186 | true 187 | 188 | 189 | 190 | org.apache.maven.plugins 191 | maven-gpg-plugin 192 | 1.6 193 | 194 | 195 | sign-artifacts 196 | verify 197 | 198 | sign 199 | 200 | 201 | 202 | 203 | gpg2.exe 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | m2e.version 213 | 214 | 215 | 216 | 217 | 218 | 220 | 221 | org.eclipse.m2e 222 | lifecycle-mapping 223 | 1.0.0 224 | 225 | 226 | 227 | 228 | 229 | org.jacoco 230 | jacoco-maven-plugin 231 | [0.7.4.201502262128,) 232 | 233 | prepare-agent 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | -------------------------------------------------------------------------------- /src/test/java/com/github/dcendents/mybatis/generator/plugin/locking/OptimisticLockingPluginTest.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.locking; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.assertj.core.api.BDDAssertions.then; 5 | import static org.mockito.BDDMockito.given; 6 | import static org.mockito.BDDMockito.willReturn; 7 | import static org.mockito.Matchers.any; 8 | import static org.mockito.Matchers.eq; 9 | import static org.mockito.Mockito.spy; 10 | import static org.mockito.Mockito.times; 11 | import static org.mockito.Mockito.verify; 12 | 13 | import java.util.ArrayList; 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | import org.junit.Before; 18 | import org.junit.Test; 19 | import org.junit.runner.RunWith; 20 | import org.mockito.Mock; 21 | import org.mockito.runners.MockitoJUnitRunner; 22 | import org.mybatis.generator.api.IntrospectedColumn; 23 | import org.mybatis.generator.api.IntrospectedTable; 24 | import org.mybatis.generator.api.dom.java.Interface; 25 | import org.mybatis.generator.api.dom.java.Method; 26 | import org.mybatis.generator.api.dom.java.TopLevelClass; 27 | import org.mybatis.generator.api.dom.xml.XmlElement; 28 | 29 | /** 30 | * Tests for the class OptimisticLockingPlugin. 31 | */ 32 | @RunWith(MockitoJUnitRunner.class) 33 | public class OptimisticLockingPluginTest { 34 | 35 | private OptimisticLockingPlugin plugin; 36 | 37 | @Mock 38 | private XmlElement element; 39 | @Mock 40 | private Method method; 41 | @Mock 42 | private Method withLock; 43 | @Mock 44 | private IntrospectedTable introspectedTable; 45 | @Mock 46 | private TopLevelClass topLevelClass; 47 | @Mock 48 | private Interface interfaze; 49 | 50 | @Mock 51 | private IntrospectedColumn id; 52 | @Mock 53 | private IntrospectedColumn other; 54 | @Mock 55 | private IntrospectedColumn modificationDate; 56 | 57 | 58 | private static final String TABLE_NAME = "table_name"; 59 | private static final String LOCK_COLUMN = "modification_date"; 60 | private static final String LOCK_COLUMN_FUNCTION = "date_trunc('milliseconds', modification_date)"; 61 | 62 | @Before 63 | public void init() throws Exception { 64 | given(id.getActualColumnName()).willReturn("id"); 65 | given(other.getActualColumnName()).willReturn("other_column"); 66 | given(modificationDate.getActualColumnName()).willReturn("modification_date"); 67 | 68 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 69 | given(introspectedTable.getAllColumns()).willReturn(Arrays.asList(id, other, modificationDate)); 70 | 71 | given(method.getName()).willReturn("methodName"); 72 | 73 | plugin = new OptimisticLockingPlugin(); 74 | plugin.getProperties().put(OptimisticLockingPlugin.TABLE_NAME, TABLE_NAME); 75 | plugin.getProperties().put(OptimisticLockingPlugin.LOCK_COLUMN, LOCK_COLUMN); 76 | plugin.getProperties().put(OptimisticLockingPlugin.LOCK_COLUMN_FUNCTION, LOCK_COLUMN_FUNCTION); 77 | plugin.validate(new ArrayList()); 78 | } 79 | 80 | @Test 81 | public void shouldBeInvalidWithoutAnyPropertyConfigured() { 82 | // Given 83 | OptimisticLockingPlugin instance = new OptimisticLockingPlugin(); 84 | 85 | // When 86 | List warnings = new ArrayList<>(); 87 | boolean ok = instance.validate(warnings); 88 | 89 | // Then 90 | assertThat(ok).isFalse(); 91 | assertThat(warnings).hasSize(2); 92 | } 93 | 94 | @Test 95 | public void shouldBeInvalidWithOnlyTheTableNameConfigured() { 96 | // Given 97 | OptimisticLockingPlugin instance = new OptimisticLockingPlugin(); 98 | instance.getProperties().put(OptimisticLockingPlugin.TABLE_NAME, TABLE_NAME); 99 | 100 | // When 101 | List warnings = new ArrayList<>(); 102 | boolean ok = instance.validate(warnings); 103 | 104 | // Then 105 | assertThat(ok).isFalse(); 106 | assertThat(warnings).hasSize(1); 107 | } 108 | 109 | @Test 110 | public void shouldBeInvalidWithOnlyTheLockColumnConfigured() { 111 | // Given 112 | OptimisticLockingPlugin instance = new OptimisticLockingPlugin(); 113 | instance.getProperties().put(OptimisticLockingPlugin.LOCK_COLUMN, LOCK_COLUMN); 114 | 115 | // When 116 | List warnings = new ArrayList<>(); 117 | boolean ok = instance.validate(warnings); 118 | 119 | // Then 120 | assertThat(ok).isFalse(); 121 | assertThat(warnings).hasSize(1); 122 | } 123 | 124 | @Test 125 | public void shouldBeValidWhenBothPropertiesAreConfigured() { 126 | // Given 127 | OptimisticLockingPlugin instance = new OptimisticLockingPlugin(); 128 | instance.getProperties().put(OptimisticLockingPlugin.TABLE_NAME, TABLE_NAME); 129 | instance.getProperties().put(OptimisticLockingPlugin.LOCK_COLUMN, LOCK_COLUMN); 130 | 131 | // When 132 | List warnings = new ArrayList<>(); 133 | boolean ok = instance.validate(warnings); 134 | 135 | // Then 136 | assertThat(ok).isTrue(); 137 | assertThat(warnings).isEmpty(); 138 | } 139 | 140 | @Test 141 | public void shouldSupportRegex() { 142 | // Given 143 | OptimisticLockingPlugin instance = new OptimisticLockingPlugin(); 144 | instance.getProperties().put(OptimisticLockingPlugin.TABLE_NAME, "tab.*_n\\S+"); 145 | instance.getProperties().put(OptimisticLockingPlugin.LOCK_COLUMN, LOCK_COLUMN); 146 | instance.validate(new ArrayList()); 147 | 148 | // When 149 | boolean ok = instance.tableMatches(introspectedTable); 150 | 151 | // Then 152 | assertThat(ok).isTrue(); 153 | } 154 | 155 | @Test 156 | public void shouldNotAddMethodIfTableDoesNotMatch() { 157 | // Given 158 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn("wrong_name"); 159 | 160 | // When 161 | boolean ok1 = plugin.clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(method, interfaze, introspectedTable); 162 | boolean ok2 = plugin.clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 163 | 164 | // Then 165 | then(ok1).isTrue(); 166 | then(ok2).isTrue(); 167 | verify(interfaze, times(0)).addMethod(any(Method.class)); 168 | verify(topLevelClass, times(0)).addMethod(any(Method.class)); 169 | } 170 | 171 | @Test 172 | public void shouldAddNewMethod() { 173 | // Given 174 | OptimisticLockingPlugin plugin = spy(this.plugin); 175 | willReturn(withLock).given(plugin).addMethod(eq(method), eq(introspectedTable)); 176 | 177 | // When 178 | boolean ok1 = plugin.clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(method, interfaze, introspectedTable); 179 | boolean ok2 = plugin.clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 180 | 181 | // Then 182 | then(ok1).isTrue(); 183 | then(ok2).isTrue(); 184 | verify(plugin, times(2)).addMethod(eq(method), eq(introspectedTable)); 185 | verify(interfaze).addMethod(eq(withLock)); 186 | verify(topLevelClass).addMethod(eq(withLock)); 187 | } 188 | 189 | @Test 190 | public void shouldCreateNewMethodUsingBaseName() { 191 | // Given 192 | Method realMethod = new Method("methodName"); 193 | 194 | // When 195 | Method newMethod = plugin.addMethod(realMethod, introspectedTable); 196 | 197 | // Then 198 | then(newMethod).isNotNull(); 199 | then(newMethod.getName()).isEqualTo(realMethod.getName() + OptimisticLockingPlugin.METHOD_SUFFIX); 200 | } 201 | 202 | @Test 203 | public void shouldAddConditionToWhereClauseInAnnotation() { 204 | // Given 205 | Method realMethod = new Method("methodName"); 206 | realMethod.addAnnotation("@Update({"); 207 | realMethod.addAnnotation(" \"update schema.table_name\","); 208 | realMethod.addAnnotation(" \"set id = #{id,jdbcType=INT},\","); 209 | realMethod.addAnnotation(" \"other_column = #{other,jdbcType=INT},\","); 210 | realMethod.addAnnotation(" \"where id = #{id,jdbcType=BIGINT}\""); 211 | realMethod.addAnnotation("})"); 212 | 213 | // When 214 | Method newMethod = plugin.addMethod(realMethod, introspectedTable); 215 | 216 | // Then 217 | then(newMethod).isNotNull(); 218 | then(newMethod.getName()).isEqualTo(realMethod.getName() + OptimisticLockingPlugin.METHOD_SUFFIX); 219 | 220 | then(newMethod.getAnnotations()).hasSize(realMethod.getAnnotations().size() + 1); 221 | then(newMethod.getAnnotations()).containsAll(realMethod.getAnnotations().subList(0, 4)); 222 | then(newMethod.getAnnotations().get(4)).isEqualTo(realMethod.getAnnotations().get(4) + ","); 223 | then(newMethod.getAnnotations().get(5)).contains(String.format("and %s = ", LOCK_COLUMN_FUNCTION)); 224 | then(newMethod.getAnnotations().get(6)).isEqualTo(realMethod.getAnnotations().get(5)); 225 | } 226 | 227 | @Test 228 | public void shouldSetCorrectTypeHandler() { 229 | // Given 230 | String typeHandler = "some.type.Handler"; 231 | given(modificationDate.getTypeHandler()).willReturn(typeHandler); 232 | 233 | Method realMethod = new Method("methodName"); 234 | realMethod.addAnnotation("@Update({"); 235 | realMethod.addAnnotation(" \"update schema.table_name\","); 236 | realMethod.addAnnotation(" \"set id = #{id,jdbcType=INT},\","); 237 | realMethod.addAnnotation(" \"other_column = #{other,jdbcType=INT},\","); 238 | realMethod.addAnnotation(" \"where id = #{id,jdbcType=BIGINT}\""); 239 | realMethod.addAnnotation("})"); 240 | 241 | // When 242 | Method newMethod = plugin.addMethod(realMethod, introspectedTable); 243 | 244 | // Then 245 | then(newMethod.getAnnotations().get(5)).contains(typeHandler); 246 | } 247 | 248 | @Test 249 | public void shouldIgnoreMissingColumn() { 250 | // Given 251 | given(introspectedTable.getAllColumns()).willReturn(Arrays.asList(id, other)); 252 | 253 | // When 254 | IntrospectedColumn column = plugin.getColumn(introspectedTable); 255 | 256 | // Then 257 | then(column).isNull(); 258 | } 259 | 260 | } 261 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | -------------------------------------------------------------------------------- /src/main/java/com/github/dcendents/mybatis/generator/plugin/dynamic/sql/DynamicSqlSupportClassGenerator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2006-2018 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.github.dcendents.mybatis.generator.plugin.dynamic.sql; 17 | 18 | import static org.mybatis.generator.codegen.mybatis3.MyBatis3FormattingUtilities.getEscapedColumnName; 19 | import static org.mybatis.generator.internal.util.StringUtility.escapeStringForJava; 20 | 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.Properties; 24 | 25 | import org.apache.commons.lang3.StringUtils; 26 | import org.mybatis.generator.api.CommentGenerator; 27 | import org.mybatis.generator.api.IntrospectedColumn; 28 | import org.mybatis.generator.api.IntrospectedTable; 29 | import org.mybatis.generator.api.dom.java.Field; 30 | import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; 31 | import org.mybatis.generator.api.dom.java.InnerClass; 32 | import org.mybatis.generator.api.dom.java.JavaVisibility; 33 | import org.mybatis.generator.api.dom.java.Method; 34 | import org.mybatis.generator.api.dom.java.TopLevelClass; 35 | import org.mybatis.generator.internal.util.JavaBeansUtil; 36 | import org.mybatis.generator.internal.util.StringUtility; 37 | 38 | public class DynamicSqlSupportClassGenerator { 39 | private IntrospectedTable introspectedTable; 40 | private CommentGenerator commentGenerator; 41 | 42 | private String sqlTableClassName; 43 | private boolean addAliasedColumns; 44 | private boolean addTableAlias; 45 | private String tableAliasFieldName; 46 | private Properties properties; 47 | 48 | private DynamicSqlSupportClassGenerator() { 49 | super(); 50 | } 51 | 52 | public TopLevelClass generate() { 53 | TopLevelClass topLevelClass = buildBasicClass(); 54 | Field tableField = calculateTableDefinition(topLevelClass); 55 | topLevelClass.addImportedType(tableField.getType()); 56 | topLevelClass.addField(tableField); 57 | 58 | InnerClass innerClass = buildInnerTableClass(topLevelClass); 59 | topLevelClass.addInnerClass(innerClass); 60 | 61 | handleAliases(topLevelClass, innerClass, tableField.getName()); 62 | 63 | List columns = introspectedTable.getAllColumns(); 64 | for (IntrospectedColumn column : columns) { 65 | handleColumn(topLevelClass, innerClass, column, tableField.getName()); 66 | } 67 | 68 | return topLevelClass; 69 | } 70 | 71 | private String calculateClassName() { 72 | FullyQualifiedJavaType mapperType = new FullyQualifiedJavaType(introspectedTable.getMyBatis3JavaMapperType()); 73 | FullyQualifiedJavaType recordType = new FullyQualifiedJavaType(introspectedTable.getBaseRecordType()); 74 | 75 | return mapperType.getPackageName() + "." + recordType.getShortNameWithoutTypeArguments() + "DynamicSqlSupport"; //$NON-NLS-1$ //$NON-NLS-2$ 76 | 77 | } 78 | 79 | private TopLevelClass buildBasicClass() { 80 | TopLevelClass topLevelClass = new TopLevelClass(calculateClassName()); 81 | topLevelClass.setVisibility(JavaVisibility.PUBLIC); 82 | topLevelClass.setFinal(true); 83 | topLevelClass.addImportedType(new FullyQualifiedJavaType("org.mybatis.dynamic.sql.SqlColumn")); //$NON-NLS-1$ 84 | topLevelClass.addImportedType(new FullyQualifiedJavaType("org.mybatis.dynamic.sql.SqlTable")); //$NON-NLS-1$ 85 | topLevelClass.addImportedType(new FullyQualifiedJavaType("java.sql.JDBCType")); //$NON-NLS-1$ 86 | return topLevelClass; 87 | } 88 | 89 | private InnerClass buildInnerTableClass(TopLevelClass topLevelClass) { 90 | FullyQualifiedJavaType fqjt = new FullyQualifiedJavaType(sqlTableClassName); 91 | InnerClass innerClass = new InnerClass(fqjt.getShortName()); 92 | innerClass.setVisibility(JavaVisibility.PUBLIC); 93 | innerClass.setStatic(true); 94 | innerClass.setFinal(true); 95 | innerClass.setSuperClass(new FullyQualifiedJavaType("org.mybatis.dynamic.sql.SqlTable")); //$NON-NLS-1$ 96 | 97 | Method method = new Method(fqjt.getShortName()); 98 | method.setVisibility(JavaVisibility.PUBLIC); 99 | method.setConstructor(true); 100 | method.addBodyLine("super(\"" //$NON-NLS-1$ 101 | + escapeStringForJava(introspectedTable.getFullyQualifiedTableNameAtRuntime()) + "\");"); //$NON-NLS-1$ 102 | innerClass.addMethod(method); 103 | 104 | commentGenerator.addClassAnnotation(innerClass, introspectedTable, topLevelClass.getImportedTypes()); 105 | 106 | return innerClass; 107 | } 108 | 109 | private Field calculateTableDefinition(TopLevelClass topLevelClass) { 110 | FullyQualifiedJavaType fqjt = new FullyQualifiedJavaType(sqlTableClassName); 111 | String fieldName = JavaBeansUtil.getValidPropertyName(sqlTableClassName); 112 | Field field = new Field(fieldName, fqjt); 113 | commentGenerator.addFieldAnnotation(field, introspectedTable, topLevelClass.getImportedTypes()); 114 | field.setVisibility(JavaVisibility.PUBLIC); 115 | field.setStatic(true); 116 | field.setFinal(true); 117 | 118 | StringBuilder initializationString = new StringBuilder(); 119 | initializationString.append(String.format("new %s()", //$NON-NLS-1$ 120 | escapeStringForJava(sqlTableClassName))); 121 | field.setInitializationString(initializationString.toString()); 122 | return field; 123 | } 124 | 125 | private void handleAliases(TopLevelClass topLevelClass, InnerClass innerClass, String tableFieldName) { 126 | // Standard MBG table alias 127 | String alias = introspectedTable.getFullyQualifiedTable().getAlias(); 128 | if (addTableAlias && StringUtils.isNotBlank(alias) && StringUtils.isNotBlank(tableAliasFieldName)) { 129 | handleAlias(topLevelClass, innerClass, tableFieldName, tableAliasFieldName, alias); 130 | } 131 | 132 | // Extra aliases 133 | for (Map.Entry entry : properties.entrySet()) { 134 | String key = (String) entry.getKey(); 135 | String value = (String) entry.getValue(); 136 | 137 | if (key.startsWith(introspectedTable.getFullyQualifiedTableNameAtRuntime() + ".")) { 138 | String aliasField = key.substring(introspectedTable.getFullyQualifiedTableNameAtRuntime().length() + 1); 139 | handleAlias(topLevelClass, innerClass, tableFieldName, aliasField, value); 140 | } 141 | } 142 | } 143 | 144 | private void handleAlias(TopLevelClass topLevelClass, InnerClass innerClass, String tableFieldName, String aliasFieldName, String alias) { 145 | FullyQualifiedJavaType fieldType = FullyQualifiedJavaType.getStringInstance(); 146 | 147 | // tlc field 148 | Field field = new Field(aliasFieldName, fieldType); 149 | field.setVisibility(JavaVisibility.PUBLIC); 150 | field.setStatic(true); 151 | field.setFinal(true); 152 | field.setInitializationString(tableFieldName + "." + aliasFieldName); //$NON-NLS-1$ 153 | commentGenerator.addFieldAnnotation(field, introspectedTable, topLevelClass.getImportedTypes()); 154 | topLevelClass.addField(field); 155 | 156 | // inner class field 157 | field = new Field(aliasFieldName, fieldType); 158 | field.setVisibility(JavaVisibility.PUBLIC); 159 | field.setFinal(true); 160 | field.setInitializationString(String.format("\"%s\"", alias)); 161 | innerClass.addField(field); 162 | } 163 | 164 | private void handleColumn(TopLevelClass topLevelClass, InnerClass innerClass, IntrospectedColumn column, String tableFieldName) { 165 | topLevelClass.addImportedType(column.getFullyQualifiedJavaType()); 166 | FullyQualifiedJavaType fieldType = calculateFieldType(column); 167 | String fieldName = column.getJavaProperty(); 168 | 169 | // tlc field 170 | Field field = new Field(fieldName, fieldType); 171 | field.setVisibility(JavaVisibility.PUBLIC); 172 | field.setStatic(true); 173 | field.setFinal(true); 174 | field.setInitializationString(tableFieldName + "." + fieldName); //$NON-NLS-1$ 175 | commentGenerator.addFieldAnnotation(field, introspectedTable, column, topLevelClass.getImportedTypes()); 176 | topLevelClass.addField(field); 177 | 178 | // tlc field alias 179 | if (addAliasedColumns && StringUtils.isNotBlank(column.getTableAlias())) { 180 | field = new Field(column.getTableAlias() + StringUtils.capitalize(fieldName), fieldType); 181 | field.setVisibility(JavaVisibility.PUBLIC); 182 | field.setStatic(true); 183 | field.setFinal(true); 184 | field.setInitializationString(tableFieldName + "." + fieldName); //$NON-NLS-1$ 185 | commentGenerator.addFieldAnnotation(field, introspectedTable, column, topLevelClass.getImportedTypes()); 186 | topLevelClass.addField(field); 187 | } 188 | 189 | // inner class field 190 | field = new Field(fieldName, fieldType); 191 | field.setVisibility(JavaVisibility.PUBLIC); 192 | field.setFinal(true); 193 | field.setInitializationString(calculateInnerInitializationString(column)); 194 | innerClass.addField(field); 195 | } 196 | 197 | private FullyQualifiedJavaType calculateFieldType(IntrospectedColumn column) { 198 | FullyQualifiedJavaType typeParameter; 199 | if (column.getFullyQualifiedJavaType().isPrimitive()) { 200 | typeParameter = column.getFullyQualifiedJavaType().getPrimitiveTypeWrapper(); 201 | } else { 202 | typeParameter = column.getFullyQualifiedJavaType(); 203 | } 204 | return new FullyQualifiedJavaType(String.format("SqlColumn<%s>", typeParameter.getShortName())); //$NON-NLS-1$ 205 | } 206 | 207 | private String calculateInnerInitializationString(IntrospectedColumn column) { 208 | StringBuilder initializationString = new StringBuilder(); 209 | 210 | initializationString.append(String.format("column(\"%s\", JDBCType.%s", //$NON-NLS-1$ //$NON-NLS-2$ 211 | escapeStringForJava(getEscapedColumnName(column)), column.getJdbcTypeName())); 212 | 213 | if (StringUtility.stringHasValue(column.getTypeHandler())) { 214 | initializationString.append(String.format(", \"%s\")", column.getTypeHandler())); //$NON-NLS-1$ 215 | } else { 216 | initializationString.append(')'); 217 | } 218 | 219 | return initializationString.toString(); 220 | } 221 | 222 | public static DynamicSqlSupportClassGenerator of(IntrospectedTable introspectedTable, CommentGenerator commentGenerator, String sqlTableClassSuffix, 223 | boolean addAliasedColumns, boolean addTableAlias, String tableAliasFieldName, Properties properties) { 224 | DynamicSqlSupportClassGenerator generator = new DynamicSqlSupportClassGenerator(); 225 | generator.introspectedTable = introspectedTable; 226 | generator.commentGenerator = commentGenerator; 227 | generator.sqlTableClassName = introspectedTable.getFullyQualifiedTable().getDomainObjectName() + sqlTableClassSuffix; 228 | generator.addAliasedColumns = addAliasedColumns; 229 | generator.addTableAlias = addTableAlias; 230 | generator.tableAliasFieldName = tableAliasFieldName; 231 | generator.properties = properties; 232 | return generator; 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /src/test/java/com/github/dcendents/mybatis/generator/plugin/client/AlterResultMapPluginTest.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.client; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.BDDMockito.given; 5 | import static org.mockito.Matchers.eq; 6 | import static org.mockito.Mockito.spy; 7 | import static org.mockito.Mockito.times; 8 | import static org.mockito.Mockito.verify; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | import org.junit.runner.RunWith; 16 | import org.mockito.Mock; 17 | import org.mockito.runners.MockitoJUnitRunner; 18 | import org.mybatis.generator.api.IntrospectedTable; 19 | import org.mybatis.generator.api.dom.java.Interface; 20 | import org.mybatis.generator.api.dom.java.Method; 21 | import org.mybatis.generator.api.dom.java.TopLevelClass; 22 | import org.mybatis.generator.api.dom.xml.Attribute; 23 | import org.mybatis.generator.api.dom.xml.XmlElement; 24 | 25 | /** 26 | * Tests for the class AlterResultMapPlugin. 27 | */ 28 | @RunWith(MockitoJUnitRunner.class) 29 | public class AlterResultMapPluginTest { 30 | 31 | private AlterResultMapPlugin plugin; 32 | 33 | @Mock 34 | private XmlElement element; 35 | @Mock 36 | private Method method; 37 | @Mock 38 | private IntrospectedTable introspectedTable; 39 | @Mock 40 | private TopLevelClass topLevelClass; 41 | @Mock 42 | private Interface interfaze; 43 | 44 | private static final String TABLE_NAME = "table_name"; 45 | private static final String RESULT_MAP_ID = "FullResultMap"; 46 | 47 | @Before 48 | public void init() throws Exception { 49 | plugin = new AlterResultMapPlugin(); 50 | plugin.getProperties().put(AlterResultMapPlugin.TABLE_NAME, TABLE_NAME); 51 | plugin.getProperties().put(AlterResultMapPlugin.RESULT_MAP_ID, RESULT_MAP_ID); 52 | plugin.validate(new ArrayList()); 53 | } 54 | 55 | @Test 56 | public void shouldBeInvalidWithoutAnyPropertyConfigured() { 57 | // Given 58 | AlterResultMapPlugin instance = new AlterResultMapPlugin(); 59 | 60 | // When 61 | List warnings = new ArrayList<>(); 62 | boolean ok = instance.validate(warnings); 63 | 64 | // Then 65 | assertThat(ok).isFalse(); 66 | assertThat(warnings).hasSize(2); 67 | } 68 | 69 | @Test 70 | public void shouldBeInvalidWithOnlyTheTableNameConfigured() { 71 | // Given 72 | AlterResultMapPlugin instance = new AlterResultMapPlugin(); 73 | instance.getProperties().put(AlterResultMapPlugin.TABLE_NAME, TABLE_NAME); 74 | 75 | // When 76 | List warnings = new ArrayList<>(); 77 | boolean ok = instance.validate(warnings); 78 | 79 | // Then 80 | assertThat(ok).isFalse(); 81 | assertThat(warnings).hasSize(1); 82 | } 83 | 84 | @Test 85 | public void shouldBeInvalidWithOnlyTheInterfacesConfigured() { 86 | // Given 87 | AlterResultMapPlugin instance = new AlterResultMapPlugin(); 88 | instance.getProperties().put(AlterResultMapPlugin.RESULT_MAP_ID, RESULT_MAP_ID); 89 | 90 | // When 91 | List warnings = new ArrayList<>(); 92 | boolean ok = instance.validate(warnings); 93 | 94 | // Then 95 | assertThat(ok).isFalse(); 96 | assertThat(warnings).hasSize(1); 97 | } 98 | 99 | @Test 100 | public void shouldBeValidWhenBothPropertiesAreConfigured() { 101 | // Given 102 | AlterResultMapPlugin instance = new AlterResultMapPlugin(); 103 | instance.getProperties().put(AlterResultMapPlugin.TABLE_NAME, TABLE_NAME); 104 | instance.getProperties().put(AlterResultMapPlugin.RESULT_MAP_ID, RESULT_MAP_ID); 105 | 106 | // When 107 | List warnings = new ArrayList<>(); 108 | boolean ok = instance.validate(warnings); 109 | 110 | // Then 111 | assertThat(ok).isTrue(); 112 | assertThat(warnings).isEmpty(); 113 | } 114 | 115 | @Test 116 | public void shouldNotModifyResultMapAttributeIfTableDoesNotMatch() { 117 | String resultMapId = "someId"; 118 | List attributes = new ArrayList<>(); 119 | attributes.add(new Attribute(AlterResultMapPlugin.RESULT_MAP_ATTRIBUTE, resultMapId)); 120 | 121 | // Given 122 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn("wrong_name"); 123 | 124 | // When 125 | plugin.renameResultMapAttribute(element, introspectedTable); 126 | 127 | // Then 128 | assertThat(attributes).hasSize(1); 129 | assertThat(attributes.get(0).getName()).isEqualTo(AlterResultMapPlugin.RESULT_MAP_ATTRIBUTE); 130 | assertThat(attributes.get(0).getValue()).isEqualTo(resultMapId); 131 | } 132 | 133 | @Test 134 | public void shouldModifyResultMapAttributeWhenTableMatches() { 135 | String resultMapId = "someId"; 136 | List attributes = new ArrayList<>(); 137 | attributes.add(new Attribute("someName", "someValue")); 138 | attributes.add(new Attribute(AlterResultMapPlugin.RESULT_MAP_ATTRIBUTE, resultMapId)); 139 | 140 | // Given 141 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 142 | given(element.getAttributes()).willReturn(attributes); 143 | 144 | // When 145 | plugin.renameResultMapAttribute(element, introspectedTable); 146 | 147 | // Then 148 | assertThat(attributes).hasSize(2); 149 | assertThat(attributes.get(1).getName()).isEqualTo(AlterResultMapPlugin.RESULT_MAP_ATTRIBUTE); 150 | assertThat(attributes.get(1).getValue()).isEqualTo(RESULT_MAP_ID); 151 | } 152 | 153 | @Test 154 | public void shouldHandleEmptyAttributeList() { 155 | List attributes = new ArrayList<>(); 156 | 157 | // Given 158 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 159 | given(element.getAttributes()).willReturn(attributes); 160 | 161 | // When 162 | plugin.renameResultMapAttribute(element, introspectedTable); 163 | 164 | // Then 165 | assertThat(attributes).isEmpty(); 166 | } 167 | 168 | @Test 169 | public void shouldNotModifyResultMapAnnotationIfTableDoesNotMatch() { 170 | String resultMapId = "someId"; 171 | List annotations = new ArrayList<>(); 172 | annotations.add(String.format(AlterResultMapPlugin.ANNOTATION_FORMAT, resultMapId)); 173 | 174 | // Given 175 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn("wrong_name"); 176 | 177 | // When 178 | plugin.renameResultMapAttribute(method, introspectedTable); 179 | 180 | // Then 181 | assertThat(annotations).hasSize(1); 182 | assertThat(annotations.get(0)).isEqualTo(String.format(AlterResultMapPlugin.ANNOTATION_FORMAT, resultMapId)); 183 | } 184 | 185 | @Test 186 | public void shouldModifyResultMapAnnotationWhenTableMatches() { 187 | String resultMapId = "someId"; 188 | List annotations = new ArrayList<>(); 189 | annotations.add("@otherAnnotation"); 190 | annotations.add(String.format(AlterResultMapPlugin.ANNOTATION_FORMAT, resultMapId)); 191 | 192 | // Given 193 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 194 | given(method.getAnnotations()).willReturn(annotations); 195 | 196 | // When 197 | plugin.renameResultMapAttribute(method, introspectedTable); 198 | 199 | // Then 200 | assertThat(annotations).hasSize(2); 201 | assertThat(annotations.get(1)).isEqualTo(String.format(AlterResultMapPlugin.ANNOTATION_FORMAT, RESULT_MAP_ID)); 202 | } 203 | 204 | @Test 205 | public void shouldHandleEmptyAnnotationList() { 206 | List annotations = new ArrayList<>(); 207 | 208 | // Given 209 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 210 | given(method.getAnnotations()).willReturn(annotations); 211 | 212 | // When 213 | plugin.renameResultMapAttribute(method, introspectedTable); 214 | 215 | // Then 216 | assertThat(annotations).isEmpty(); 217 | } 218 | 219 | @Test 220 | public void shouldRenameResultMapOfSqlMapSelectByExampleWithoutBLOBs() throws Exception { 221 | AlterResultMapPlugin plugin = spy(this.plugin); 222 | 223 | // Given 224 | 225 | // When 226 | boolean ok = plugin.sqlMapSelectByExampleWithoutBLOBsElementGenerated(element, introspectedTable); 227 | 228 | // Then 229 | assertThat(ok).isTrue(); 230 | verify(plugin).renameResultMapAttribute(eq(element), eq(introspectedTable)); 231 | } 232 | 233 | @Test 234 | public void shouldRenameResultMapOfSqlMapSelectByExampleWithBLOBs() throws Exception { 235 | AlterResultMapPlugin plugin = spy(this.plugin); 236 | 237 | // Given 238 | 239 | // When 240 | boolean ok = plugin.sqlMapSelectByExampleWithBLOBsElementGenerated(element, introspectedTable); 241 | 242 | // Then 243 | assertThat(ok).isTrue(); 244 | verify(plugin).renameResultMapAttribute(eq(element), eq(introspectedTable)); 245 | } 246 | 247 | @Test 248 | public void shouldRenameResultMapOfSqlMapSelectByPrimaryKey() throws Exception { 249 | AlterResultMapPlugin plugin = spy(this.plugin); 250 | 251 | // Given 252 | 253 | // When 254 | boolean ok = plugin.sqlMapSelectByPrimaryKeyElementGenerated(element, introspectedTable); 255 | 256 | // Then 257 | assertThat(ok).isTrue(); 258 | verify(plugin).renameResultMapAttribute(eq(element), eq(introspectedTable)); 259 | } 260 | 261 | @Test 262 | public void shouldRenameResultMapOfSqlMapSelectAll() throws Exception { 263 | AlterResultMapPlugin plugin = spy(this.plugin); 264 | 265 | // Given 266 | 267 | // When 268 | boolean ok = plugin.sqlMapSelectAllElementGenerated(element, introspectedTable); 269 | 270 | // Then 271 | assertThat(ok).isTrue(); 272 | verify(plugin).renameResultMapAttribute(eq(element), eq(introspectedTable)); 273 | } 274 | 275 | @Test 276 | public void shouldRenameResultMapOfClientSelectByExampleWithBLOBs() throws Exception { 277 | AlterResultMapPlugin plugin = spy(this.plugin); 278 | 279 | // Given 280 | 281 | // When 282 | boolean ok1 = plugin.clientSelectByExampleWithBLOBsMethodGenerated(method, interfaze, introspectedTable); 283 | boolean ok2 = plugin.clientSelectByExampleWithBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 284 | 285 | // Then 286 | assertThat(ok1).isTrue(); 287 | assertThat(ok2).isTrue(); 288 | verify(plugin, times(2)).renameResultMapAttribute(eq(method), eq(introspectedTable)); 289 | } 290 | 291 | @Test 292 | public void shouldRenameResultMapOfClientSelectByExampleWithoutBLOBs() throws Exception { 293 | AlterResultMapPlugin plugin = spy(this.plugin); 294 | 295 | // Given 296 | 297 | // When 298 | boolean ok1 = plugin.clientSelectByExampleWithoutBLOBsMethodGenerated(method, interfaze, introspectedTable); 299 | boolean ok2 = plugin.clientSelectByExampleWithoutBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 300 | 301 | // Then 302 | assertThat(ok1).isTrue(); 303 | assertThat(ok2).isTrue(); 304 | verify(plugin, times(2)).renameResultMapAttribute(eq(method), eq(introspectedTable)); 305 | } 306 | 307 | @Test 308 | public void shouldRenameResultMapOfClientSelectByPrimaryKey() throws Exception { 309 | AlterResultMapPlugin plugin = spy(this.plugin); 310 | 311 | // Given 312 | 313 | // When 314 | boolean ok1 = plugin.clientSelectByPrimaryKeyMethodGenerated(method, interfaze, introspectedTable); 315 | boolean ok2 = plugin.clientSelectByPrimaryKeyMethodGenerated(method, topLevelClass, introspectedTable); 316 | 317 | // Then 318 | assertThat(ok1).isTrue(); 319 | assertThat(ok2).isTrue(); 320 | verify(plugin, times(2)).renameResultMapAttribute(eq(method), eq(introspectedTable)); 321 | } 322 | 323 | @Test 324 | public void shouldRenameResultMapOfClientSelectAll() throws Exception { 325 | AlterResultMapPlugin plugin = spy(this.plugin); 326 | 327 | // Given 328 | 329 | // When 330 | boolean ok1 = plugin.clientSelectAllMethodGenerated(method, interfaze, introspectedTable); 331 | boolean ok2 = plugin.clientSelectAllMethodGenerated(method, topLevelClass, introspectedTable); 332 | 333 | // Then 334 | assertThat(ok1).isTrue(); 335 | assertThat(ok2).isTrue(); 336 | verify(plugin, times(2)).renameResultMapAttribute(eq(method), eq(introspectedTable)); 337 | } 338 | 339 | } 340 | -------------------------------------------------------------------------------- /src/main/java/com/github/dcendents/mybatis/generator/plugin/subpackage/CreateSubPackagePlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.subpackage; 2 | 3 | import java.util.List; 4 | 5 | import lombok.AllArgsConstructor; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import org.mybatis.generator.api.IntrospectedTable; 9 | import org.mybatis.generator.api.PluginAdapter; 10 | import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; 11 | import org.mybatis.generator.api.dom.java.Interface; 12 | import org.mybatis.generator.api.dom.java.Method; 13 | import org.mybatis.generator.api.dom.java.Parameter; 14 | import org.mybatis.generator.api.dom.java.TopLevelClass; 15 | import org.mybatis.generator.api.dom.xml.Attribute; 16 | import org.mybatis.generator.api.dom.xml.Document; 17 | import org.mybatis.generator.api.dom.xml.XmlElement; 18 | 19 | /** 20 | * Mybatis generator plugin to rename the generated files (extensible design). 21 | */ 22 | @AllArgsConstructor 23 | @Slf4j 24 | public class CreateSubPackagePlugin extends PluginAdapter { 25 | public static final String MODEL_PACKAGE_PROPERTY = "modelSubPackage"; 26 | public static final String MODEL_CLASS_SUFFIX_PROPERTY = "modelClassSuffix"; 27 | public static final String MAPPER_PACKAGE_PROPERTY = "mapperSubPackage"; 28 | public static final String MAPPER_CLASS_SUFFIX_PROPERTY = "mapperClassSuffix"; 29 | public static final String EXAMPLE_PACKAGE_PROPERTY = "exampleSubPackage"; 30 | public static final String EXAMPLE_CLASS_SUFFIX_PROPERTY = "exampleClassSuffix"; 31 | 32 | static final String ATTRIBUTE_NAMESPACE = "namespace"; 33 | static final String ATTRIBUTE_TYPE = "type"; 34 | 35 | private RenameProperties modelProperties; 36 | private RenameProperties mapperProperties; 37 | private RenameProperties exampleProperties; 38 | 39 | public CreateSubPackagePlugin() { 40 | modelProperties = new RenameProperties(); 41 | mapperProperties = new RenameProperties(); 42 | exampleProperties = new RenameProperties(); 43 | } 44 | 45 | @Override 46 | public boolean validate(List warnings) { 47 | modelProperties.validate(properties.getProperty(MODEL_PACKAGE_PROPERTY), 48 | properties.getProperty(MODEL_CLASS_SUFFIX_PROPERTY)); 49 | mapperProperties.validate(properties.getProperty(MAPPER_PACKAGE_PROPERTY), 50 | properties.getProperty(MAPPER_CLASS_SUFFIX_PROPERTY)); 51 | exampleProperties.validate(properties.getProperty(EXAMPLE_PACKAGE_PROPERTY), 52 | properties.getProperty(EXAMPLE_CLASS_SUFFIX_PROPERTY)); 53 | 54 | return modelProperties.isEnabled() || mapperProperties.isEnabled() || exampleProperties.isEnabled(); 55 | } 56 | 57 | @Override 58 | public void initialized(IntrospectedTable introspectedTable) { 59 | introspectedTable.setBaseRecordType(modelProperties.setTypes(introspectedTable.getBaseRecordType())); 60 | introspectedTable.setMyBatis3JavaMapperType(mapperProperties.setTypes(introspectedTable 61 | .getMyBatis3JavaMapperType())); 62 | introspectedTable.setExampleType(exampleProperties.setTypes(introspectedTable.getExampleType())); 63 | } 64 | 65 | /** 66 | * Rename the method types. 67 | * 68 | * @param method 69 | * the method 70 | * @return true 71 | */ 72 | boolean renameMethod(Method method) { 73 | method.setReturnType(modelProperties.renameType(method.getReturnType())); 74 | 75 | for (int i = 0; i < method.getParameters().size(); i++) { 76 | Parameter parameter = method.getParameters().get(i); 77 | FullyQualifiedJavaType parameterType = parameter.getType(); 78 | FullyQualifiedJavaType newParameterType = modelProperties.renameType(parameterType); 79 | if (parameterType != newParameterType) { 80 | Parameter newParam = new Parameter(newParameterType, parameter.getName(), parameter.isVarargs()); 81 | for (String annotation : parameter.getAnnotations()) { 82 | newParam.addAnnotation(annotation); 83 | } 84 | method.getParameters().set(i, newParam); 85 | log.debug("set new parameter: [{}][{}]", parameter, newParam); 86 | } 87 | } 88 | 89 | modelProperties.renameAnnotations(method.getAnnotations()); 90 | mapperProperties.renameAnnotations(method.getAnnotations()); 91 | 92 | return true; 93 | } 94 | 95 | /** 96 | * Rename the element attribute. 97 | * 98 | * @param element 99 | * the element 100 | * @param attributeName 101 | * the attribute name 102 | * @return true 103 | */ 104 | boolean renameElementAttribute(XmlElement element, String attributeName) { 105 | for (int i = 0; i < element.getAttributes().size(); i++) { 106 | Attribute attribute = element.getAttributes().get(i); 107 | if (attributeName.equals(attribute.getName())) { 108 | element.getAttributes().set(i, modelProperties.renameAttribute(element.getAttributes().get(i))); 109 | element.getAttributes().set(i, mapperProperties.renameAttribute(element.getAttributes().get(i))); 110 | } 111 | } 112 | 113 | return true; 114 | } 115 | 116 | @Override 117 | public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) { 118 | return renameElementAttribute(document.getRootElement(), ATTRIBUTE_NAMESPACE); 119 | } 120 | 121 | @Override 122 | public boolean sqlMapResultMapWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) { 123 | return renameElementAttribute(element, ATTRIBUTE_TYPE); 124 | } 125 | 126 | @Override 127 | public boolean sqlMapResultMapWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) { 128 | return renameElementAttribute(element, ATTRIBUTE_TYPE); 129 | } 130 | 131 | @Override 132 | public boolean clientSelectByPrimaryKeyMethodGenerated(Method method, Interface interfaze, 133 | IntrospectedTable introspectedTable) { 134 | return renameMethod(method); 135 | } 136 | 137 | @Override 138 | public boolean clientSelectByPrimaryKeyMethodGenerated(Method method, TopLevelClass topLevelClass, 139 | IntrospectedTable introspectedTable) { 140 | return renameMethod(method); 141 | } 142 | 143 | @Override 144 | public boolean clientCountByExampleMethodGenerated(Method method, Interface interfaze, 145 | IntrospectedTable introspectedTable) { 146 | return renameMethod(method); 147 | } 148 | 149 | @Override 150 | public boolean clientCountByExampleMethodGenerated(Method method, TopLevelClass topLevelClass, 151 | IntrospectedTable introspectedTable) { 152 | return renameMethod(method); 153 | } 154 | 155 | @Override 156 | public boolean clientDeleteByExampleMethodGenerated(Method method, Interface interfaze, 157 | IntrospectedTable introspectedTable) { 158 | return renameMethod(method); 159 | } 160 | 161 | @Override 162 | public boolean clientDeleteByExampleMethodGenerated(Method method, TopLevelClass topLevelClass, 163 | IntrospectedTable introspectedTable) { 164 | return renameMethod(method); 165 | } 166 | 167 | @Override 168 | public boolean clientDeleteByPrimaryKeyMethodGenerated(Method method, Interface interfaze, 169 | IntrospectedTable introspectedTable) { 170 | return renameMethod(method); 171 | } 172 | 173 | @Override 174 | public boolean clientDeleteByPrimaryKeyMethodGenerated(Method method, TopLevelClass topLevelClass, 175 | IntrospectedTable introspectedTable) { 176 | return renameMethod(method); 177 | } 178 | 179 | @Override 180 | public boolean clientInsertMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 181 | return renameMethod(method); 182 | } 183 | 184 | @Override 185 | public boolean clientInsertMethodGenerated(Method method, TopLevelClass topLevelClass, 186 | IntrospectedTable introspectedTable) { 187 | return renameMethod(method); 188 | } 189 | 190 | @Override 191 | public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 192 | FullyQualifiedJavaType modelType = new FullyQualifiedJavaType(modelProperties.getOriginalType()); 193 | if (interfaze != null) { 194 | interfaze.addImportedType(modelType); 195 | } 196 | if (topLevelClass != null) { 197 | topLevelClass.addImportedType(modelType); 198 | } 199 | 200 | return true; 201 | } 202 | 203 | @Override 204 | public boolean clientSelectByExampleWithBLOBsMethodGenerated(Method method, Interface interfaze, 205 | IntrospectedTable introspectedTable) { 206 | return renameMethod(method); 207 | } 208 | 209 | @Override 210 | public boolean clientSelectByExampleWithBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, 211 | IntrospectedTable introspectedTable) { 212 | return renameMethod(method); 213 | } 214 | 215 | @Override 216 | public boolean clientSelectByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, 217 | IntrospectedTable introspectedTable) { 218 | return renameMethod(method); 219 | } 220 | 221 | @Override 222 | public boolean clientSelectByExampleWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, 223 | IntrospectedTable introspectedTable) { 224 | return renameMethod(method); 225 | } 226 | 227 | @Override 228 | public boolean clientUpdateByExampleSelectiveMethodGenerated(Method method, Interface interfaze, 229 | IntrospectedTable introspectedTable) { 230 | return renameMethod(method); 231 | } 232 | 233 | @Override 234 | public boolean clientUpdateByExampleSelectiveMethodGenerated(Method method, TopLevelClass topLevelClass, 235 | IntrospectedTable introspectedTable) { 236 | return renameMethod(method); 237 | } 238 | 239 | @Override 240 | public boolean clientUpdateByExampleWithBLOBsMethodGenerated(Method method, Interface interfaze, 241 | IntrospectedTable introspectedTable) { 242 | return renameMethod(method); 243 | } 244 | 245 | @Override 246 | public boolean clientUpdateByExampleWithBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, 247 | IntrospectedTable introspectedTable) { 248 | return renameMethod(method); 249 | } 250 | 251 | @Override 252 | public boolean clientUpdateByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, 253 | IntrospectedTable introspectedTable) { 254 | return renameMethod(method); 255 | } 256 | 257 | @Override 258 | public boolean clientUpdateByExampleWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, 259 | IntrospectedTable introspectedTable) { 260 | return renameMethod(method); 261 | } 262 | 263 | @Override 264 | public boolean clientUpdateByPrimaryKeySelectiveMethodGenerated(Method method, Interface interfaze, 265 | IntrospectedTable introspectedTable) { 266 | return renameMethod(method); 267 | } 268 | 269 | @Override 270 | public boolean clientUpdateByPrimaryKeySelectiveMethodGenerated(Method method, TopLevelClass topLevelClass, 271 | IntrospectedTable introspectedTable) { 272 | return renameMethod(method); 273 | } 274 | 275 | @Override 276 | public boolean clientUpdateByPrimaryKeyWithBLOBsMethodGenerated(Method method, Interface interfaze, 277 | IntrospectedTable introspectedTable) { 278 | return renameMethod(method); 279 | } 280 | 281 | @Override 282 | public boolean clientUpdateByPrimaryKeyWithBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, 283 | IntrospectedTable introspectedTable) { 284 | return renameMethod(method); 285 | } 286 | 287 | @Override 288 | public boolean clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(Method method, Interface interfaze, 289 | IntrospectedTable introspectedTable) { 290 | return renameMethod(method); 291 | } 292 | 293 | @Override 294 | public boolean clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, 295 | IntrospectedTable introspectedTable) { 296 | return renameMethod(method); 297 | } 298 | 299 | @Override 300 | public boolean clientInsertSelectiveMethodGenerated(Method method, Interface interfaze, 301 | IntrospectedTable introspectedTable) { 302 | return renameMethod(method); 303 | } 304 | 305 | @Override 306 | public boolean clientInsertSelectiveMethodGenerated(Method method, TopLevelClass topLevelClass, 307 | IntrospectedTable introspectedTable) { 308 | return renameMethod(method); 309 | } 310 | 311 | @Override 312 | public boolean clientSelectAllMethodGenerated(Method method, Interface interfaze, 313 | IntrospectedTable introspectedTable) { 314 | return renameMethod(method); 315 | } 316 | 317 | @Override 318 | public boolean clientSelectAllMethodGenerated(Method method, TopLevelClass topLevelClass, 319 | IntrospectedTable introspectedTable) { 320 | return renameMethod(method); 321 | } 322 | 323 | @Override 324 | public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 325 | if (modelProperties.isEnabled()) { 326 | topLevelClass.setAbstract(true); 327 | } 328 | return true; 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GitHub license](https://img.shields.io/github/license/dcendents/mybatis-generator-plugins.svg)](http://www.apache.org/licenses/LICENSE-2.0.html) 2 | [![Build Status](https://travis-ci.org/dcendents/mybatis-generator-plugins.svg?branch=master)](https://travis-ci.org/dcendents/mybatis-generator-plugins) 3 | [![codecov.io](http://codecov.io/github/dcendents/mybatis-generator-plugins/coverage.svg?branch=master)](http://codecov.io/github/dcendents/mybatis-generator-plugins?branch=master) 4 | [![Maven Central](https://img.shields.io/maven-central/v/com.github.dcendents/mybatis-generator-plugins.svg)](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22mybatis-generator-plugins%22) 5 | [![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=dcendents/mybatis-generator-plugins)](https://dependabot.com) 6 | [![Dependabot SemVer Compatibility](https://img.shields.io/dependabot/semver/maven/mybatis-generator-plugins.svg)](https://dependabot.com/compatibility-score/?dependency-name=mybatis-generator-plugins&package-manager=maven&version-scheme=semver) 7 | 8 | MyBatis Generator Plugins 9 | ==================== 10 | Set of plugins for the mybatis-generator to further tweak the generated code. 11 | 12 | *Note*: Most of these plugins have been tested using the targetRuntime `MyBatis3` and the java client type `MIXEDMAPPER`. 13 | 14 | 15 | ## CreateSubPackagePlugin 16 | 17 | Powerful plugin that will rename the generated model, mappers and examples by moving them in a sub-package and/or append a suffix. This is intended to keep generated code apart from the final classes to allow the geneator plugin to overwrite them every time. 18 | 19 | e.g.: some.package.Actor will now be generated as some.package.sub.ActorSuffix and will be abstract. 20 | some.package.ActorMapper will now be generated as some.package.sub.ActorMapperSuffix but methods will still expect and object of type some.package.Actor (to be created manually). 21 | 22 | There are 6 optional parameters to set: 23 | - *modelSubPackage*: The sub package to create for model classes. 24 | - *modelClassSuffix*: The suffix to add to model classes. 25 | - *mapperSubPackage*: The sub package to create for mapper interfaces. 26 | - *mapperClassSuffix*: The suffix to add to mapper interfaces. 27 | - *exampleSubPackage*: The sub package to create for example classes. 28 | - *exampleClassSuffix*: The suffix to add to example classes. 29 | 30 | e.g.: 31 | ```xml 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | ``` 40 | 41 | ## RenameExampleClassAndMethodsPlugin 42 | 43 | Plugin that will rename the example classes and parameters to give them a more suitable name for a production environment. Also this plugin will fix the update statements and remove the id column(s). There are 4 mandatory parameters to set: 44 | - **classMethodSearchString**: The string to search in class names. 45 | - **classMethodReplaceString**: The replace value. 46 | - **parameterSearchString**: The string to search for parameter names. 47 | - **parameterReplaceString**: The replace value. 48 | 49 | e.g.: 50 | ```xml 51 | 52 | 53 | 54 | 55 | 56 | 57 | ``` 58 | 59 | ## AddClassAnnotationsPlugin 60 | 61 | Plugin that will add the specified annotation to every generated class. There are 2 mandatory parameters to set: 62 | - **annotationClass**: The class of the annotation, this will be added as an import statement. 63 | - **annotationString**: The literal string that will be added, complete will all values 64 | 65 | If you need to add multiple annotations, configure this plugin many times, one per annotation to add. 66 | 67 | e.g.: 68 | ```xml 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | ``` 78 | 79 | ## AlterModelPlugin 80 | 81 | A simple plugin to modify the generated model. Currently it can add interfaces to the specified generated model class. There are 2 mandatory parameters to set: 82 | - **fullyQualifiedTableName**: The name of the database table including the schema. 83 | - Will accept a regex expression 84 | - **addInterfaces**: A coma delimited list of interfaces to add to the model class implementations. 85 | 86 | e.g.: 87 | ```xml 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | ``` 97 | 98 | ## WrapObjectPlugin 99 | 100 | Plugin that can be used to make a generated class wrap another java bean. For each property to wrap, the field will not be generated and the getter/setter will simply redirect to the wrapped java bean methods instead. This strategy can be used when you need to persist some third party objects but still want the flexibility to add new properties (like a database id). This pattern is more flexible than trying to extend the class. There are 2 mandatory and 3 optional parameters to set: 101 | - **fullyQualifiedTableName**: The name of the database table including the schema. 102 | - **objectClass**: The class of the object to be wrapped. 103 | - *objectFieldName*: The name of the field to add, will default to the class name starting with a lower case. 104 | - *includes*: A coma separated list of fields to delegate to the wrapped object, everything else will be excluded. If left blank all fields are included. 105 | - *excludes*: A coma separated list of fields to exclude. 106 | 107 | The plugin need to be added for each table as needed. 108 | 109 | e.g.: 110 | ```xml 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | ``` 121 | 122 | ## AlterResultMapPlugin 123 | 124 | A simple plugin to modify the generated client to use a different ResultMap. There are 2 mandatory parameters to set: 125 | - **fullyQualifiedTableName**: The name of the database table including the schema. 126 | - **resultMapId**: The id of the result map to be used. 127 | 128 | e.g.: 129 | ```xml 130 | 131 | 132 | 133 | 134 | ``` 135 | 136 | ## DynamicSqlPlugin 137 | 138 | If you are not ready to switch to the new `MyBatis3DynamicSql` targetRuntime but would still enjoy the creation of the SqlTable and SqlColumn structures. 139 | Then you can use this plugin while keeping your targetRuntime. There are 4 optional parameters to set: 140 | - *tableClassSuffix*: A suffix to append to the generated SqlTable class (so the name does not collide with your existing model class). 141 | - *addAliasedColumns*: For each SqlColumn, add a second field with its name prefixed by the table alias. Useful when using static imports and different tables have identical column names. 142 | - *addTableAlias*: Also add an entry for the table alias as configured on the table element of the mybatis-generator configuration. 143 | - *tableAliasFieldName*: The name to use for the table alias field if enabled. Will default to `tableAlias` if not set. 144 | 145 | Additionally it is possible to add more aliases (or any other String constant) to the generated tables by adding properties with the format `fullyQualifiedTableName.aliasField`. 146 | 147 | e.g.: 148 | ```xml 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | ``` 158 | 159 | ## OptimisticLockingPlugin 160 | 161 | This plugin will add a method `updateByPrimaryKeyWithOptimisticLocking` using the provided column as an optimistic lock (see https://en.wikipedia.org/wiki/Optimistic_concurrency_control). It requires the generation of the method `updateByPrimaryKey` using java annotations as it will copy it and add a condition to the where clause. There are 2 mandatory and 1 optional parameters to set: 162 | - **fullyQualifiedTableName**: The name of the database table including the schema. 163 | - Will accept a regex expression 164 | - **lockColumn**: The column to use for optimistic locking. 165 | - *lockColumnFunction*: if specified, this will be used in the where clause instead of the column name. 166 | 167 | e.g.: 168 | ```xml 169 | 170 | 171 | 172 | 173 | 174 | ``` 175 | 176 | ## CreateGenericInterfacePlugin 177 | 178 | This plugin will create a Mapper interface using java generics as method arguments and return types. It will modify the mappers to extend it with the concrete types. It makes it easier to add utility methods that are agnostic of the exact mapper they are using. e.g.: Maybe a method that will call insert when the id field is null and update when it is not for any model/mapper combination. There is 1 mandatory parameter to set: 179 | - **interface**: The fully qualified name of the interface to create. 180 | 181 | e.g.: 182 | ```xml 183 | 184 | 185 | 186 | ``` 187 | 188 | Demo 189 | ==================== 190 | 191 | See the following project for a demo of most of these plugins: https://github.com/dcendents/mybatis-jaxws 192 | 193 | Build Metrics 194 | ==================== 195 | 196 | [![Build Status](https://travis-ci.org/dcendents/mybatis-generator-plugins.svg?branch=master)](https://travis-ci.org/dcendents/mybatis-generator-plugins) 197 | [![codecov.io](http://codecov.io/github/dcendents/mybatis-generator-plugins/coverage.svg?branch=master)](http://codecov.io/github/dcendents/mybatis-generator-plugins?branch=master) 198 | [![BCH compliance](https://bettercodehub.com/edge/badge/dcendents/mybatis-generator-plugins?branch=master)](https://bettercodehub.com/) 199 | [![DepShield Badge](https://depshield.sonatype.org/badges/dcendents/mybatis-generator-plugins/depshield.svg)](https://depshield.github.io) 200 | ![codecov.io](http://codecov.io/github/dcendents/mybatis-generator-plugins/branch.svg?branch=master) 201 | 202 | License 203 | ==================== 204 | 205 | Licensed under the Apache License, Version 2.0 (the "License"); 206 | you may not use this file except in compliance with the License. 207 | You may obtain a copy of the License at 208 | 209 | http://www.apache.org/licenses/LICENSE-2.0 210 | 211 | Unless required by applicable law or agreed to in writing, software 212 | distributed under the License is distributed on an "AS IS" BASIS, 213 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 214 | See the License for the specific language governing permissions and 215 | limitations under the License. 216 | 217 | -------------------------------------------------------------------------------- /src/main/java/com/github/dcendents/mybatis/generator/plugin/rename/RenameExampleClassAndMethodsPlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.rename; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | import lombok.NoArgsConstructor; 9 | import lombok.extern.slf4j.Slf4j; 10 | 11 | import org.mybatis.generator.api.IntrospectedColumn; 12 | import org.mybatis.generator.api.IntrospectedTable; 13 | import org.mybatis.generator.api.PluginAdapter; 14 | import org.mybatis.generator.api.dom.java.Interface; 15 | import org.mybatis.generator.api.dom.java.Method; 16 | import org.mybatis.generator.api.dom.java.Parameter; 17 | import org.mybatis.generator.api.dom.java.TopLevelClass; 18 | import org.mybatis.generator.api.dom.xml.Attribute; 19 | import org.mybatis.generator.api.dom.xml.Element; 20 | import org.mybatis.generator.api.dom.xml.TextElement; 21 | import org.mybatis.generator.api.dom.xml.XmlElement; 22 | 23 | import static org.mybatis.generator.internal.util.StringUtility.stringHasValue; 24 | import static org.mybatis.generator.internal.util.messages.Messages.getString; 25 | 26 | /** 27 | * Mybatis generator plugin to rename Example classes and methods. 28 | */ 29 | @Slf4j 30 | @NoArgsConstructor 31 | public class RenameExampleClassAndMethodsPlugin extends PluginAdapter { 32 | public static final String VALIDATION_ERROR_MESSAGE = "ValidationError.18"; 33 | public static final String CLASS_SEARCH_PROPERTY = "classMethodSearchString"; 34 | public static final String CLASS_REPLACE_PROPERTY = "classMethodReplaceString"; 35 | public static final String PARAM_SEARCH_PROPERTY = "parameterSearchString"; 36 | public static final String PARAM_REPLACE_PROPERTY = "parameterReplaceString"; 37 | 38 | static final String XML_ID_ATTRIBUTE = "id"; 39 | 40 | private String classMethodReplaceString; 41 | private Pattern classMethodPattern; 42 | private String parameterReplaceString; 43 | private Pattern parameterPattern; 44 | 45 | @Override 46 | public boolean validate(List warnings) { 47 | 48 | String classMethodSearchString = properties.getProperty(CLASS_SEARCH_PROPERTY); 49 | classMethodReplaceString = properties.getProperty(CLASS_REPLACE_PROPERTY); 50 | 51 | String parameterSearchString = properties.getProperty(PARAM_SEARCH_PROPERTY); 52 | parameterReplaceString = properties.getProperty(PARAM_REPLACE_PROPERTY); 53 | 54 | boolean valid = stringHasValue(classMethodSearchString) && stringHasValue(classMethodReplaceString) 55 | && stringHasValue(parameterSearchString) && stringHasValue(parameterReplaceString); 56 | 57 | if (valid) { 58 | classMethodPattern = Pattern.compile(classMethodSearchString); 59 | parameterPattern = Pattern.compile(parameterSearchString); 60 | } else { 61 | if (!stringHasValue(classMethodSearchString)) { 62 | warnings.add(getString(VALIDATION_ERROR_MESSAGE, 63 | RenameExampleClassAndMethodsPlugin.class.getSimpleName(), CLASS_SEARCH_PROPERTY)); 64 | } 65 | if (!stringHasValue(classMethodReplaceString)) { 66 | warnings.add(getString(VALIDATION_ERROR_MESSAGE, 67 | RenameExampleClassAndMethodsPlugin.class.getSimpleName(), CLASS_REPLACE_PROPERTY)); 68 | } 69 | if (!stringHasValue(parameterSearchString)) { 70 | warnings.add(getString(VALIDATION_ERROR_MESSAGE, 71 | RenameExampleClassAndMethodsPlugin.class.getSimpleName(), PARAM_SEARCH_PROPERTY)); 72 | } 73 | if (!stringHasValue(parameterReplaceString)) { 74 | warnings.add(getString(VALIDATION_ERROR_MESSAGE, 75 | RenameExampleClassAndMethodsPlugin.class.getSimpleName(), PARAM_REPLACE_PROPERTY)); 76 | } 77 | } 78 | 79 | return valid; 80 | } 81 | 82 | @Override 83 | public void initialized(IntrospectedTable introspectedTable) { 84 | String oldType = introspectedTable.getExampleType(); 85 | Matcher matcher = classMethodPattern.matcher(oldType); 86 | oldType = matcher.replaceAll(classMethodReplaceString); 87 | 88 | introspectedTable.setExampleType(oldType); 89 | } 90 | 91 | boolean renameMethod(Method method) { 92 | String oldMethodName = method.getName(); 93 | Matcher matcher = classMethodPattern.matcher(oldMethodName); 94 | String newMethodName = matcher.replaceAll(classMethodReplaceString); 95 | method.setName(newMethodName); 96 | 97 | for (int i = 0; i < method.getParameters().size(); i++) { 98 | Parameter parameter = method.getParameters().get(i); 99 | String oldParamName = parameter.getName(); 100 | matcher = parameterPattern.matcher(oldParamName); 101 | if (matcher.lookingAt()) { 102 | String newName = matcher.replaceAll(parameterReplaceString); 103 | Parameter newParam = new Parameter(parameter.getType(), newName, parameter.isVarargs()); 104 | for (String annotation : parameter.getAnnotations()) { 105 | newParam.addAnnotation(annotation); 106 | } 107 | method.getParameters().set(i, newParam); 108 | } 109 | } 110 | 111 | return true; 112 | } 113 | 114 | boolean renameElement(XmlElement element) { 115 | for (int i = 0; i < element.getAttributes().size(); i++) { 116 | Attribute attribute = element.getAttributes().get(i); 117 | if (XML_ID_ATTRIBUTE.equals(attribute.getName())) { 118 | String oldValue = attribute.getValue(); 119 | Matcher matcher = classMethodPattern.matcher(oldValue); 120 | String newValue = matcher.replaceAll(classMethodReplaceString); 121 | Attribute newAtt = new Attribute(attribute.getName(), newValue); 122 | element.getAttributes().set(i, newAtt); 123 | } 124 | } 125 | 126 | return true; 127 | } 128 | 129 | /** 130 | * Remove the id columns from the sql statement. Useful when the generated update statement is trying to update an 131 | * id column. 132 | * 133 | * @param introspectedTable 134 | * the table 135 | * @param element 136 | * the element 137 | */ 138 | void removeIdColumns(IntrospectedTable introspectedTable, XmlElement element) { 139 | List updates = new ArrayList<>(); 140 | 141 | String alias = introspectedTable.getTableConfiguration().getAlias(); 142 | if (alias == null) { 143 | alias = ""; 144 | } else { 145 | alias = alias + "."; 146 | } 147 | 148 | List ids = introspectedTable.getPrimaryKeyColumns(); 149 | for (IntrospectedColumn column : ids) { 150 | String typeHandler = column.getTypeHandler() != null ? String.format(",typeHandler=%s", column.getTypeHandler()) : ""; 151 | String update = String.format("%4$s%1$s = #{record.%2$s,jdbcType=%3$s%5$s},", column.getActualColumnName(), 152 | column.getJavaProperty(), column.getJdbcTypeName(), alias, typeHandler); 153 | log.debug("update: {}", update); 154 | updates.add(update); 155 | } 156 | 157 | if (!updates.isEmpty()) { 158 | removeIdColumns(updates, element, null, -1); 159 | } 160 | } 161 | 162 | /** 163 | * Remove the id columns from the sql statement. Useful when the generated update statement is trying to update an 164 | * id column. 165 | * 166 | * @param updates 167 | * the update statements 168 | * @param element 169 | * the element 170 | * @param parent 171 | * the parent element 172 | * @param index 173 | * the index of the element in the parent list 174 | */ 175 | void removeIdColumns(List updates, Element element, XmlElement parent, int index) { 176 | log.debug("element type: {}", element.getClass().getSimpleName()); 177 | log.debug("element: {}", element.getFormattedContent(0)); 178 | 179 | if (element instanceof TextElement) { 180 | TextElement textElement = (TextElement) element; 181 | for (String update : updates) { 182 | if (textElement.getContent().contains(update)) { 183 | TextElement newElement = new TextElement(textElement.getContent().replace(update, "")); 184 | parent.getElements().set(index, newElement); 185 | } 186 | } 187 | } else if (element instanceof XmlElement) { 188 | XmlElement xmlElement = (XmlElement) element; 189 | for (int i = 0; i < xmlElement.getElements().size(); i++) { 190 | Element e = xmlElement.getElements().get(i); 191 | removeIdColumns(updates, e, xmlElement, i); 192 | } 193 | } 194 | } 195 | 196 | @Override 197 | public boolean clientCountByExampleMethodGenerated(Method method, Interface interfaze, 198 | IntrospectedTable introspectedTable) { 199 | return renameMethod(method); 200 | } 201 | 202 | @Override 203 | public boolean clientCountByExampleMethodGenerated(Method method, TopLevelClass topLevelClass, 204 | IntrospectedTable introspectedTable) { 205 | return renameMethod(method); 206 | } 207 | 208 | @Override 209 | public boolean clientDeleteByExampleMethodGenerated(Method method, Interface interfaze, 210 | IntrospectedTable introspectedTable) { 211 | return renameMethod(method); 212 | } 213 | 214 | @Override 215 | public boolean clientDeleteByExampleMethodGenerated(Method method, TopLevelClass topLevelClass, 216 | IntrospectedTable introspectedTable) { 217 | return renameMethod(method); 218 | } 219 | 220 | @Override 221 | public boolean clientDeleteByPrimaryKeyMethodGenerated(Method method, Interface interfaze, 222 | IntrospectedTable introspectedTable) { 223 | return renameMethod(method); 224 | } 225 | 226 | @Override 227 | public boolean clientDeleteByPrimaryKeyMethodGenerated(Method method, TopLevelClass topLevelClass, 228 | IntrospectedTable introspectedTable) { 229 | return renameMethod(method); 230 | } 231 | 232 | @Override 233 | public boolean clientSelectByExampleWithBLOBsMethodGenerated(Method method, Interface interfaze, 234 | IntrospectedTable introspectedTable) { 235 | return renameMethod(method); 236 | } 237 | 238 | @Override 239 | public boolean clientSelectByExampleWithBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, 240 | IntrospectedTable introspectedTable) { 241 | return renameMethod(method); 242 | } 243 | 244 | @Override 245 | public boolean clientSelectByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, 246 | IntrospectedTable introspectedTable) { 247 | return renameMethod(method); 248 | } 249 | 250 | @Override 251 | public boolean clientSelectByExampleWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, 252 | IntrospectedTable introspectedTable) { 253 | return renameMethod(method); 254 | } 255 | 256 | @Override 257 | public boolean clientUpdateByExampleSelectiveMethodGenerated(Method method, Interface interfaze, 258 | IntrospectedTable introspectedTable) { 259 | return renameMethod(method); 260 | } 261 | 262 | @Override 263 | public boolean clientUpdateByExampleSelectiveMethodGenerated(Method method, TopLevelClass topLevelClass, 264 | IntrospectedTable introspectedTable) { 265 | return renameMethod(method); 266 | } 267 | 268 | @Override 269 | public boolean clientUpdateByExampleWithBLOBsMethodGenerated(Method method, Interface interfaze, 270 | IntrospectedTable introspectedTable) { 271 | return renameMethod(method); 272 | } 273 | 274 | @Override 275 | public boolean clientUpdateByExampleWithBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, 276 | IntrospectedTable introspectedTable) { 277 | return renameMethod(method); 278 | } 279 | 280 | @Override 281 | public boolean clientUpdateByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, 282 | IntrospectedTable introspectedTable) { 283 | return renameMethod(method); 284 | } 285 | 286 | @Override 287 | public boolean clientUpdateByExampleWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, 288 | IntrospectedTable introspectedTable) { 289 | return renameMethod(method); 290 | } 291 | 292 | @Override 293 | public boolean sqlMapCountByExampleElementGenerated(XmlElement element, IntrospectedTable introspectedTable) { 294 | return renameElement(element); 295 | } 296 | 297 | @Override 298 | public boolean sqlMapDeleteByExampleElementGenerated(XmlElement element, IntrospectedTable introspectedTable) { 299 | return renameElement(element); 300 | } 301 | 302 | @Override 303 | public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element, 304 | IntrospectedTable introspectedTable) { 305 | return renameElement(element); 306 | } 307 | 308 | @Override 309 | public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(XmlElement element, 310 | IntrospectedTable introspectedTable) { 311 | return renameElement(element); 312 | } 313 | 314 | @Override 315 | public boolean sqlMapUpdateByExampleSelectiveElementGenerated(XmlElement element, 316 | IntrospectedTable introspectedTable) { 317 | removeIdColumns(introspectedTable, element); 318 | return renameElement(element); 319 | } 320 | 321 | @Override 322 | public boolean sqlMapUpdateByExampleWithBLOBsElementGenerated(XmlElement element, 323 | IntrospectedTable introspectedTable) { 324 | removeIdColumns(introspectedTable, element); 325 | return renameElement(element); 326 | } 327 | 328 | @Override 329 | public boolean sqlMapUpdateByExampleWithoutBLOBsElementGenerated(XmlElement element, 330 | IntrospectedTable introspectedTable) { 331 | removeIdColumns(introspectedTable, element); 332 | return renameElement(element); 333 | } 334 | } 335 | -------------------------------------------------------------------------------- /src/test/java/com/github/dcendents/mybatis/generator/plugin/client/CreateGenericInterfacePluginTest.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.client; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.assertj.core.api.BDDAssertions.then; 5 | import static org.mockito.BDDMockito.given; 6 | import static org.mockito.Matchers.any; 7 | import static org.mockito.Matchers.eq; 8 | import static org.mockito.Mockito.spy; 9 | import static org.mockito.Mockito.times; 10 | import static org.mockito.Mockito.verify; 11 | 12 | import java.util.ArrayList; 13 | import java.util.Arrays; 14 | import java.util.List; 15 | 16 | import org.junit.Before; 17 | import org.junit.Test; 18 | import org.junit.runner.RunWith; 19 | import org.mockito.ArgumentCaptor; 20 | import org.mockito.Matchers; 21 | import org.mockito.Mock; 22 | import org.mockito.runners.MockitoJUnitRunner; 23 | import org.mybatis.generator.api.GeneratedJavaFile; 24 | import org.mybatis.generator.api.IntrospectedTable; 25 | import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; 26 | import org.mybatis.generator.api.dom.java.Interface; 27 | import org.mybatis.generator.api.dom.java.Method; 28 | import org.mybatis.generator.api.dom.java.Parameter; 29 | import org.mybatis.generator.api.dom.java.TopLevelClass; 30 | import org.mybatis.generator.config.Context; 31 | import org.mybatis.generator.config.JavaClientGeneratorConfiguration; 32 | 33 | /** 34 | * Tests for the class CreateGenericInterfacePlugin. 35 | */ 36 | @RunWith(MockitoJUnitRunner.class) 37 | public class CreateGenericInterfacePluginTest { 38 | 39 | private CreateGenericInterfacePlugin plugin; 40 | 41 | @Mock 42 | private Context context; 43 | @Mock 44 | private JavaClientGeneratorConfiguration javaClientGeneratorConfiguration; 45 | 46 | @Mock 47 | private Method method; 48 | @Mock 49 | private IntrospectedTable introspectedTable; 50 | @Mock 51 | private TopLevelClass topLevelClass; 52 | @Mock 53 | private Interface interfaze; 54 | 55 | @Mock 56 | private Parameter parameter1; 57 | @Mock 58 | private Parameter parameter2; 59 | 60 | private static final String INTERFACE = "some.Interface"; 61 | 62 | @Before 63 | public void init() throws Exception { 64 | given(context.getJavaClientGeneratorConfiguration()).willReturn(javaClientGeneratorConfiguration); 65 | 66 | given(javaClientGeneratorConfiguration.getTargetProject()).willReturn("src/main/java"); 67 | 68 | given(method.getParameters()).willReturn(Arrays.asList(parameter1, parameter2)); 69 | 70 | plugin = new CreateGenericInterfacePlugin(); 71 | plugin.setContext(context); 72 | 73 | plugin.getProperties().put(CreateGenericInterfacePlugin.INTERFACE, INTERFACE); 74 | // plugin.getProperties().put(AlterResultMapPlugin.RESULT_MAP_ID, RESULT_MAP_ID); 75 | plugin.validate(new ArrayList()); 76 | } 77 | 78 | @Test 79 | public void shouldBeInvalidWithoutAnyPropertyConfigured() { 80 | // Given 81 | CreateGenericInterfacePlugin instance = new CreateGenericInterfacePlugin(); 82 | 83 | // When 84 | List warnings = new ArrayList<>(); 85 | boolean ok = instance.validate(warnings); 86 | 87 | // Then 88 | assertThat(ok).isFalse(); 89 | assertThat(warnings).hasSize(1); 90 | } 91 | 92 | @Test 93 | public void shouldBeValidWhenPropertiesAreConfigured() { 94 | // Given 95 | CreateGenericInterfacePlugin instance = new CreateGenericInterfacePlugin(); 96 | instance.getProperties().put(CreateGenericInterfacePlugin.INTERFACE, INTERFACE); 97 | 98 | // When 99 | List warnings = new ArrayList<>(); 100 | boolean ok = instance.validate(warnings); 101 | 102 | // Then 103 | assertThat(ok).isTrue(); 104 | assertThat(warnings).isEmpty(); 105 | } 106 | 107 | @Test 108 | public void shouldGenerateAdditionalFile() throws Exception { 109 | // Given 110 | 111 | // When 112 | List files = plugin.contextGenerateAdditionalJavaFiles(); 113 | 114 | // Then 115 | then(files).hasSize(1); 116 | } 117 | 118 | @Test 119 | public void shouldAddInterfaceToMappers() { 120 | // Given 121 | 122 | // When 123 | boolean ok = plugin.clientGenerated(interfaze, topLevelClass, introspectedTable); 124 | 125 | // Then 126 | then(ok).isTrue(); 127 | 128 | ArgumentCaptor fullyQualifiedJavaTypeCaptor = ArgumentCaptor.forClass(FullyQualifiedJavaType.class); 129 | verify(interfaze).addSuperInterface(fullyQualifiedJavaTypeCaptor.capture()); 130 | 131 | then(fullyQualifiedJavaTypeCaptor.getValue()).isNotNull(); 132 | then(fullyQualifiedJavaTypeCaptor.getValue().getFullyQualifiedNameWithoutTypeParameters()).isEqualTo(INTERFACE); 133 | } 134 | 135 | @Test 136 | public void shouldAddClientCountByExampleMethod() { 137 | // Given 138 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 139 | 140 | // When 141 | boolean ok1 = plugin.clientCountByExampleMethodGenerated(method, interfaze, introspectedTable); 142 | boolean ok2 = plugin.clientCountByExampleMethodGenerated(method, topLevelClass, introspectedTable); 143 | 144 | // Then 145 | then(ok1).isTrue(); 146 | then(ok2).isTrue(); 147 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 148 | } 149 | 150 | @Test 151 | public void shouldAddClientDeleteByExampleMethod() { 152 | // Given 153 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 154 | 155 | // When 156 | boolean ok1 = plugin.clientDeleteByExampleMethodGenerated(method, interfaze, introspectedTable); 157 | boolean ok2 = plugin.clientDeleteByExampleMethodGenerated(method, topLevelClass, introspectedTable); 158 | 159 | // Then 160 | then(ok1).isTrue(); 161 | then(ok2).isTrue(); 162 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 163 | } 164 | 165 | @Test 166 | public void shouldAddClientDeleteByPrimaryKeyMethod() { 167 | // Given 168 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 169 | 170 | // When 171 | boolean ok1 = plugin.clientDeleteByPrimaryKeyMethodGenerated(method, interfaze, introspectedTable); 172 | boolean ok2 = plugin.clientDeleteByPrimaryKeyMethodGenerated(method, topLevelClass, introspectedTable); 173 | 174 | // Then 175 | then(ok1).isTrue(); 176 | then(ok2).isTrue(); 177 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 178 | } 179 | 180 | @Test 181 | public void shouldAddClientInsertMethod() { 182 | // Given 183 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 184 | 185 | // When 186 | boolean ok1 = plugin.clientInsertMethodGenerated(method, interfaze, introspectedTable); 187 | boolean ok2 = plugin.clientInsertMethodGenerated(method, topLevelClass, introspectedTable); 188 | 189 | // Then 190 | then(ok1).isTrue(); 191 | then(ok2).isTrue(); 192 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 193 | } 194 | 195 | @Test 196 | public void shouldAddClientSelectByExampleWithBLOBsMethod() { 197 | // Given 198 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 199 | 200 | // When 201 | boolean ok1 = plugin.clientSelectByExampleWithBLOBsMethodGenerated(method, interfaze, introspectedTable); 202 | boolean ok2 = plugin.clientSelectByExampleWithBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 203 | 204 | // Then 205 | then(ok1).isTrue(); 206 | then(ok2).isTrue(); 207 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 208 | } 209 | 210 | @Test 211 | public void shouldAddClientSelectByExampleWithoutBLOBsMethod() { 212 | // Given 213 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 214 | 215 | // When 216 | boolean ok1 = plugin.clientSelectByExampleWithoutBLOBsMethodGenerated(method, interfaze, introspectedTable); 217 | boolean ok2 = plugin.clientSelectByExampleWithoutBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 218 | 219 | // Then 220 | then(ok1).isTrue(); 221 | then(ok2).isTrue(); 222 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 223 | } 224 | 225 | @Test 226 | public void shouldAddClientSelectByPrimaryKeyMethod() { 227 | // Given 228 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 229 | 230 | // When 231 | boolean ok1 = plugin.clientSelectByPrimaryKeyMethodGenerated(method, interfaze, introspectedTable); 232 | boolean ok2 = plugin.clientSelectByPrimaryKeyMethodGenerated(method, topLevelClass, introspectedTable); 233 | 234 | // Then 235 | then(ok1).isTrue(); 236 | then(ok2).isTrue(); 237 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 238 | } 239 | 240 | @Test 241 | public void shouldAddClientUpdateByExampleSelectiveMethod() { 242 | // Given 243 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 244 | 245 | // When 246 | boolean ok1 = plugin.clientUpdateByExampleSelectiveMethodGenerated(method, interfaze, introspectedTable); 247 | boolean ok2 = plugin.clientUpdateByExampleSelectiveMethodGenerated(method, topLevelClass, introspectedTable); 248 | 249 | // Then 250 | then(ok1).isTrue(); 251 | then(ok2).isTrue(); 252 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 253 | } 254 | 255 | @Test 256 | public void shouldAddClientUpdateByExampleWithBLOBsMethod() { 257 | // Given 258 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 259 | 260 | // When 261 | boolean ok1 = plugin.clientUpdateByExampleWithBLOBsMethodGenerated(method, interfaze, introspectedTable); 262 | boolean ok2 = plugin.clientUpdateByExampleWithBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 263 | 264 | // Then 265 | then(ok1).isTrue(); 266 | then(ok2).isTrue(); 267 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 268 | } 269 | 270 | @Test 271 | public void shouldAddClientUpdateByExampleWithoutBLOBsMethod() { 272 | // Given 273 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 274 | 275 | // When 276 | boolean ok1 = plugin.clientUpdateByExampleWithoutBLOBsMethodGenerated(method, interfaze, introspectedTable); 277 | boolean ok2 = plugin.clientUpdateByExampleWithoutBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 278 | 279 | // Then 280 | then(ok1).isTrue(); 281 | then(ok2).isTrue(); 282 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 283 | } 284 | 285 | @Test 286 | public void shouldAddClientUpdateByPrimaryKeySelectiveMethod() { 287 | // Given 288 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 289 | 290 | // When 291 | boolean ok1 = plugin.clientUpdateByPrimaryKeySelectiveMethodGenerated(method, interfaze, introspectedTable); 292 | boolean ok2 = plugin.clientUpdateByPrimaryKeySelectiveMethodGenerated(method, topLevelClass, introspectedTable); 293 | 294 | // Then 295 | then(ok1).isTrue(); 296 | then(ok2).isTrue(); 297 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 298 | } 299 | 300 | @Test 301 | public void shouldAddClientUpdateByPrimaryKeyWithBLOBsMethod() { 302 | // Given 303 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 304 | 305 | // When 306 | boolean ok1 = plugin.clientUpdateByPrimaryKeyWithBLOBsMethodGenerated(method, interfaze, introspectedTable); 307 | boolean ok2 = plugin.clientUpdateByPrimaryKeyWithBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 308 | 309 | // Then 310 | then(ok1).isTrue(); 311 | then(ok2).isTrue(); 312 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 313 | } 314 | 315 | @Test 316 | public void shouldAddClientUpdateByPrimaryKeyWithoutBLOBsMethod() { 317 | // Given 318 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 319 | 320 | // When 321 | boolean ok1 = plugin.clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(method, interfaze, introspectedTable); 322 | boolean ok2 = plugin.clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 323 | 324 | // Then 325 | then(ok1).isTrue(); 326 | then(ok2).isTrue(); 327 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 328 | } 329 | 330 | @Test 331 | public void shouldAddClientInsertSelectiveMethod() { 332 | // Given 333 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 334 | 335 | // When 336 | boolean ok1 = plugin.clientInsertSelectiveMethodGenerated(method, interfaze, introspectedTable); 337 | boolean ok2 = plugin.clientInsertSelectiveMethodGenerated(method, topLevelClass, introspectedTable); 338 | 339 | // Then 340 | then(ok1).isTrue(); 341 | then(ok2).isTrue(); 342 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 343 | } 344 | 345 | @Test 346 | public void shouldAddClientSelectAllMethod() { 347 | // Given 348 | CreateGenericInterfacePlugin plugin = spy(this.plugin); 349 | 350 | // When 351 | boolean ok1 = plugin.clientSelectAllMethodGenerated(method, interfaze, introspectedTable); 352 | boolean ok2 = plugin.clientSelectAllMethodGenerated(method, topLevelClass, introspectedTable); 353 | 354 | // Then 355 | then(ok1).isTrue(); 356 | then(ok2).isTrue(); 357 | verify(plugin, times(2)).addGenericMethod(eq(method), any(FullyQualifiedJavaType.class), Matchers.anyVararg()); 358 | } 359 | 360 | } 361 | -------------------------------------------------------------------------------- /src/main/java/com/github/dcendents/mybatis/generator/plugin/client/CreateGenericInterfacePlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.client; 2 | 3 | import static org.mybatis.generator.internal.util.StringUtility.stringHasValue; 4 | 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.HashSet; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.Set; 11 | 12 | import org.mybatis.generator.api.GeneratedJavaFile; 13 | import org.mybatis.generator.api.IntrospectedTable; 14 | import org.mybatis.generator.api.PluginAdapter; 15 | import org.mybatis.generator.api.dom.DefaultJavaFormatter; 16 | import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; 17 | import org.mybatis.generator.api.dom.java.Interface; 18 | import org.mybatis.generator.api.dom.java.JavaVisibility; 19 | import org.mybatis.generator.api.dom.java.Method; 20 | import org.mybatis.generator.api.dom.java.Parameter; 21 | import org.mybatis.generator.api.dom.java.TopLevelClass; 22 | 23 | import lombok.NoArgsConstructor; 24 | 25 | /** 26 | * Mybatis generator plugin to create a generic interface for all mappers. 27 | */ 28 | @NoArgsConstructor 29 | public class CreateGenericInterfacePlugin extends PluginAdapter { 30 | public static final String INTERFACE = "interface"; 31 | 32 | private String interfaceName; 33 | private Interface genericInterface; 34 | 35 | private FullyQualifiedJavaType genericModel = new FullyQualifiedJavaType("T"); 36 | private FullyQualifiedJavaType genericExample = new FullyQualifiedJavaType("U"); 37 | private FullyQualifiedJavaType genericId = new FullyQualifiedJavaType("V"); 38 | 39 | private FullyQualifiedJavaType genericModelList; 40 | private FullyQualifiedJavaType longPrimitive; 41 | 42 | private Set methodsAdded; 43 | 44 | private Map models; 45 | private Map examples; 46 | private Map ids; 47 | 48 | @Override 49 | public boolean validate(List warnings) { 50 | interfaceName = properties.getProperty(INTERFACE); 51 | 52 | String warning = "Property %s not set for plugin %s"; 53 | if (!stringHasValue(interfaceName)) { 54 | warnings.add(String.format(warning, INTERFACE, this.getClass().getSimpleName())); 55 | return false; 56 | } 57 | 58 | init(); 59 | 60 | return true; 61 | } 62 | 63 | private void init() { 64 | genericModelList = FullyQualifiedJavaType.getNewListInstance(); 65 | genericModelList.addTypeArgument(genericModel); 66 | 67 | longPrimitive = new FullyQualifiedJavaType("long"); 68 | 69 | FullyQualifiedJavaType className = new FullyQualifiedJavaType(interfaceName); 70 | className.addTypeArgument(genericModel); 71 | className.addTypeArgument(genericExample); 72 | className.addTypeArgument(genericId); 73 | 74 | genericInterface = new Interface(className); 75 | genericInterface.setVisibility(JavaVisibility.PUBLIC); 76 | 77 | methodsAdded = new HashSet<>(); 78 | 79 | models = new HashMap<>(); 80 | examples = new HashMap<>(); 81 | ids = new HashMap<>(); 82 | } 83 | 84 | @Override 85 | public List contextGenerateAdditionalJavaFiles() { 86 | List models = new ArrayList<>(); 87 | 88 | GeneratedJavaFile genericInterfaceFile = 89 | new GeneratedJavaFile(genericInterface, context.getJavaClientGeneratorConfiguration().getTargetProject(), new DefaultJavaFormatter()); 90 | 91 | models.add(genericInterfaceFile); 92 | 93 | return models; 94 | } 95 | 96 | @Override 97 | public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 98 | FullyQualifiedJavaType type = new FullyQualifiedJavaType(interfaceName); 99 | type.addTypeArgument(models.get(introspectedTable)); 100 | type.addTypeArgument(examples.get(introspectedTable)); 101 | type.addTypeArgument(ids.get(introspectedTable)); 102 | 103 | interfaze.addSuperInterface(type); 104 | 105 | return true; 106 | } 107 | 108 | void addGenericMethod(Method method, FullyQualifiedJavaType returnType, FullyQualifiedJavaType... types) { 109 | method.addAnnotation("@Override"); 110 | 111 | if (!methodsAdded.contains(method.getName())) { 112 | Method genericMethod = new Method(method.getName()); 113 | genericMethod.addJavaDocLine("/**"); 114 | genericMethod.addJavaDocLine(" * This method was generated by MyBatis Generator."); 115 | genericMethod.addJavaDocLine(" *"); 116 | genericMethod.addJavaDocLine(" * @mbg.generated"); 117 | genericMethod.addJavaDocLine(" */"); 118 | 119 | genericMethod.setReturnType(returnType); 120 | 121 | for (int i = 0; i < method.getParameters().size(); i++) { 122 | Parameter parameter = method.getParameters().get(i); 123 | FullyQualifiedJavaType paramType = types.length > i ? types[i] : parameter.getType(); 124 | 125 | Parameter genericParameter = new Parameter(paramType, parameter.getName()); 126 | genericMethod.addParameter(genericParameter); 127 | } 128 | 129 | genericInterface.addMethod(genericMethod); 130 | 131 | methodsAdded.add(method.getName()); 132 | } 133 | } 134 | 135 | @Override 136 | public boolean clientCountByExampleMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 137 | addClientCountByExample(method, introspectedTable); 138 | return true; 139 | } 140 | 141 | @Override 142 | public boolean clientCountByExampleMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 143 | addClientCountByExample(method, introspectedTable); 144 | return true; 145 | } 146 | 147 | private void addClientCountByExample(Method method, IntrospectedTable introspectedTable) { 148 | examples.put(introspectedTable, method.getParameters().get(0).getType()); 149 | addGenericMethod(method, longPrimitive, genericExample); 150 | } 151 | 152 | @Override 153 | public boolean clientDeleteByExampleMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 154 | addClientDeleteByExample(method); 155 | return true; 156 | } 157 | 158 | @Override 159 | public boolean clientDeleteByExampleMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 160 | addClientDeleteByExample(method); 161 | return true; 162 | } 163 | 164 | private void addClientDeleteByExample(Method method) { 165 | addGenericMethod(method, FullyQualifiedJavaType.getIntInstance(), genericExample); 166 | } 167 | 168 | @Override 169 | public boolean clientDeleteByPrimaryKeyMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 170 | addClientDeleteByPrimaryKey(method, introspectedTable); 171 | return true; 172 | } 173 | 174 | @Override 175 | public boolean clientDeleteByPrimaryKeyMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 176 | addClientDeleteByPrimaryKey(method, introspectedTable); 177 | return true; 178 | } 179 | 180 | private void addClientDeleteByPrimaryKey(Method method, IntrospectedTable introspectedTable) { 181 | ids.put(introspectedTable, method.getParameters().get(0).getType()); 182 | addGenericMethod(method, FullyQualifiedJavaType.getIntInstance(), genericId); 183 | } 184 | 185 | @Override 186 | public boolean clientInsertMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 187 | addClientInsert(method, introspectedTable); 188 | return true; 189 | } 190 | 191 | @Override 192 | public boolean clientInsertMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 193 | addClientInsert(method, introspectedTable); 194 | return true; 195 | } 196 | 197 | private void addClientInsert(Method method, IntrospectedTable introspectedTable) { 198 | models.put(introspectedTable, method.getParameters().get(0).getType()); 199 | addGenericMethod(method, FullyQualifiedJavaType.getIntInstance(), genericModel); 200 | } 201 | 202 | @Override 203 | public boolean clientSelectByExampleWithBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 204 | addClientSelectByExampleWithBLOBs(method); 205 | return true; 206 | } 207 | 208 | @Override 209 | public boolean clientSelectByExampleWithBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 210 | addClientSelectByExampleWithBLOBs(method); 211 | return true; 212 | } 213 | 214 | private void addClientSelectByExampleWithBLOBs(Method method) { 215 | addGenericMethod(method, genericModelList, genericExample); 216 | } 217 | 218 | @Override 219 | public boolean clientSelectByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 220 | addClientSelectByExampleWithoutBLOBs(method); 221 | return true; 222 | } 223 | 224 | @Override 225 | public boolean clientSelectByExampleWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 226 | addClientSelectByExampleWithoutBLOBs(method); 227 | return true; 228 | } 229 | 230 | private void addClientSelectByExampleWithoutBLOBs(Method method) { 231 | addGenericMethod(method, genericModelList, genericExample); 232 | } 233 | 234 | @Override 235 | public boolean clientSelectByPrimaryKeyMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 236 | addClientSelectByPrimaryKey(method); 237 | return true; 238 | } 239 | 240 | @Override 241 | public boolean clientSelectByPrimaryKeyMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 242 | addClientSelectByPrimaryKey(method); 243 | return true; 244 | } 245 | 246 | private void addClientSelectByPrimaryKey(Method method) { 247 | addGenericMethod(method, genericModel, genericId); 248 | } 249 | 250 | @Override 251 | public boolean clientUpdateByExampleSelectiveMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 252 | addClientUpdateByExampleSelective(method); 253 | return true; 254 | } 255 | 256 | @Override 257 | public boolean clientUpdateByExampleSelectiveMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 258 | addClientUpdateByExampleSelective(method); 259 | return true; 260 | } 261 | 262 | private void addClientUpdateByExampleSelective(Method method) { 263 | addGenericMethod(method, FullyQualifiedJavaType.getIntInstance(), genericModel, genericExample); 264 | } 265 | 266 | @Override 267 | public boolean clientUpdateByExampleWithBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 268 | addClientUpdateByExampleWithBLOBs(method); 269 | return true; 270 | } 271 | 272 | @Override 273 | public boolean clientUpdateByExampleWithBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 274 | addClientUpdateByExampleWithBLOBs(method); 275 | return true; 276 | } 277 | 278 | private void addClientUpdateByExampleWithBLOBs(Method method) { 279 | addGenericMethod(method, FullyQualifiedJavaType.getIntInstance(), genericModel, genericExample); 280 | } 281 | 282 | @Override 283 | public boolean clientUpdateByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 284 | addClientUpdateByExampleWithoutBLOBs(method); 285 | return true; 286 | } 287 | 288 | @Override 289 | public boolean clientUpdateByExampleWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 290 | addClientUpdateByExampleWithoutBLOBs(method); 291 | return true; 292 | } 293 | 294 | private void addClientUpdateByExampleWithoutBLOBs(Method method) { 295 | addGenericMethod(method, FullyQualifiedJavaType.getIntInstance(), genericModel, genericExample); 296 | } 297 | 298 | @Override 299 | public boolean clientUpdateByPrimaryKeySelectiveMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 300 | addClientUpdateByPrimaryKeySelective(method); 301 | return true; 302 | } 303 | 304 | @Override 305 | public boolean clientUpdateByPrimaryKeySelectiveMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 306 | addClientUpdateByPrimaryKeySelective(method); 307 | return true; 308 | } 309 | 310 | private void addClientUpdateByPrimaryKeySelective(Method method) { 311 | addGenericMethod(method, FullyQualifiedJavaType.getIntInstance(), genericModel); 312 | } 313 | 314 | @Override 315 | public boolean clientUpdateByPrimaryKeyWithBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 316 | addClientUpdateByPrimaryKeyWithBLOBs(method); 317 | return true; 318 | } 319 | 320 | @Override 321 | public boolean clientUpdateByPrimaryKeyWithBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 322 | addClientUpdateByPrimaryKeyWithBLOBs(method); 323 | return true; 324 | } 325 | 326 | private void addClientUpdateByPrimaryKeyWithBLOBs(Method method) { 327 | addGenericMethod(method, FullyQualifiedJavaType.getIntInstance(), genericModel); 328 | } 329 | 330 | @Override 331 | public boolean clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 332 | addClientUpdateByPrimaryKeyWithoutBLOBs(method); 333 | return true; 334 | } 335 | 336 | @Override 337 | public boolean clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 338 | addClientUpdateByPrimaryKeyWithoutBLOBs(method); 339 | return true; 340 | } 341 | 342 | private void addClientUpdateByPrimaryKeyWithoutBLOBs(Method method) { 343 | addGenericMethod(method, FullyQualifiedJavaType.getIntInstance(), genericModel); 344 | } 345 | 346 | @Override 347 | public boolean clientInsertSelectiveMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 348 | addClientInsertSelective(method); 349 | return true; 350 | } 351 | 352 | @Override 353 | public boolean clientInsertSelectiveMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 354 | addClientInsertSelective(method); 355 | return true; 356 | } 357 | 358 | private void addClientInsertSelective(Method method) { 359 | addGenericMethod(method, FullyQualifiedJavaType.getIntInstance(), genericModel); 360 | } 361 | 362 | @Override 363 | public boolean clientSelectAllMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { 364 | addClientSelectAll(method); 365 | return true; 366 | } 367 | 368 | @Override 369 | public boolean clientSelectAllMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { 370 | addClientSelectAll(method); 371 | return true; 372 | } 373 | 374 | private void addClientSelectAll(Method method) { 375 | addGenericMethod(method, genericModel); 376 | } 377 | 378 | } 379 | -------------------------------------------------------------------------------- /src/test/java/com/github/dcendents/mybatis/generator/plugin/wrap/WrapObjectPluginTest.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.wrap; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.BDDMockito.given; 5 | import static org.mockito.BDDMockito.willAnswer; 6 | import static org.mockito.Matchers.any; 7 | import static org.mockito.Matchers.anyString; 8 | import static org.mockito.Matchers.eq; 9 | import static org.mockito.Mockito.times; 10 | import static org.mockito.Mockito.verify; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | import org.junit.Before; 16 | import org.junit.Test; 17 | import org.junit.runner.RunWith; 18 | import org.mockito.ArgumentCaptor; 19 | import org.mockito.Mock; 20 | import org.mockito.invocation.InvocationOnMock; 21 | import org.mockito.runners.MockitoJUnitRunner; 22 | import org.mockito.stubbing.Answer; 23 | import org.mybatis.generator.api.IntrospectedColumn; 24 | import org.mybatis.generator.api.IntrospectedTable; 25 | import org.mybatis.generator.api.dom.java.Field; 26 | import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; 27 | import org.mybatis.generator.api.dom.java.JavaVisibility; 28 | import org.mybatis.generator.api.dom.java.Method; 29 | import org.mybatis.generator.api.dom.java.Parameter; 30 | import org.mybatis.generator.api.dom.java.TopLevelClass; 31 | 32 | /** 33 | * Tests for the class WrapObjectPlugin. 34 | */ 35 | @RunWith(MockitoJUnitRunner.class) 36 | public class WrapObjectPluginTest { 37 | 38 | private WrapObjectPlugin plugin; 39 | 40 | @Mock 41 | private IntrospectedTable introspectedTable; 42 | @Mock 43 | private TopLevelClass topLevelClass; 44 | @Mock 45 | private Field field; 46 | @Mock 47 | private IntrospectedColumn introspectedColumn; 48 | @Mock 49 | private Method method; 50 | 51 | private static final String TABLE_NAME = "table_name"; 52 | private static final String OBJECT_CLASS = "com.github.dcendents.mybatis.generator.plugin.wrap.ClassDTO"; 53 | private static final String OBJECT_FIELD_NAME = "wrapObj"; 54 | private static final String INCLUDES = "name ,, address , homeAddress ,workAddress,street, "; 55 | private static final String EXCLUDES = " city ,, postCode , "; 56 | 57 | private List includeList; 58 | private List excludeList; 59 | 60 | private List methodLines; 61 | 62 | @Before 63 | public void init() throws Exception { 64 | plugin = new WrapObjectPlugin(); 65 | plugin.getProperties().put(WrapObjectPlugin.TABLE_NAME, TABLE_NAME); 66 | plugin.getProperties().put(WrapObjectPlugin.OBJECT_CLASS, OBJECT_CLASS); 67 | plugin.getProperties().put(WrapObjectPlugin.OBJECT_FIELD_NAME, OBJECT_FIELD_NAME); 68 | plugin.getProperties().put(WrapObjectPlugin.INCLUDES, INCLUDES); 69 | plugin.getProperties().put(WrapObjectPlugin.EXCLUDES, EXCLUDES); 70 | plugin.validate(new ArrayList()); 71 | 72 | includeList = new ArrayList<>(); 73 | for (String include : INCLUDES.split(",")) { 74 | includeList.add(include.trim()); 75 | } 76 | excludeList = new ArrayList<>(); 77 | for (String exclude : EXCLUDES.split(",")) { 78 | excludeList.add(exclude.trim()); 79 | } 80 | 81 | methodLines = new ArrayList<>(); 82 | methodLines.add("line1"); 83 | methodLines.add("line2"); 84 | methodLines.add("line3"); 85 | 86 | given(method.getBodyLines()).willReturn(methodLines); 87 | willAnswer(new Answer() { 88 | @Override 89 | public Void answer(InvocationOnMock invocation) throws Throwable { 90 | methodLines.add(invocation.getArgumentAt(0, String.class)); 91 | return null; 92 | } 93 | }).given(method).addBodyLine(anyString()); 94 | } 95 | 96 | @Test 97 | public void shouldHaveDefaultConstructor() throws Exception { 98 | // Given 99 | 100 | // When 101 | WrapObjectPlugin instance = new WrapObjectPlugin(); 102 | 103 | // Then 104 | assertThat(instance).isNotNull(); 105 | } 106 | 107 | @Test 108 | public void shouldBeUnvalidIfTableNameIsNotSet() throws Exception { 109 | // Given 110 | WrapObjectPlugin instance = new WrapObjectPlugin(); 111 | instance.getProperties().put(WrapObjectPlugin.OBJECT_CLASS, OBJECT_CLASS); 112 | 113 | // When 114 | List warnings = new ArrayList<>(); 115 | boolean ok = instance.validate(warnings); 116 | 117 | // Then 118 | assertThat(ok).isFalse(); 119 | assertThat(warnings).hasSize(1); 120 | } 121 | 122 | @Test 123 | public void shouldBeUnvalidIfObjectClassIsNotSet() throws Exception { 124 | // Given 125 | WrapObjectPlugin instance = new WrapObjectPlugin(); 126 | instance.getProperties().put(WrapObjectPlugin.TABLE_NAME, TABLE_NAME); 127 | 128 | // When 129 | List warnings = new ArrayList<>(); 130 | boolean ok = instance.validate(warnings); 131 | 132 | // Then 133 | assertThat(ok).isFalse(); 134 | assertThat(warnings).hasSize(1); 135 | } 136 | 137 | @Test 138 | public void shouldBeUnvalidIfObjectClassCannotBeLoaded() throws Exception { 139 | // Given 140 | WrapObjectPlugin instance = new WrapObjectPlugin(); 141 | instance.getProperties().put(WrapObjectPlugin.TABLE_NAME, TABLE_NAME); 142 | instance.getProperties().put(WrapObjectPlugin.OBJECT_CLASS, "class.does.not.Exists"); 143 | 144 | // When 145 | List warnings = new ArrayList<>(); 146 | boolean ok = instance.validate(warnings); 147 | 148 | // Then 149 | assertThat(ok).isFalse(); 150 | assertThat(warnings).hasSize(1); 151 | } 152 | 153 | @Test 154 | public void shouldBeValidIfTableNameAndObjectClassAreSet() throws Exception { 155 | // Given 156 | WrapObjectPlugin instance = new WrapObjectPlugin(); 157 | instance.getProperties().put(WrapObjectPlugin.TABLE_NAME, TABLE_NAME); 158 | instance.getProperties().put(WrapObjectPlugin.OBJECT_CLASS, OBJECT_CLASS); 159 | 160 | // When 161 | List warnings = new ArrayList<>(); 162 | boolean ok = instance.validate(warnings); 163 | 164 | // Then 165 | assertThat(ok).isTrue(); 166 | assertThat(warnings).isEmpty(); 167 | } 168 | 169 | @Test 170 | public void shouldAcceptComaDelimitedIncludeList() throws Exception { 171 | // Given 172 | WrapObjectPlugin instance = new WrapObjectPlugin(); 173 | instance.getProperties().put(WrapObjectPlugin.TABLE_NAME, TABLE_NAME); 174 | instance.getProperties().put(WrapObjectPlugin.OBJECT_CLASS, OBJECT_CLASS); 175 | instance.getProperties().put(WrapObjectPlugin.INCLUDES, INCLUDES); 176 | 177 | // When 178 | List warnings = new ArrayList<>(); 179 | boolean ok = instance.validate(warnings); 180 | 181 | // Then 182 | assertThat(ok).isTrue(); 183 | assertThat(warnings).isEmpty(); 184 | assertThat(instance.getIncludes()).containsOnlyElementsOf(includeList); 185 | } 186 | 187 | @Test 188 | public void shouldAcceptComaDelimitedExcludeList() throws Exception { 189 | // Given 190 | WrapObjectPlugin instance = new WrapObjectPlugin(); 191 | instance.getProperties().put(WrapObjectPlugin.TABLE_NAME, TABLE_NAME); 192 | instance.getProperties().put(WrapObjectPlugin.OBJECT_CLASS, OBJECT_CLASS); 193 | instance.getProperties().put(WrapObjectPlugin.EXCLUDES, EXCLUDES); 194 | 195 | // When 196 | List warnings = new ArrayList<>(); 197 | boolean ok = instance.validate(warnings); 198 | 199 | // Then 200 | assertThat(ok).isTrue(); 201 | assertThat(warnings).isEmpty(); 202 | assertThat(instance.getExcludes()).containsOnlyElementsOf(excludeList); 203 | } 204 | 205 | @Test 206 | public void shouldAcceptValueForFieldName() throws Exception { 207 | // Given 208 | String objectFieldName = "fieldName"; 209 | WrapObjectPlugin instance = new WrapObjectPlugin(); 210 | instance.getProperties().put(WrapObjectPlugin.TABLE_NAME, TABLE_NAME); 211 | instance.getProperties().put(WrapObjectPlugin.OBJECT_CLASS, OBJECT_CLASS); 212 | instance.getProperties().put(WrapObjectPlugin.OBJECT_FIELD_NAME, objectFieldName); 213 | 214 | // When 215 | List warnings = new ArrayList<>(); 216 | boolean ok = instance.validate(warnings); 217 | 218 | // Then 219 | assertThat(ok).isTrue(); 220 | assertThat(warnings).isEmpty(); 221 | assertThat(instance.getObjectFieldName()).isEqualTo(objectFieldName); 222 | } 223 | 224 | @Test 225 | public void shouldNotModifyModelBaseRecordClassIfTableDoesNotMatch() throws Exception { 226 | // Given 227 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn("wrong_name"); 228 | 229 | // When 230 | boolean ok = plugin.modelBaseRecordClassGenerated(topLevelClass, introspectedTable); 231 | 232 | // Then 233 | assertThat(ok).isTrue(); 234 | verify(topLevelClass, times(0)).addField(any(Field.class)); 235 | } 236 | 237 | @Test 238 | public void shouldAddWrappedObjectFieldToModelBaseRecordClass() throws Exception { 239 | // Given 240 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 241 | 242 | // When 243 | boolean ok = plugin.modelBaseRecordClassGenerated(topLevelClass, introspectedTable); 244 | 245 | // Then 246 | assertThat(ok).isTrue(); 247 | 248 | ArgumentCaptor fieldCaptor = ArgumentCaptor.forClass(Field.class); 249 | ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(FullyQualifiedJavaType.class); 250 | 251 | verify(topLevelClass).addField(fieldCaptor.capture()); 252 | verify(topLevelClass).addImportedType(typeCaptor.capture()); 253 | 254 | Field field = fieldCaptor.getValue(); 255 | FullyQualifiedJavaType type = typeCaptor.getValue(); 256 | 257 | assertThat(field).isNotNull(); 258 | assertThat(type).isNotNull(); 259 | 260 | assertThat(field.getName()).isEqualTo(OBJECT_FIELD_NAME); 261 | assertThat(field.getType()).isEqualTo(type); 262 | assertThat(field.getType().getFullyQualifiedName()).isEqualTo(OBJECT_CLASS); 263 | assertThat(field.getVisibility()).isEqualTo(JavaVisibility.PROTECTED); 264 | assertThat(field.getInitializationString()).isNotNull(); 265 | assertThat(field.getJavaDocLines()).contains(" * @mbggenerated"); 266 | } 267 | 268 | @Test 269 | public void shouldKeepFieldIfTableDoesNotMatch() throws Exception { 270 | // Given 271 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn("wrong_name"); 272 | 273 | // When 274 | boolean ok = plugin.modelFieldGenerated(field, topLevelClass, introspectedColumn, introspectedTable, null); 275 | 276 | // Then 277 | assertThat(ok).isTrue(); 278 | } 279 | 280 | @Test 281 | public void shouldKeepFieldIfNotInIncludeList() throws Exception { 282 | // Given 283 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 284 | given(field.getName()).willReturn("notInList"); 285 | 286 | // When 287 | boolean ok = plugin.modelFieldGenerated(field, topLevelClass, introspectedColumn, introspectedTable, null); 288 | 289 | // Then 290 | assertThat(ok).isTrue(); 291 | } 292 | 293 | @Test 294 | public void shouldKeepFieldIfInExcludeList() throws Exception { 295 | // Given 296 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 297 | given(field.getName()).willReturn(excludeList.get(0)); 298 | 299 | // When 300 | boolean ok = plugin.modelFieldGenerated(field, topLevelClass, introspectedColumn, introspectedTable, null); 301 | 302 | // Then 303 | assertThat(ok).isTrue(); 304 | } 305 | 306 | @Test 307 | public void shouldKeepFieldIfItHasNoGetter() throws Exception { 308 | FullyQualifiedJavaType type = new FullyQualifiedJavaType(String.class.getName()); 309 | 310 | // Given 311 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 312 | given(field.getName()).willReturn("address"); 313 | given(field.getType()).willReturn(type); 314 | 315 | // When 316 | boolean ok = plugin.modelFieldGenerated(field, topLevelClass, introspectedColumn, introspectedTable, null); 317 | 318 | // Then 319 | assertThat(ok).isTrue(); 320 | } 321 | 322 | @Test 323 | public void shouldNotGeneratedFieldIfItIsWrapped() throws Exception { 324 | FullyQualifiedJavaType type = new FullyQualifiedJavaType(String.class.getName()); 325 | 326 | // Given 327 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 328 | given(field.getName()).willReturn("name"); 329 | given(field.getType()).willReturn(type); 330 | 331 | // When 332 | boolean ok = plugin.modelFieldGenerated(field, topLevelClass, introspectedColumn, introspectedTable, null); 333 | 334 | // Then 335 | assertThat(ok).isFalse(); 336 | verify(topLevelClass).addImportedType(eq(type)); 337 | } 338 | 339 | @Test 340 | public void shouldHandleBooleanPrimitiveFieldType() throws Exception { 341 | FullyQualifiedJavaType type = FullyQualifiedJavaType.getBooleanPrimitiveInstance(); 342 | 343 | // Given 344 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 345 | given(field.getName()).willReturn("homeAddress"); 346 | given(field.getType()).willReturn(type); 347 | 348 | // When 349 | boolean ok = plugin.modelFieldGenerated(field, topLevelClass, introspectedColumn, introspectedTable, null); 350 | 351 | // Then 352 | assertThat(ok).isFalse(); 353 | verify(topLevelClass).addImportedType(eq(type)); 354 | } 355 | 356 | @Test 357 | public void shouldHandleBooleanObjectType() throws Exception { 358 | FullyQualifiedJavaType type = new FullyQualifiedJavaType(Boolean.class.getName()); 359 | 360 | // Given 361 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 362 | given(field.getName()).willReturn("workAddress"); 363 | given(field.getType()).willReturn(type); 364 | 365 | // When 366 | boolean ok = plugin.modelFieldGenerated(field, topLevelClass, introspectedColumn, introspectedTable, null); 367 | 368 | // Then 369 | assertThat(ok).isFalse(); 370 | verify(topLevelClass).addImportedType(eq(type)); 371 | } 372 | 373 | @Test 374 | public void shouldHandleMixedBooleanPrimitiveObjectType() throws Exception { 375 | FullyQualifiedJavaType type = new FullyQualifiedJavaType(Boolean.class.getName()); 376 | 377 | // Given 378 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 379 | given(field.getName()).willReturn("homeAddress"); 380 | given(field.getType()).willReturn(type); 381 | 382 | // When 383 | boolean ok = plugin.modelFieldGenerated(field, topLevelClass, introspectedColumn, introspectedTable, null); 384 | 385 | // Then 386 | assertThat(ok).isFalse(); 387 | verify(topLevelClass).addImportedType(eq(type)); 388 | } 389 | 390 | @Test 391 | public void shouldHandleMixedBooleanObjectPrimitiveType() throws Exception { 392 | FullyQualifiedJavaType type = FullyQualifiedJavaType.getBooleanPrimitiveInstance(); 393 | 394 | // Given 395 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 396 | given(field.getName()).willReturn("workAddress"); 397 | given(field.getType()).willReturn(type); 398 | 399 | // When 400 | boolean ok = plugin.modelFieldGenerated(field, topLevelClass, introspectedColumn, introspectedTable, null); 401 | 402 | // Then 403 | assertThat(ok).isFalse(); 404 | verify(topLevelClass).addImportedType(eq(type)); 405 | } 406 | 407 | @Test 408 | public void shouldNotModifyGetterWhenTableDoesNotMatch() throws Exception { 409 | // Given 410 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn("wrong_name"); 411 | 412 | // When 413 | boolean ok = plugin.modelGetterMethodGenerated(method, topLevelClass, introspectedColumn, introspectedTable, null); 414 | 415 | // Then 416 | assertThat(ok).isTrue(); 417 | assertThat(methodLines).hasSize(3); 418 | verify(method, times(0)).getBodyLines(); 419 | verify(method, times(0)).addBodyLine(anyString()); 420 | } 421 | 422 | @Test 423 | public void shouldNotModifyGetterWhenPropertyIsNotWrapped() throws Exception { 424 | // Given 425 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 426 | plugin.getGettersToWrap().clear(); 427 | plugin.getWrappedGetters().clear(); 428 | 429 | // When 430 | boolean ok = plugin.modelGetterMethodGenerated(method, topLevelClass, introspectedColumn, introspectedTable, null); 431 | 432 | // Then 433 | assertThat(ok).isTrue(); 434 | assertThat(methodLines).hasSize(3); 435 | verify(method, times(0)).getBodyLines(); 436 | verify(method, times(0)).addBodyLine(anyString()); 437 | } 438 | 439 | @Test 440 | public void shouldReplaceGetterToCallWrappedProperty() throws Exception { 441 | // Given 442 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 443 | given(method.getName()).willReturn("getName"); 444 | plugin.getGettersToWrap().add("getName"); 445 | plugin.getWrappedGetters().put("getName", "getName"); 446 | 447 | // When 448 | boolean ok = plugin.modelGetterMethodGenerated(method, topLevelClass, introspectedColumn, introspectedTable, null); 449 | 450 | // Then 451 | assertThat(ok).isTrue(); 452 | assertThat(methodLines).hasSize(1); 453 | verify(method).getBodyLines(); 454 | verify(method).addBodyLine(anyString()); 455 | } 456 | 457 | @Test 458 | public void shouldNotModifySetterWhenTableDoesNotMatch() throws Exception { 459 | // Given 460 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn("wrong_name"); 461 | 462 | // When 463 | boolean ok = plugin.modelSetterMethodGenerated(method, topLevelClass, introspectedColumn, introspectedTable, null); 464 | 465 | // Then 466 | assertThat(ok).isTrue(); 467 | assertThat(methodLines).hasSize(3); 468 | verify(method, times(0)).getBodyLines(); 469 | verify(method, times(0)).addBodyLine(anyString()); 470 | } 471 | 472 | @Test 473 | public void shouldNotModifySetterWhenPropertyIsNotWrapped() throws Exception { 474 | // Given 475 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 476 | plugin.getSettersToWrap().clear(); 477 | 478 | // When 479 | boolean ok = plugin.modelSetterMethodGenerated(method, topLevelClass, introspectedColumn, introspectedTable, null); 480 | 481 | // Then 482 | assertThat(ok).isTrue(); 483 | assertThat(methodLines).hasSize(3); 484 | verify(method, times(0)).getBodyLines(); 485 | verify(method, times(0)).addBodyLine(anyString()); 486 | } 487 | 488 | @Test 489 | public void shouldReplaceSetterToCallWrappedProperty() throws Exception { 490 | Parameter parameter = new Parameter(FullyQualifiedJavaType.getStringInstance(), "name"); 491 | List parameters = new ArrayList<>(); 492 | parameters.add(parameter); 493 | 494 | // Given 495 | given(introspectedTable.getFullyQualifiedTableNameAtRuntime()).willReturn(TABLE_NAME); 496 | given(method.getName()).willReturn("setName"); 497 | given(method.getParameters()).willReturn(parameters); 498 | plugin.getSettersToWrap().add("setName"); 499 | 500 | // When 501 | boolean ok = plugin.modelSetterMethodGenerated(method, topLevelClass, introspectedColumn, introspectedTable, null); 502 | 503 | // Then 504 | assertThat(ok).isTrue(); 505 | assertThat(methodLines).hasSize(1); 506 | verify(method).getBodyLines(); 507 | verify(method).addBodyLine(anyString()); 508 | } 509 | 510 | } 511 | -------------------------------------------------------------------------------- /src/test/java/com/github/dcendents/mybatis/generator/plugin/subpackage/CreateSubPackagePluginTest.java: -------------------------------------------------------------------------------- 1 | package com.github.dcendents.mybatis.generator.plugin.subpackage; 2 | 3 | import static org.assertj.core.api.Assertions.assertThat; 4 | import static org.mockito.BDDMockito.given; 5 | import static org.mockito.BDDMockito.willReturn; 6 | import static org.mockito.Matchers.anyBoolean; 7 | import static org.mockito.Matchers.eq; 8 | import static org.mockito.Mockito.spy; 9 | import static org.mockito.Mockito.times; 10 | import static org.mockito.Mockito.verify; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | import org.junit.Before; 16 | import org.junit.Test; 17 | import org.junit.runner.RunWith; 18 | import org.mockito.ArgumentCaptor; 19 | import org.mockito.Mock; 20 | import org.mockito.runners.MockitoJUnitRunner; 21 | import org.mybatis.generator.api.IntrospectedTable; 22 | import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; 23 | import org.mybatis.generator.api.dom.java.Interface; 24 | import org.mybatis.generator.api.dom.java.Method; 25 | import org.mybatis.generator.api.dom.java.Parameter; 26 | import org.mybatis.generator.api.dom.java.TopLevelClass; 27 | import org.mybatis.generator.api.dom.xml.Attribute; 28 | import org.mybatis.generator.api.dom.xml.Document; 29 | import org.mybatis.generator.api.dom.xml.XmlElement; 30 | 31 | /** 32 | * Tests for the class CreateSubPackagePlugin. 33 | */ 34 | @RunWith(MockitoJUnitRunner.class) 35 | public class CreateSubPackagePluginTest { 36 | 37 | private CreateSubPackagePlugin plugin; 38 | 39 | @Mock 40 | private RenameProperties modelProperties; 41 | @Mock 42 | private RenameProperties mapperProperties; 43 | @Mock 44 | private RenameProperties exampleProperties; 45 | 46 | @Mock 47 | private IntrospectedTable introspectedTable; 48 | @Mock 49 | private Method method; 50 | @Mock 51 | private Document document; 52 | @Mock 53 | private XmlElement element; 54 | @Mock 55 | private Interface interfaze; 56 | @Mock 57 | private TopLevelClass topLevelClass; 58 | 59 | private static final String MODEL_PACKAGE = "gen1"; 60 | private static final String MODEL_SUFFIX = "Gen2"; 61 | private static final String MAPPER_PACKAGE = "gen3"; 62 | private static final String MAPPER_SUFFIX = "Gen4"; 63 | private static final String EXAMPLE_PACKAGE = "filter1"; 64 | private static final String EXAMPLE_SUFFIX = "Filter2"; 65 | 66 | @Before 67 | public void init() throws Exception { 68 | plugin = new CreateSubPackagePlugin(modelProperties, mapperProperties, exampleProperties); 69 | 70 | plugin.getProperties().put(CreateSubPackagePlugin.MODEL_PACKAGE_PROPERTY, MODEL_PACKAGE); 71 | plugin.getProperties().put(CreateSubPackagePlugin.MODEL_CLASS_SUFFIX_PROPERTY, MODEL_SUFFIX); 72 | plugin.getProperties().put(CreateSubPackagePlugin.MAPPER_PACKAGE_PROPERTY, MAPPER_PACKAGE); 73 | plugin.getProperties().put(CreateSubPackagePlugin.MAPPER_CLASS_SUFFIX_PROPERTY, MAPPER_SUFFIX); 74 | plugin.getProperties().put(CreateSubPackagePlugin.EXAMPLE_PACKAGE_PROPERTY, EXAMPLE_PACKAGE); 75 | plugin.getProperties().put(CreateSubPackagePlugin.EXAMPLE_CLASS_SUFFIX_PROPERTY, EXAMPLE_SUFFIX); 76 | 77 | given(document.getRootElement()).willReturn(element); 78 | } 79 | 80 | @Test 81 | public void shouldHaveDefaultConstructor() throws Exception { 82 | // Given 83 | 84 | // When 85 | CreateSubPackagePlugin instance = new CreateSubPackagePlugin(); 86 | 87 | // Then 88 | assertThat(instance).isNotNull(); 89 | } 90 | 91 | @Test 92 | public void shouldBeValidIfAtLeastOneConfigurationIsSet() throws Exception { 93 | // Given 94 | given(modelProperties.isEnabled()).willReturn(true); 95 | 96 | // When 97 | List warnings = new ArrayList<>(); 98 | boolean ok = plugin.validate(warnings); 99 | 100 | // Then 101 | assertThat(ok).isTrue(); 102 | assertThat(warnings).isEmpty(); 103 | verify(modelProperties).validate(eq(MODEL_PACKAGE), eq(MODEL_SUFFIX)); 104 | verify(mapperProperties).validate(eq(MAPPER_PACKAGE), eq(MAPPER_SUFFIX)); 105 | verify(exampleProperties).validate(eq(EXAMPLE_PACKAGE), eq(EXAMPLE_SUFFIX)); 106 | } 107 | 108 | @Test 109 | public void shouldNotBeValidIfAllPropertiesAreDisabled() throws Exception { 110 | // Given 111 | 112 | // When 113 | List warnings = new ArrayList<>(); 114 | boolean ok = plugin.validate(warnings); 115 | 116 | // Then 117 | assertThat(ok).isFalse(); 118 | assertThat(warnings).isEmpty(); 119 | verify(modelProperties).validate(eq(MODEL_PACKAGE), eq(MODEL_SUFFIX)); 120 | verify(mapperProperties).validate(eq(MAPPER_PACKAGE), eq(MAPPER_SUFFIX)); 121 | verify(exampleProperties).validate(eq(EXAMPLE_PACKAGE), eq(EXAMPLE_SUFFIX)); 122 | } 123 | 124 | @Test 125 | public void shouldInitializeNewTypes() throws Exception { 126 | String baseRecordType = "baseRecordType"; 127 | String newBaseRecordType = "newBaseRecordType"; 128 | String javaMapperType = "javaMapperType"; 129 | String newJavaMapperType = "newJavaMapperType"; 130 | String exampleType = "exampleType"; 131 | String newExampleType = "newExampleType"; 132 | 133 | // Given 134 | given(introspectedTable.getBaseRecordType()).willReturn(baseRecordType); 135 | given(introspectedTable.getMyBatis3JavaMapperType()).willReturn(javaMapperType); 136 | given(introspectedTable.getExampleType()).willReturn(exampleType); 137 | 138 | given(modelProperties.setTypes(eq(baseRecordType))).willReturn(newBaseRecordType); 139 | given(mapperProperties.setTypes(eq(javaMapperType))).willReturn(newJavaMapperType); 140 | given(exampleProperties.setTypes(eq(exampleType))).willReturn(newExampleType); 141 | 142 | // When 143 | plugin.initialized(introspectedTable); 144 | 145 | // Then 146 | verify(introspectedTable).setBaseRecordType(eq(newBaseRecordType)); 147 | verify(introspectedTable).setMyBatis3JavaMapperType(eq(newJavaMapperType)); 148 | verify(introspectedTable).setExampleType(eq(newExampleType)); 149 | } 150 | 151 | @Test 152 | public void shouldRenameMethodTypes() throws Exception { 153 | FullyQualifiedJavaType returnType = new FullyQualifiedJavaType("returnType"); 154 | FullyQualifiedJavaType newReturnType = new FullyQualifiedJavaType("newReturnType"); 155 | 156 | // Given 157 | given(method.getReturnType()).willReturn(returnType); 158 | given(modelProperties.renameType(eq(returnType))).willReturn(newReturnType); 159 | 160 | // When 161 | plugin.renameMethod(method); 162 | 163 | // Then 164 | verify(method).setReturnType(eq(newReturnType)); 165 | } 166 | 167 | @Test 168 | public void shouldRenameMethodParameters() throws Exception { 169 | FullyQualifiedJavaType type = new FullyQualifiedJavaType("type"); 170 | FullyQualifiedJavaType renamedType = new FullyQualifiedJavaType("renamedType"); 171 | 172 | Parameter parameter = new Parameter(type, "name", "annotation"); 173 | List parameters = new ArrayList<>(); 174 | parameters.add(parameter); 175 | 176 | // Given 177 | given(method.getParameters()).willReturn(parameters); 178 | given(modelProperties.renameType(eq(type))).willReturn(renamedType); 179 | 180 | // When 181 | boolean ok = plugin.renameMethod(method); 182 | 183 | // Then 184 | assertThat(ok).isTrue(); 185 | assertThat(parameters).hasSize(1); 186 | 187 | Parameter newParameter = parameters.get(0); 188 | assertThat(newParameter).isNotSameAs(parameter); 189 | assertThat(newParameter.getType()).isEqualTo(renamedType); 190 | assertThat(newParameter.getName()).isEqualTo(parameter.getName()); 191 | assertThat(newParameter.getAnnotations()).containsExactlyElementsOf(parameter.getAnnotations()); 192 | } 193 | 194 | @Test 195 | public void shouldIgnoreMethodParametersOfDifferentType() throws Exception { 196 | FullyQualifiedJavaType type = new FullyQualifiedJavaType("type"); 197 | 198 | Parameter parameter = new Parameter(type, "name", "annotation"); 199 | List parameters = new ArrayList<>(); 200 | parameters.add(parameter); 201 | 202 | // Given 203 | given(method.getParameters()).willReturn(parameters); 204 | given(modelProperties.renameType(eq(type))).willReturn(type); 205 | 206 | // When 207 | boolean ok = plugin.renameMethod(method); 208 | 209 | // Then 210 | assertThat(ok).isTrue(); 211 | assertThat(parameters).hasSize(1); 212 | 213 | Parameter newParameter = parameters.get(0); 214 | assertThat(newParameter).isSameAs(parameter); 215 | } 216 | 217 | @Test 218 | public void shouldRenameMethodAnnotations() throws Exception { 219 | List annotations = new ArrayList<>(); 220 | annotations.add("@MultiLine({"); 221 | annotations.add("\" line1\","); 222 | annotations.add("\" line2 type\","); 223 | annotations.add("\" line3\","); 224 | annotations.add("})"); 225 | annotations.add("@SingleLine(\"type\")"); 226 | final int annotationsSize = annotations.size(); 227 | 228 | // Given 229 | given(method.getAnnotations()).willReturn(annotations); 230 | 231 | // When 232 | boolean ok = plugin.renameMethod(method); 233 | 234 | // Then 235 | assertThat(ok).isTrue(); 236 | assertThat(annotations).hasSize(annotationsSize); 237 | 238 | verify(modelProperties).renameAnnotations(eq(annotations)); 239 | verify(mapperProperties).renameAnnotations(eq(annotations)); 240 | } 241 | 242 | @Test 243 | public void shouldHandleElementWithoutAttribute() throws Exception { 244 | // Given 245 | 246 | // When 247 | boolean ok = plugin.renameElementAttribute(element, ""); 248 | 249 | // Then 250 | assertThat(ok).isTrue(); 251 | } 252 | 253 | @Test 254 | public void shouldIgnoreUnspecifiedElementAttribute() throws Exception { 255 | Attribute attribute = new Attribute("name", "value"); 256 | List attributes = new ArrayList<>(); 257 | attributes.add(attribute); 258 | 259 | // Given 260 | given(element.getAttributes()).willReturn(attributes); 261 | 262 | // When 263 | boolean ok = plugin.renameElementAttribute(element, "otherName"); 264 | 265 | // Then 266 | assertThat(ok).isTrue(); 267 | assertThat(attributes).hasSize(1); 268 | 269 | Attribute newAttribute = attributes.get(0); 270 | assertThat(newAttribute).isSameAs(attribute); 271 | } 272 | 273 | @Test 274 | public void shouldRenameModelElementAttribute() throws Exception { 275 | Attribute attribute = new Attribute("name", "value"); 276 | List attributes = new ArrayList<>(); 277 | attributes.add(attribute); 278 | 279 | Attribute renamedAttribute = new Attribute("name", "newValue"); 280 | 281 | // Given 282 | given(element.getAttributes()).willReturn(attributes); 283 | given(modelProperties.renameAttribute(eq(attribute))).willReturn(renamedAttribute); 284 | given(mapperProperties.renameAttribute(eq(renamedAttribute))).willReturn(renamedAttribute); 285 | 286 | // When 287 | boolean ok = plugin.renameElementAttribute(element, "name"); 288 | 289 | // Then 290 | assertThat(ok).isTrue(); 291 | assertThat(attributes).hasSize(1); 292 | 293 | Attribute newAttribute = attributes.get(0); 294 | assertThat(newAttribute).isNotSameAs(attribute); 295 | assertThat(newAttribute).isSameAs(renamedAttribute); 296 | } 297 | 298 | @Test 299 | public void shouldRenameMapperElementAttribute() throws Exception { 300 | Attribute attribute = new Attribute("name", "value"); 301 | List attributes = new ArrayList<>(); 302 | attributes.add(attribute); 303 | 304 | Attribute renamedAttribute = new Attribute("name", "newValue"); 305 | 306 | // Given 307 | given(element.getAttributes()).willReturn(attributes); 308 | given(modelProperties.renameAttribute(eq(attribute))).willReturn(attribute); 309 | given(mapperProperties.renameAttribute(eq(attribute))).willReturn(renamedAttribute); 310 | 311 | // When 312 | boolean ok = plugin.renameElementAttribute(element, "name"); 313 | 314 | // Then 315 | assertThat(ok).isTrue(); 316 | assertThat(attributes).hasSize(1); 317 | 318 | Attribute newAttribute = attributes.get(0); 319 | assertThat(newAttribute).isNotSameAs(attribute); 320 | assertThat(newAttribute).isSameAs(renamedAttribute); 321 | } 322 | 323 | @Test 324 | public void shouldRenameNamespaceOfSqlMap() throws Exception { 325 | CreateSubPackagePlugin plugin = spy(this.plugin); 326 | 327 | // Given 328 | willReturn(true).given(plugin).renameElementAttribute(eq(element), 329 | eq(CreateSubPackagePlugin.ATTRIBUTE_NAMESPACE)); 330 | 331 | // When 332 | boolean ok = plugin.sqlMapDocumentGenerated(document, null); 333 | 334 | // Then 335 | assertThat(ok).isTrue(); 336 | verify(plugin).renameElementAttribute(eq(element), eq(CreateSubPackagePlugin.ATTRIBUTE_NAMESPACE)); 337 | } 338 | 339 | @Test 340 | public void shouldRenameTypeOfSqlMapWithoutBlobs() throws Exception { 341 | CreateSubPackagePlugin plugin = spy(this.plugin); 342 | 343 | // Given 344 | willReturn(true).given(plugin).renameElementAttribute(eq(element), 345 | eq(CreateSubPackagePlugin.ATTRIBUTE_TYPE)); 346 | 347 | // When 348 | boolean ok = plugin.sqlMapResultMapWithoutBLOBsElementGenerated(element, null); 349 | 350 | // Then 351 | assertThat(ok).isTrue(); 352 | verify(plugin).renameElementAttribute(eq(element), eq(CreateSubPackagePlugin.ATTRIBUTE_TYPE)); 353 | } 354 | 355 | @Test 356 | public void shouldRenameTypeOfSqlMapWithBlobs() throws Exception { 357 | CreateSubPackagePlugin plugin = spy(this.plugin); 358 | 359 | // Given 360 | willReturn(true).given(plugin).renameElementAttribute(eq(element), 361 | eq(CreateSubPackagePlugin.ATTRIBUTE_TYPE)); 362 | 363 | // When 364 | boolean ok = plugin.sqlMapResultMapWithBLOBsElementGenerated(element, null); 365 | 366 | // Then 367 | assertThat(ok).isTrue(); 368 | verify(plugin).renameElementAttribute(eq(element), eq(CreateSubPackagePlugin.ATTRIBUTE_TYPE)); 369 | } 370 | 371 | @Test 372 | public void shouldRenameMethodOfClientSelectByPrimaryKey() throws Exception { 373 | CreateSubPackagePlugin plugin = spy(this.plugin); 374 | 375 | // Given 376 | willReturn(true).given(plugin).renameMethod(method); 377 | 378 | // When 379 | boolean ok1 = plugin.clientSelectByPrimaryKeyMethodGenerated(method, interfaze, introspectedTable); 380 | boolean ok2 = plugin.clientSelectByPrimaryKeyMethodGenerated(method, topLevelClass, introspectedTable); 381 | 382 | // Then 383 | assertThat(ok1).isTrue(); 384 | assertThat(ok2).isTrue(); 385 | verify(plugin, times(2)).renameMethod(eq(method)); 386 | } 387 | 388 | @Test 389 | public void shouldRenameMethodOfClientCountByExample() throws Exception { 390 | CreateSubPackagePlugin plugin = spy(this.plugin); 391 | 392 | // Given 393 | willReturn(true).given(plugin).renameMethod(method); 394 | 395 | // When 396 | boolean ok1 = plugin.clientCountByExampleMethodGenerated(method, interfaze, introspectedTable); 397 | boolean ok2 = plugin.clientCountByExampleMethodGenerated(method, topLevelClass, introspectedTable); 398 | 399 | // Then 400 | assertThat(ok1).isTrue(); 401 | assertThat(ok2).isTrue(); 402 | verify(plugin, times(2)).renameMethod(eq(method)); 403 | } 404 | 405 | @Test 406 | public void shouldRenameMethodOfClientDeleteByExample() throws Exception { 407 | CreateSubPackagePlugin plugin = spy(this.plugin); 408 | 409 | // Given 410 | willReturn(true).given(plugin).renameMethod(method); 411 | 412 | // When 413 | boolean ok1 = plugin.clientDeleteByExampleMethodGenerated(method, interfaze, introspectedTable); 414 | boolean ok2 = plugin.clientDeleteByExampleMethodGenerated(method, topLevelClass, introspectedTable); 415 | 416 | // Then 417 | assertThat(ok1).isTrue(); 418 | assertThat(ok2).isTrue(); 419 | verify(plugin, times(2)).renameMethod(eq(method)); 420 | } 421 | 422 | @Test 423 | public void shouldRenameMethodOfClientDeleteByPrimaryKey() throws Exception { 424 | CreateSubPackagePlugin plugin = spy(this.plugin); 425 | 426 | // Given 427 | willReturn(true).given(plugin).renameMethod(method); 428 | 429 | // When 430 | boolean ok1 = plugin.clientDeleteByPrimaryKeyMethodGenerated(method, interfaze, introspectedTable); 431 | boolean ok2 = plugin.clientDeleteByPrimaryKeyMethodGenerated(method, topLevelClass, introspectedTable); 432 | 433 | // Then 434 | assertThat(ok1).isTrue(); 435 | assertThat(ok2).isTrue(); 436 | verify(plugin, times(2)).renameMethod(eq(method)); 437 | } 438 | 439 | @Test 440 | public void shouldRenameMethodOfClientInsert() throws Exception { 441 | CreateSubPackagePlugin plugin = spy(this.plugin); 442 | 443 | // Given 444 | willReturn(true).given(plugin).renameMethod(method); 445 | 446 | // When 447 | boolean ok1 = plugin.clientInsertMethodGenerated(method, interfaze, introspectedTable); 448 | boolean ok2 = plugin.clientInsertMethodGenerated(method, topLevelClass, introspectedTable); 449 | 450 | // Then 451 | assertThat(ok1).isTrue(); 452 | assertThat(ok2).isTrue(); 453 | verify(plugin, times(2)).renameMethod(eq(method)); 454 | } 455 | 456 | @Test 457 | public void shouldRenameMethodOfClientSelectByExampleWithBLOBs() throws Exception { 458 | CreateSubPackagePlugin plugin = spy(this.plugin); 459 | 460 | // Given 461 | willReturn(true).given(plugin).renameMethod(method); 462 | 463 | // When 464 | boolean ok1 = plugin.clientSelectByExampleWithBLOBsMethodGenerated(method, interfaze, introspectedTable); 465 | boolean ok2 = plugin.clientSelectByExampleWithBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 466 | 467 | // Then 468 | assertThat(ok1).isTrue(); 469 | assertThat(ok2).isTrue(); 470 | verify(plugin, times(2)).renameMethod(eq(method)); 471 | } 472 | 473 | @Test 474 | public void shouldRenameMethodOfClientSelectByExampleWithoutBLOBs() throws Exception { 475 | CreateSubPackagePlugin plugin = spy(this.plugin); 476 | 477 | // Given 478 | willReturn(true).given(plugin).renameMethod(method); 479 | 480 | // When 481 | boolean ok1 = plugin.clientSelectByExampleWithoutBLOBsMethodGenerated(method, interfaze, introspectedTable); 482 | boolean ok2 = plugin.clientSelectByExampleWithoutBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 483 | 484 | // Then 485 | assertThat(ok1).isTrue(); 486 | assertThat(ok2).isTrue(); 487 | verify(plugin, times(2)).renameMethod(eq(method)); 488 | } 489 | 490 | @Test 491 | public void shouldRenameMethodOfClientUpdateByExampleSelective() throws Exception { 492 | CreateSubPackagePlugin plugin = spy(this.plugin); 493 | 494 | // Given 495 | willReturn(true).given(plugin).renameMethod(method); 496 | 497 | // When 498 | boolean ok1 = plugin.clientUpdateByExampleSelectiveMethodGenerated(method, interfaze, introspectedTable); 499 | boolean ok2 = plugin.clientUpdateByExampleSelectiveMethodGenerated(method, topLevelClass, introspectedTable); 500 | 501 | // Then 502 | assertThat(ok1).isTrue(); 503 | assertThat(ok2).isTrue(); 504 | verify(plugin, times(2)).renameMethod(eq(method)); 505 | } 506 | 507 | @Test 508 | public void shouldRenameMethodOfClientUpdateByExampleWithBLOBs() throws Exception { 509 | CreateSubPackagePlugin plugin = spy(this.plugin); 510 | 511 | // Given 512 | willReturn(true).given(plugin).renameMethod(method); 513 | 514 | // When 515 | boolean ok1 = plugin.clientUpdateByExampleWithBLOBsMethodGenerated(method, interfaze, introspectedTable); 516 | boolean ok2 = plugin.clientUpdateByExampleWithBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 517 | 518 | // Then 519 | assertThat(ok1).isTrue(); 520 | assertThat(ok2).isTrue(); 521 | verify(plugin, times(2)).renameMethod(eq(method)); 522 | } 523 | 524 | @Test 525 | public void shouldRenameMethodOfClientUpdateByExampleWithoutBLOBs() throws Exception { 526 | CreateSubPackagePlugin plugin = spy(this.plugin); 527 | 528 | // Given 529 | willReturn(true).given(plugin).renameMethod(method); 530 | 531 | // When 532 | boolean ok1 = plugin.clientUpdateByExampleWithoutBLOBsMethodGenerated(method, interfaze, introspectedTable); 533 | boolean ok2 = plugin.clientUpdateByExampleWithoutBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 534 | 535 | // Then 536 | assertThat(ok1).isTrue(); 537 | assertThat(ok2).isTrue(); 538 | verify(plugin, times(2)).renameMethod(eq(method)); 539 | } 540 | 541 | @Test 542 | public void shouldRenameMethodOfClientUpdateByPrimaryKeySelective() throws Exception { 543 | CreateSubPackagePlugin plugin = spy(this.plugin); 544 | 545 | // Given 546 | willReturn(true).given(plugin).renameMethod(method); 547 | 548 | // When 549 | boolean ok1 = plugin.clientUpdateByPrimaryKeySelectiveMethodGenerated(method, interfaze, introspectedTable); 550 | boolean ok2 = plugin.clientUpdateByPrimaryKeySelectiveMethodGenerated(method, topLevelClass, introspectedTable); 551 | 552 | // Then 553 | assertThat(ok1).isTrue(); 554 | assertThat(ok2).isTrue(); 555 | verify(plugin, times(2)).renameMethod(eq(method)); 556 | } 557 | 558 | @Test 559 | public void shouldRenameMethodOfClientUpdateByPrimaryKeyWithBLOBs() throws Exception { 560 | CreateSubPackagePlugin plugin = spy(this.plugin); 561 | 562 | // Given 563 | willReturn(true).given(plugin).renameMethod(method); 564 | 565 | // When 566 | boolean ok1 = plugin.clientUpdateByPrimaryKeyWithBLOBsMethodGenerated(method, interfaze, introspectedTable); 567 | boolean ok2 = plugin.clientUpdateByPrimaryKeyWithBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 568 | 569 | // Then 570 | assertThat(ok1).isTrue(); 571 | assertThat(ok2).isTrue(); 572 | verify(plugin, times(2)).renameMethod(eq(method)); 573 | } 574 | 575 | @Test 576 | public void shouldRenameMethodOfClientUpdateByPrimaryKeyWithoutBLOBs() throws Exception { 577 | CreateSubPackagePlugin plugin = spy(this.plugin); 578 | 579 | // Given 580 | willReturn(true).given(plugin).renameMethod(method); 581 | 582 | // When 583 | boolean ok1 = plugin.clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(method, interfaze, introspectedTable); 584 | boolean ok2 = plugin.clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(method, topLevelClass, introspectedTable); 585 | 586 | // Then 587 | assertThat(ok1).isTrue(); 588 | assertThat(ok2).isTrue(); 589 | verify(plugin, times(2)).renameMethod(eq(method)); 590 | } 591 | 592 | @Test 593 | public void shouldRenameMethodOfClientInsertSelective() throws Exception { 594 | CreateSubPackagePlugin plugin = spy(this.plugin); 595 | 596 | // Given 597 | willReturn(true).given(plugin).renameMethod(method); 598 | 599 | // When 600 | boolean ok1 = plugin.clientInsertSelectiveMethodGenerated(method, interfaze, introspectedTable); 601 | boolean ok2 = plugin.clientInsertSelectiveMethodGenerated(method, topLevelClass, introspectedTable); 602 | 603 | // Then 604 | assertThat(ok1).isTrue(); 605 | assertThat(ok2).isTrue(); 606 | verify(plugin, times(2)).renameMethod(eq(method)); 607 | } 608 | 609 | @Test 610 | public void shouldRenameMethodOfClientSelectAll() throws Exception { 611 | CreateSubPackagePlugin plugin = spy(this.plugin); 612 | 613 | // Given 614 | willReturn(true).given(plugin).renameMethod(method); 615 | 616 | // When 617 | boolean ok1 = plugin.clientSelectAllMethodGenerated(method, interfaze, introspectedTable); 618 | boolean ok2 = plugin.clientSelectAllMethodGenerated(method, topLevelClass, introspectedTable); 619 | 620 | // Then 621 | assertThat(ok1).isTrue(); 622 | assertThat(ok2).isTrue(); 623 | verify(plugin, times(2)).renameMethod(eq(method)); 624 | } 625 | 626 | @Test 627 | public void shouldAddImportedTypesToClient() throws Exception { 628 | String type = "someType"; 629 | 630 | // Given 631 | given(modelProperties.getOriginalType()).willReturn(type); 632 | 633 | // When 634 | boolean ok = plugin.clientGenerated(interfaze, topLevelClass, introspectedTable); 635 | 636 | // Then 637 | assertThat(ok).isTrue(); 638 | 639 | ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(FullyQualifiedJavaType.class); 640 | 641 | verify(interfaze).addImportedType(typeCaptor.capture()); 642 | FullyQualifiedJavaType interfaceType = typeCaptor.getValue(); 643 | assertThat(interfaceType).isNotNull(); 644 | assertThat(interfaceType.getFullyQualifiedName()).isEqualTo(type); 645 | 646 | verify(topLevelClass).addImportedType(typeCaptor.capture()); 647 | FullyQualifiedJavaType classType = typeCaptor.getValue(); 648 | assertThat(classType).isNotNull(); 649 | assertThat(classType.getFullyQualifiedName()).isEqualTo(type); 650 | } 651 | 652 | @Test 653 | public void shouldHandleClientNullValues() throws Exception { 654 | String type = "someType"; 655 | 656 | // Given 657 | given(modelProperties.getOriginalType()).willReturn(type); 658 | 659 | // When 660 | boolean ok = plugin.clientGenerated(null, null, null); 661 | 662 | // Then 663 | assertThat(ok).isTrue(); 664 | } 665 | 666 | @Test 667 | public void shouldSetBaseClassAbstract() throws Exception { 668 | // Given 669 | given(modelProperties.isEnabled()).willReturn(true); 670 | 671 | // When 672 | boolean ok = plugin.modelBaseRecordClassGenerated(topLevelClass, introspectedTable); 673 | 674 | // Then 675 | assertThat(ok).isTrue(); 676 | verify(topLevelClass).setAbstract(eq(true)); 677 | } 678 | 679 | @Test 680 | public void shouldNotSetBaseClassAbstractIfDisabled() throws Exception { 681 | // Given 682 | given(modelProperties.isEnabled()).willReturn(false); 683 | 684 | // When 685 | boolean ok = plugin.modelBaseRecordClassGenerated(topLevelClass, introspectedTable); 686 | 687 | // Then 688 | assertThat(ok).isTrue(); 689 | verify(topLevelClass, times(0)).setAbstract(anyBoolean()); 690 | } 691 | } 692 | --------------------------------------------------------------------------------