diff --git a/README_zh.md b/README_zh.md
index d5d4d678f30e20573039f4ac0810e5095a0e0c26..585114fbbee4c12c1301b1fab2fed99a42f18b09 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -171,7 +171,7 @@ public class UserRepositoryIntegrationTest {
```xml
io.easybest
- spring-boot-starter-data-mybatis
+ spring-data-mybatis-boot-starter
2.0.1.RELEASE
```
diff --git a/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfiguration.java b/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfiguration.java
index 8a0f8aee184b7e4d7896972cce3d407cf9a8bab7..c91308b984efc1e39d0dab287ac6a086bf0282ee 100644
--- a/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfiguration.java
+++ b/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfiguration.java
@@ -15,20 +15,29 @@
*/
package org.springframework.data.mybatis.autoconfigure;
+import java.util.List;
+
import javax.sql.DataSource;
+import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.domain.EntityScanPackages;
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
+import org.springframework.data.mybatis.mapping.MybatisEntityClassScanner;
+import org.springframework.data.mybatis.mapping.MybatisMappingContext;
import org.springframework.data.mybatis.repository.MybatisRepository;
import org.springframework.data.mybatis.repository.config.EnableMybatisRepositories;
import org.springframework.data.mybatis.repository.config.MybatisRepositoryConfigExtension;
@@ -57,11 +66,27 @@ import org.springframework.data.mybatis.repository.support.MybatisRepositoryFact
@ConditionalOnBean(DataSource.class)
@ConditionalOnClass(MybatisRepository.class)
@ConditionalOnMissingBean({ MybatisRepositoryFactoryBean.class, MybatisRepositoryConfigExtension.class })
-@ConditionalOnProperty(prefix = "spring.data.mybatis.repositories", name = "enabled", havingValue = "true",
+@ConditionalOnProperty(prefix = SpringDataMybatisProperties.PREFIX, name = "enabled", havingValue = "true",
matchIfMissing = true)
@Import(MybatisRepositoriesAutoConfigureRegistrar.class)
@AutoConfigureAfter({ MybatisAutoConfiguration.class, TaskExecutionAutoConfiguration.class })
@EnableConfigurationProperties(SpringDataMybatisProperties.class)
public class MybatisRepositoriesAutoConfiguration {
+ @Bean
+ @ConditionalOnMissingBean
+ public MybatisMappingContext mybatisMappingContext(BeanFactory beanFactory, SqlSessionTemplate sqlSessionTemplate)
+ throws ClassNotFoundException {
+ MybatisMappingContext context = new MybatisMappingContext(sqlSessionTemplate);
+
+ List packages = EntityScanPackages.get(beanFactory).getPackageNames();
+ if (packages.isEmpty() && AutoConfigurationPackages.has(beanFactory)) {
+ packages = AutoConfigurationPackages.get(beanFactory);
+ }
+ if (!packages.isEmpty()) {
+ context.setInitialEntitySet(MybatisEntityClassScanner.scan(packages));
+ }
+ return context;
+ }
+
}
diff --git a/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfigureRegistrar.java b/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfigureRegistrar.java
index 04750d75683a34672ccf95458efca0cbabfd65e0..547fc7ba054de174f6a9b20ed62095c303bf0803 100644
--- a/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfigureRegistrar.java
+++ b/spring-data-mybatis-boot-starter/src/main/java/org/springframework/data/mybatis/autoconfigure/MybatisRepositoriesAutoConfigureRegistrar.java
@@ -21,7 +21,6 @@ import java.util.Locale;
import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
-import org.springframework.core.io.ResourceLoader;
import org.springframework.data.mybatis.repository.config.EnableMybatisRepositories;
import org.springframework.data.mybatis.repository.config.MybatisRepositoryConfigExtension;
import org.springframework.data.repository.config.BootstrapMode;
@@ -38,8 +37,6 @@ class MybatisRepositoriesAutoConfigureRegistrar extends AbstractRepositoryConfig
private BootstrapMode bootstrapMode = null;
- private ResourceLoader resourceLoader;
-
@Override
protected Class extends Annotation> getAnnotation() {
return EnableMybatisRepositories.class;
@@ -52,7 +49,7 @@ class MybatisRepositoriesAutoConfigureRegistrar extends AbstractRepositoryConfig
@Override
protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {
- return new MybatisRepositoryConfigExtension(this.resourceLoader);
+ return new MybatisRepositoryConfigExtension();
}
@Override
@@ -73,12 +70,6 @@ class MybatisRepositoriesAutoConfigureRegistrar extends AbstractRepositoryConfig
}
}
- @Override
- public void setResourceLoader(ResourceLoader resourceLoader) {
- this.resourceLoader = resourceLoader;
- super.setResourceLoader(resourceLoader);
- }
-
@EnableMybatisRepositories
private static class EnableMybatisRepositoriesConfiguration {
diff --git a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/FieldNamingStrategy.java b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/Fetch.java
similarity index 83%
rename from spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/FieldNamingStrategy.java
rename to spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/Fetch.java
index 280cc6d558ddeee6c032d45f9764dc878c959bdd..926184071c08ea8c7839a6bf996d26bef60080b5 100644
--- a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/FieldNamingStrategy.java
+++ b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/Fetch.java
@@ -21,14 +21,15 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- * Specify field naming strategy for property.
+ * Define the fetching strategy used for the given association.
+ *
* @author JARVIS SONG
- * @since 2.0.0
+ * @since 2.0.2
*/
-@Target({ ElementType.TYPE })
+@Target({ ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
-public @interface FieldNamingStrategy {
+public @interface Fetch {
- String value() default "";
+ FetchMode value();
}
diff --git a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/FetchMode.java b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/FetchMode.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce90f4f2c02158e68c88b45c130a13932e285855
--- /dev/null
+++ b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/FetchMode.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.annotation;
+
+/**
+ * Fetch options on associations. Defines more of the "how" of fetching, whereas JPA
+ * {@link javax.persistence.FetchType} focuses on the "when".
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public enum FetchMode {
+
+ /**
+ * Use a secondary select for each individual entity, collection, or join load.
+ */
+ SELECT,
+ /**
+ * Use an outer join to load the related entities, collections or joins.
+ */
+ JOIN,
+ /**
+ * Available for collections only. When accessing a non-initialized collection, this
+ * fetch mode will trigger loading all elements of all collections of the same role
+ * for all owners associated with the persistence context using a single secondary
+ * select.
+ */
+ SUBSELECT
+
+}
diff --git a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/JdbcType.java b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/JdbcType.java
index 94a7fee7a306d264d318776b0aafecde9733b3fe..b72dcbdf75db93d9c391ab390c867160dbf696d0 100644
--- a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/JdbcType.java
+++ b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/JdbcType.java
@@ -29,6 +29,6 @@ import java.lang.annotation.Target;
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
public @interface JdbcType {
- String value() default "";
+ String value();
}
diff --git a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/TypeHandler.java b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/TypeHandler.java
index 13f551c6bf79e35f4cdd117e70d8e3f72a523316..96d82e53d205c2b999262a3b7d55c3cc9fc34c8a 100644
--- a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/TypeHandler.java
+++ b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/annotation/TypeHandler.java
@@ -29,6 +29,6 @@ import java.lang.annotation.Target;
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER })
public @interface TypeHandler {
- String value();
+ Class> value();
}
diff --git a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/domain/Audit.java b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/domain/Audit.java
index 55a81c6d97c441845f5b83fe73884ff869be7ffb..6ed0cefaaf72f1dd4d172db1e99b2a1d87be9c29 100644
--- a/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/domain/Audit.java
+++ b/spring-data-mybatis-core/src/main/java/org/springframework/data/mybatis/domain/Audit.java
@@ -55,7 +55,7 @@ public abstract class Auditfalse
- 2.3.3.RELEASE
- 2.3.3.RELEASE
+ 2.3.4.RELEASE
+ 2.3.4.RELEASE
3.5.5
@@ -73,18 +73,18 @@
4.13
5.6.2
1.3.72
- 1.3.8
+ 1.3.9
1.2.3
1.18.12
3.3.3
1.10.0
4.3.1
- Dysprosium-SR11
+ Dysprosium-SR12
1.3.8
1.2.1
2.2.19
1.7.26
- 5.2.8.RELEASE
+ 5.2.9.RELEASE
1.1.1.RELEASE
2.0.0.RELEASE
1.14.3
@@ -356,12 +356,6 @@
1.18.10.0
-
- org.jfrog.buildinfo
- artifactory-maven-plugin
- 2.7.0
-
-
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/domain/support/AuditingInterceptor.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/auditing/AuditingInterceptor.java
similarity index 97%
rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/domain/support/AuditingInterceptor.java
rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/auditing/AuditingInterceptor.java
index 118404394bc33d419c658ccf80447b54f9caa92e..ef4687a87aff4d36cb252ce006849e8366d1c1d8 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/domain/support/AuditingInterceptor.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/auditing/AuditingInterceptor.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.data.mybatis.domain.support;
+package org.springframework.data.mybatis.auditing;
import java.util.Map;
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/domain/support/MybatisAuditingHandler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/auditing/MybatisAuditingHandler.java
similarity index 97%
rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/domain/support/MybatisAuditingHandler.java
rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/auditing/MybatisAuditingHandler.java
index 0dd85e468c0df77314c0c18fc39850a8c0b0626d..09d4f21728b39039d33bd6ef22ca300c3eba2d0d 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/domain/support/MybatisAuditingHandler.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/auditing/MybatisAuditingHandler.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.data.mybatis.domain.support;
+package org.springframework.data.mybatis.auditing;
import org.mybatis.spring.SqlSessionTemplate;
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisMappingContext.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisMappingContext.java
index d085bfed45c4979c9a9d5700073240ad96c5d4f4..caf9011e1b0bd1b04b47656c722d5045a4401433 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisMappingContext.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisMappingContext.java
@@ -15,24 +15,34 @@
*/
package org.springframework.data.mybatis.mapping;
+import java.beans.Introspector;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
+import javax.persistence.Entity;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;
import javax.persistence.NamedQueries;
+import org.mybatis.spring.SqlSessionTemplate;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.data.mapping.MappingException;
import org.springframework.data.mapping.context.AbstractMappingContext;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.FieldNamingStrategy;
import org.springframework.data.mapping.model.Property;
+import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
import org.springframework.data.mapping.model.SimpleTypeHolder;
-import org.springframework.data.mybatis.repository.MybatisRepository;
+import org.springframework.data.mapping.model.SnakeCaseFieldNamingStrategy;
+import org.springframework.data.mybatis.dialect.Dialect;
+import org.springframework.data.mybatis.dialect.internal.DatabaseMetaDataDialectResolutionInfoAdapter;
+import org.springframework.data.mybatis.dialect.internal.StandardDialectResolver;
+import org.springframework.data.mybatis.mapping.model.Domain;
+import org.springframework.data.mybatis.mapping.model.Model;
+import org.springframework.data.mybatis.precompiler.SimpleMybatisPrecompiler;
import org.springframework.data.util.TypeInformation;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
/**
* {@link MappingContext} implementation based on JPA annotations.
@@ -40,20 +50,86 @@ import org.springframework.util.MultiValueMap;
* @author JARVIS SONG
* @since 1.0.0
*/
-public class MybatisMappingContext
- extends AbstractMappingContext, MybatisPersistentProperty> {
+public class MybatisMappingContext extends
+ AbstractMappingContext, MybatisPersistentProperty> implements InitializingBean {
+
+ private static final SnakeCaseFieldNamingStrategy SNAKE_CASE_FIELD_NAMING_STRATEGY = new SnakeCaseFieldNamingStrategy();
+
+ private final SqlSessionTemplate sqlSessionTemplate;
+
+ private final Dialect dialect;
private FieldNamingStrategy fieldNamingStrategy;
private Map namedQueries = new HashMap<>();
- private MultiValueMap, Class>> entityRepositoryMapping = new LinkedMultiValueMap<>();
+ private Map, Domain> domainCache = new HashMap<>();
+
+ public MybatisMappingContext(SqlSessionTemplate sqlSessionTemplate) {
+ this.sqlSessionTemplate = sqlSessionTemplate;
+ this.dialect = StandardDialectResolver.INSTANCE.resolveDialect(new DatabaseMetaDataDialectResolutionInfoAdapter(
+ sqlSessionTemplate.getConfiguration().getEnvironment().getDataSource()));
+ }
+
+ @Override
+ public void afterPropertiesSet() {
+ super.afterPropertiesSet();
+
+ if (null == this.fieldNamingStrategy) {
+ if (null != this.sqlSessionTemplate
+ && this.sqlSessionTemplate.getConfiguration().isMapUnderscoreToCamelCase()) {
+ this.fieldNamingStrategy = SNAKE_CASE_FIELD_NAMING_STRATEGY;
+ }
+ else {
+ this.fieldNamingStrategy = PropertyNameFieldNamingStrategy.INSTANCE;
+ }
+ }
+
+ // initialize models
+ this.domainCache = this.getManagedTypes().stream().map(TypeInformation::getType)
+ .filter(clz -> clz.isAnnotationPresent(Entity.class)).collect(Collectors.toMap(clz -> clz,
+ clz -> new Domain(this, null, clz, Introspector.decapitalize(clz.getSimpleName()))));
+
+ this.domainCache.values().stream().forEach(Domain::initialize);
+
+ // generate mybatis mappers
+ this.domainCache.values().stream().forEach(domain -> new SimpleMybatisPrecompiler(this, domain).compile());
+ }
+
+ public Model getModel(Class> clz) {
+ return this.domainCache.get(clz);
+ }
+
+ public Model getRequiredModel(Class> type) throws MappingException {
+
+ Model model = getModel(type);
+
+ if (model != null) {
+ return model;
+ }
+
+ throw new MappingException(String.format("Couldn't find Model for type %s!", type));
+ }
@Override
protected MybatisPersistentEntityImpl> createPersistentEntity(TypeInformation typeInformation) {
+ MybatisPersistentEntityImpl entity = new MybatisPersistentEntityImpl<>(typeInformation);
+ this.processNamedQueries(entity);
+ return entity;
+ }
+
+ @Override
+ protected MybatisPersistentProperty createPersistentProperty(Property property,
+ MybatisPersistentEntityImpl> owner, SimpleTypeHolder simpleTypeHolder) {
+
+ return new MybatisPersistentPropertyImpl(property, owner, simpleTypeHolder);
+ }
- MybatisPersistentEntityImpl entity = new MybatisPersistentEntityImpl(typeInformation);
+ public String getNamedQuery(String name) {
+ return this.namedQueries.get(name);
+ }
+ private void processNamedQueries(MybatisPersistentEntityImpl> entity) {
javax.persistence.NamedQuery namedQuery = entity.findAnnotation(javax.persistence.NamedQuery.class);
if ((null != namedQuery)) {
this.namedQueries.put(namedQuery.name(), namedQuery.query());
@@ -75,41 +151,22 @@ public class MybatisMappingContext
this.namedQueries.put(nq.name(), nq.query());
}
}
-
- return entity;
- }
-
- @Override
- protected MybatisPersistentProperty createPersistentProperty(Property property,
- MybatisPersistentEntityImpl> owner, SimpleTypeHolder simpleTypeHolder) {
- return new MybatisPersistentPropertyImpl(property, owner, simpleTypeHolder, this.fieldNamingStrategy);
}
public void setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) {
this.fieldNamingStrategy = fieldNamingStrategy;
}
- public String getNamedQuery(String name) {
- return this.namedQueries.get(name);
+ public SqlSessionTemplate getSqlSessionTemplate() {
+ return this.sqlSessionTemplate;
}
- public void setEntityRepositoryMapping(MultiValueMap, Class>> entityRepositoryMapping) {
- this.entityRepositoryMapping = entityRepositoryMapping;
+ public Dialect getDialect() {
+ return this.dialect;
}
- public Class> getRepositoryInterface(Class> entityClass) {
- List> repositories = this.entityRepositoryMapping.get(entityClass);
- if (CollectionUtils.isEmpty(repositories)) {
- return null;
- }
-
- if (repositories.size() == 1) {
- return repositories.get(0);
- }
-
- return repositories.stream().filter(r -> MybatisRepository.class.isAssignableFrom(r)).findFirst()
- .orElse(repositories.get(0));
-
+ public FieldNamingStrategy getFieldNamingStrategy() {
+ return this.fieldNamingStrategy;
}
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntity.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntity.java
index 46ea499fd5b005500c0f9b66a983bee9d4f1a7ba..d116bcdca65fa6eac93356612cc30ff55fb7ae86 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntity.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntity.java
@@ -16,7 +16,6 @@
package org.springframework.data.mybatis.mapping;
import org.springframework.data.mapping.PersistentEntity;
-import org.springframework.data.mybatis.mapping.model.Table;
/**
* Interface for a MyBatis-specific entity.
@@ -27,9 +26,11 @@ import org.springframework.data.mybatis.mapping.model.Table;
*/
public interface MybatisPersistentEntity extends PersistentEntity {
- Table getTable();
-
- boolean hasCompositeId();
+ /**
+ * Returns whether this entity represents a composite primary key.
+ * @return whether composite primary key
+ */
+ boolean isCompositePrimaryKey();
Class> getIdClass();
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntityImpl.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntityImpl.java
index d7b526b582f20eb9455788ce75d714a2892fdac8..32413cd54a95734575a7dd7f1a59295bc5af33fa 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntityImpl.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentEntityImpl.java
@@ -18,14 +18,10 @@ package org.springframework.data.mybatis.mapping;
import java.util.Comparator;
import javax.persistence.EmbeddedId;
-import javax.persistence.Entity;
import javax.persistence.IdClass;
import org.springframework.data.mapping.model.BasicPersistentEntity;
-import org.springframework.data.mybatis.mapping.model.Table;
-import org.springframework.data.util.Lazy;
import org.springframework.data.util.TypeInformation;
-import org.springframework.util.StringUtils;
/**
* Implementation of {@link MybatisPersistentEntity}.
@@ -36,68 +32,29 @@ import org.springframework.util.StringUtils;
class MybatisPersistentEntityImpl extends BasicPersistentEntity
implements MybatisPersistentEntity {
- private Lazy table;
-
MybatisPersistentEntityImpl(TypeInformation information) {
- this(information, null);
+ this(information, (o1, o2) -> o1.isIdProperty() ? -1 : 1);
}
MybatisPersistentEntityImpl(TypeInformation information, Comparator comparator) {
super(information, comparator);
- this.table = Lazy.of(() -> {
-
- String schema = null;
- String catalog = null;
- String name = null;
- if (this.isAnnotationPresent(javax.persistence.Table.class)) {
- javax.persistence.Table t = this.getRequiredAnnotation(javax.persistence.Table.class);
- schema = t.schema();
- catalog = t.catalog();
- name = t.name();
- }
- if (StringUtils.isEmpty(name)) {
- Entity entity = this.findAnnotation(Entity.class);
- name = ((null != entity) && StringUtils.hasText(entity.name())) ? entity.name()
- : this.getType().getSimpleName();
- }
- Table table = new Table(schema, catalog, name);
- return table;
- });
- }
-
- @Override
- public Table getTable() {
- return this.table.get();
- }
-
- @Override
- public String getName() {
- Entity entity = this.findAnnotation(Entity.class);
- return ((null != entity) && StringUtils.hasText(entity.name())) ? entity.name() : super.getName();
}
@Override
- public boolean hasCompositeId() {
+ public boolean isCompositePrimaryKey() {
if (this.isAnnotationPresent(IdClass.class)) {
return true;
}
- if (this.hasIdProperty()) {
- return this.getRequiredIdProperty().isAnnotationPresent(EmbeddedId.class);
- }
- return false;
+
+ return this.hasIdProperty() ? this.getRequiredIdProperty().isAnnotationPresent(EmbeddedId.class) : false;
}
@Override
public Class> getIdClass() {
- if (this.isAnnotationPresent(IdClass.class)) {
- IdClass idClass = this.getRequiredAnnotation(IdClass.class);
- return idClass.value();
- }
- if (this.hasIdProperty()) {
- return this.getRequiredIdProperty().getActualType();
- }
- return null;
+
+ return this.isAnnotationPresent(IdClass.class) ? this.getRequiredAnnotation(IdClass.class).value()
+ : (this.hasIdProperty() ? this.getRequiredIdProperty().getActualType() : null);
}
@Override
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentProperty.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentProperty.java
index ad82c60738f9d79f4ab09ae65851dfa5e15dd61f..c36a77a950bf2a69ee82826cf09a8869532093a3 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentProperty.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/MybatisPersistentProperty.java
@@ -16,7 +16,6 @@
package org.springframework.data.mybatis.mapping;
import org.springframework.data.mapping.PersistentProperty;
-import org.springframework.data.mybatis.mapping.model.Column;
/**
* Interface for a MyBatis-specific {@link PersistentProperty}.
@@ -32,8 +31,6 @@ public interface MybatisPersistentProperty extends PersistentProperty> UPDATEABLE_ANNOTATIONS;
- private static final Map, JdbcType> JAVA_MAPPED_TO_JDBC_TYPES;
-
static {
Set> annotations = new HashSet<>();
@@ -119,28 +98,6 @@ class MybatisPersistentPropertyImpl extends AnnotationBasedPersistentProperty, JdbcType> javaTypesMappedToJdbcTypes = new HashMap<>();
- javaTypesMappedToJdbcTypes.put(String.class, JdbcType.VARCHAR);
- javaTypesMappedToJdbcTypes.put(java.math.BigDecimal.class, JdbcType.NUMERIC);
- javaTypesMappedToJdbcTypes.put(boolean.class, JdbcType.BIT);
- javaTypesMappedToJdbcTypes.put(byte.class, JdbcType.TINYINT);
- javaTypesMappedToJdbcTypes.put(short.class, JdbcType.SMALLINT);
- javaTypesMappedToJdbcTypes.put(int.class, JdbcType.INTEGER);
- javaTypesMappedToJdbcTypes.put(long.class, JdbcType.BIGINT);
- javaTypesMappedToJdbcTypes.put(float.class, JdbcType.REAL);
- javaTypesMappedToJdbcTypes.put(double.class, JdbcType.DOUBLE);
- javaTypesMappedToJdbcTypes.put(byte[].class, JdbcType.VARBINARY);
- javaTypesMappedToJdbcTypes.put(java.util.Date.class, JdbcType.TIMESTAMP);
- javaTypesMappedToJdbcTypes.put(java.sql.Date.class, JdbcType.DATE);
- javaTypesMappedToJdbcTypes.put(java.sql.Time.class, JdbcType.TIME);
- javaTypesMappedToJdbcTypes.put(java.sql.Timestamp.class, JdbcType.TIMESTAMP);
- javaTypesMappedToJdbcTypes.put(Boolean.class, JdbcType.BIT);
- javaTypesMappedToJdbcTypes.put(Integer.class, JdbcType.INTEGER);
- javaTypesMappedToJdbcTypes.put(Long.class, JdbcType.BIGINT);
- javaTypesMappedToJdbcTypes.put(Float.class, JdbcType.REAL);
- javaTypesMappedToJdbcTypes.put(Double.class, JdbcType.DOUBLE);
-
- JAVA_MAPPED_TO_JDBC_TYPES = Collections.unmodifiableMap(javaTypesMappedToJdbcTypes);
}
private final @Nullable Boolean usePropertyAccess;
@@ -155,17 +112,14 @@ class MybatisPersistentPropertyImpl extends AnnotationBasedPersistentProperty isEntity;
- private final Lazy column;
-
/**
* Creates a new {@link AnnotationBasedPersistentProperty}.
* @param property must not be {@literal null}.
* @param owner must not be {@literal null}.
* @param simpleTypeHolder simple type holder
- * @param fieldNamingStrategy naming strategy
*/
MybatisPersistentPropertyImpl(Property property, PersistentEntity, MybatisPersistentProperty> owner,
- SimpleTypeHolder simpleTypeHolder, FieldNamingStrategy fieldNamingStrategy) {
+ SimpleTypeHolder simpleTypeHolder) {
super(property, owner, simpleTypeHolder);
this.isAssociation = Lazy.of(() -> ASSOCIATION_ANNOTATIONS.stream().anyMatch(this::isAnnotationPresent));
@@ -177,99 +131,6 @@ class MybatisPersistentPropertyImpl extends AnnotationBasedPersistentProperty ID_ANNOTATIONS.stream().anyMatch(this::isAnnotationPresent));
this.isEntity = Lazy.of(() -> ENTITY_ANNOTATIONS.stream().anyMatch(this::isAnnotationPresent));
- this.column = Lazy.of(() -> {
- String columnName = PropertyNameFieldNamingStrategy.INSTANCE.getFieldName(this);
- Class> actualType = this.getType();
-
- javax.persistence.Column column = this.findAnnotation(javax.persistence.Column.class);
- if (null != column && StringUtils.hasText(column.name())) {
- columnName = column.name();
- }
- else {
- OrderColumn orderColumn = this.findAnnotation(OrderColumn.class);
- if (null != orderColumn && StringUtils.hasText(orderColumn.name())) {
- columnName = orderColumn.name();
- }
- else if (null != fieldNamingStrategy) {
- columnName = fieldNamingStrategy.getFieldName(this);
- }
- }
- JdbcType jdbcType = JdbcType.UNDEFINED;
- org.springframework.data.mybatis.annotation.JdbcType jdbcTypeAnn = this
- .findAnnotation(org.springframework.data.mybatis.annotation.JdbcType.class);
- if (null != jdbcTypeAnn) {
- jdbcType = JdbcType.valueOf(jdbcTypeAnn.value());
- }
- else if (this.isAnnotationPresent(Temporal.class)) {
- Temporal temporal = this.getRequiredAnnotation(Temporal.class);
- switch (temporal.value()) {
-
- case DATE:
- jdbcType = JdbcType.DATE;
- break;
- case TIME:
- jdbcType = JdbcType.TIME;
- break;
- case TIMESTAMP:
- jdbcType = JdbcType.TIMESTAMP;
- break;
- }
- }
- else if (actualType.isEnum()) {
- jdbcType = JdbcType.VARCHAR;
- }
- else {
- if (this.isAnnotationPresent(Lob.class)) {
- jdbcType = (actualType != String.class) ? JdbcType.BLOB : JdbcType.CLOB;
- }
- else {
- JdbcType jt = JAVA_MAPPED_TO_JDBC_TYPES.get(actualType);
- if (null != jt) {
- jdbcType = jt;
- }
- }
- }
- Column col = new Column(columnName, jdbcType);
- if (this.isVersionProperty()) {
- col.setVersion(true);
- }
- col.setJavaType(actualType);
- col.setPrimaryKey(this.isIdProperty.get());
- TypeHandler typeHandler = this.findAnnotation(TypeHandler.class);
- if (null != typeHandler && StringUtils.hasText(typeHandler.value())) {
- try {
- col.setTypeHandler(ClassUtils.forName(typeHandler.value(), this.getClass().getClassLoader()));
- }
- catch (Exception ex) {
- throw new MappingException(ex.getMessage(), ex);
- }
- }
- else {
-
- if (this.isEnumerated()) {
- Enumerated enumerated = this.getRequiredAnnotation(Enumerated.class);
- if (enumerated.value() == EnumType.ORDINAL) {
- col.setTypeHandler(EnumOrdinalTypeHandler.class);
- }
- else {
- col.setTypeHandler(EnumTypeHandler.class);
- }
- }
- else if (actualType == Long.class && jdbcType == JdbcType.TIMESTAMP) {
- col.setTypeHandler(UnixTimestampDateTypeHandler.class);
- }
- else if (actualType == Date.class && jdbcType == JdbcType.BIGINT) {
- col.setTypeHandler(DateUnixTimestampTypeHandler.class);
- }
-
- }
- return col;
- });
- }
-
- @Override
- public Column getColumn() {
- return this.column.get();
}
@Override
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Association.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Association.java
index 875c64b571e045d1524def8aa11444ece8e7c264..4c1f92e6f23dd92d4d9269e740822da26db13a18 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Association.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Association.java
@@ -15,63 +15,12 @@
*/
package org.springframework.data.mybatis.mapping.model;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-import lombok.Data;
-import lombok.experimental.Accessors;
-
/**
- * Association.
+ * .
*
* @author JARVIS SONG
- * @since 2.0.0
+ * @since 2.0.2
*/
-@Data
-@Accessors(chain = true)
-public class Association implements Serializable {
-
- private static final long serialVersionUID = 3169794115053267639L;
-
- private String property;
-
- private String javaType;
-
- private String select;
-
- private String fetch;
-
- private String targetTable;
-
- private List joinColumns = new ArrayList<>();
-
- private List results = new LinkedList<>();
-
- public Association addResult(ColumnResult cr) {
- this.results.add(cr);
- return this;
- }
-
- public Association addJoinColumn(JoinColumn jc) {
- this.joinColumns.add(jc);
- return this;
- }
-
- @Data
- @Accessors(chain = true)
- public static class JoinColumn {
-
- private String name;
-
- private String referencedColumnName;
-
- public JoinColumn(String name, String referencedColumnName) {
- this.name = name;
- this.referencedColumnName = referencedColumnName;
- }
-
- }
+public interface Association extends Model {
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Column.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Column.java
index 04327ead6ae8599e85ce847c57cf43c9ba73d0d2..7485f0d315ddd099c5941303809097a62947cee4 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Column.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Column.java
@@ -15,81 +15,287 @@
*/
package org.springframework.data.mybatis.mapping.model;
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZonedDateTime;
+import java.time.chrono.JapaneseDate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
import java.util.HashMap;
import java.util.Map;
+import java.util.stream.Collectors;
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
+import javax.persistence.Enumerated;
+import javax.persistence.Lob;
+import javax.persistence.Temporal;
+
+import org.apache.ibatis.type.EnumOrdinalTypeHandler;
+import org.apache.ibatis.type.EnumTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeAliasRegistry;
+import org.springframework.data.mybatis.annotation.TypeHandler;
+import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
+import org.springframework.data.mybatis.mapping.handler.DateUnixTimestampTypeHandler;
+import org.springframework.data.mybatis.mapping.handler.UnixTimestampDateTypeHandler;
+import org.springframework.util.StringUtils;
+
/**
- * Column model.
+ * .
*
* @author JARVIS SONG
- * @since 2.0.0
+ * @since 2.0.2
*/
-@Getter
-@Setter
-@ToString
-public class Column {
+public class Column implements Component, Cloneable {
+
+ private static final long serialVersionUID = 6881902687485454726L;
+
+ protected static Map, String> TYPE_ALIAS = new HashMap<>();
- private static Map, String> TYPE_ALIAS = new HashMap<>();
+ private static final Map, JdbcType> JAVA_TYPE_MAPPING;
static {
TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
Map> typeAliases = typeAliasRegistry.getTypeAliases();
typeAliases.entrySet().stream().forEach(entry -> TYPE_ALIAS.put(entry.getValue(), entry.getKey()));
+
+ Map, JdbcType> map = new HashMap<>();
+ map.put(Boolean.class, JdbcType.BOOLEAN);
+ map.put(boolean.class, JdbcType.BOOLEAN);
+ map.put(Byte.class, JdbcType.BIT);
+ map.put(byte.class, JdbcType.BIT);
+ map.put(Short.class, JdbcType.SMALLINT);
+ map.put(short.class, JdbcType.SMALLINT);
+ map.put(Integer.class, JdbcType.INTEGER);
+ map.put(int.class, JdbcType.INTEGER);
+ map.put(Long.class, JdbcType.BIGINT);
+ map.put(long.class, JdbcType.BIGINT);
+ map.put(Float.class, JdbcType.FLOAT);
+ map.put(float.class, JdbcType.FLOAT);
+ map.put(Double.class, JdbcType.DOUBLE);
+ map.put(double.class, JdbcType.DOUBLE);
+ map.put(Character.class, JdbcType.VARCHAR);
+ map.put(char.class, JdbcType.VARCHAR);
+ map.put(Reader.class, JdbcType.CLOB);
+ map.put(String.class, JdbcType.VARCHAR);
+ map.put(BigInteger.class, JdbcType.BIGINT);
+ map.put(BigDecimal.class, JdbcType.DECIMAL);
+ map.put(InputStream.class, JdbcType.BLOB);
+ map.put(Byte[].class, JdbcType.BLOB);
+ map.put(byte[].class, JdbcType.BLOB);
+ map.put(Object.class, JdbcType.OTHER);
+ map.put(Date.class, JdbcType.TIMESTAMP);
+ map.put(java.sql.Date.class, JdbcType.DATE);
+ map.put(java.sql.Time.class, JdbcType.TIME);
+ map.put(java.sql.Timestamp.class, JdbcType.TIMESTAMP);
+ map.put(Instant.class, JdbcType.TIMESTAMP);
+ map.put(LocalDateTime.class, JdbcType.TIMESTAMP_WITH_TIMEZONE);
+ map.put(LocalDate.class, JdbcType.DATE);
+ map.put(LocalTime.class, JdbcType.TIME);
+ map.put(OffsetDateTime.class, JdbcType.TIMESTAMP);
+ map.put(OffsetTime.class, JdbcType.TIME);
+ map.put(ZonedDateTime.class, JdbcType.TIMESTAMP);
+ map.put(Month.class, JdbcType.INTEGER);
+ map.put(Year.class, JdbcType.INTEGER);
+ map.put(YearMonth.class, JdbcType.VARCHAR);
+ map.put(JapaneseDate.class, JdbcType.TIMESTAMP);
+ JAVA_TYPE_MAPPING = Collections.unmodifiableMap(map);
+ }
+
+ protected final Model model;
+
+ private final MybatisPersistentProperty property;
+
+ protected final String columnAlias;
+
+ protected Identifier name;
+
+ protected String propertyName;
+
+ protected JdbcType jdbcType;
+
+ protected Class> javaType;
+
+ protected Class> typeHandler;
+
+ public Column(Model model, MybatisPersistentProperty property) {
+ this.model = model;
+ this.property = property;
+
+ javax.persistence.Column columnAnn = property.findAnnotation(javax.persistence.Column.class);
+ if (null != columnAnn && StringUtils.hasText(columnAnn.name())) {
+ this.name = Identifier.toIdentifier(columnAnn.name());
+ }
+ else {
+ this.name = Identifier
+ .toIdentifier(model.getMappingContext().getFieldNamingStrategy().getFieldName(property));
+ }
+ this.javaType = property.getType();
+ this.jdbcType = this.processJdbcType(property);
+ this.typeHandler = this.processTypeHandler(property);
+
+ String[] aliasArray = model.getAlias().split("\\.");
+ int pos = 1;
+ if (aliasArray.length == pos) {
+ this.columnAlias = this.name.getText();
+ this.propertyName = property.getName();
+ }
+ else {
+ String[] aa = new String[aliasArray.length - pos];
+ System.arraycopy(aliasArray, pos, aa, 0, aa.length);
+ String pre = Arrays.stream(aa).collect(Collectors.joining("."));
+ this.propertyName = pre + '.' + property.getName();
+
+ if (model instanceof Embedding) {
+ if (aa.length == 1) {
+ this.columnAlias = this.name.getText();
+ }
+ else {
+ String[] bb = new String[aa.length - 1];
+ System.arraycopy(aa, 0, bb, 0, bb.length);
+ this.columnAlias = Arrays.stream(bb).collect(Collectors.joining(".")) + '.' + this.name.getText();
+ }
+ }
+ else {
+ this.columnAlias = pre + '.' + this.name.getText();
+ }
+
+ }
}
- private Identifier name;
+ private JdbcType processJdbcType(MybatisPersistentProperty property) {
- private JdbcType jdbcType;
+ org.springframework.data.mybatis.annotation.JdbcType jdbcTypeAnn = property
+ .findAnnotation(org.springframework.data.mybatis.annotation.JdbcType.class);
+ if (null != jdbcTypeAnn) {
+ return JdbcType.valueOf(jdbcTypeAnn.value());
+ }
- private Class> javaType;
+ if (property.isAnnotationPresent(Temporal.class)) {
+ Temporal temporalAnn = property.getRequiredAnnotation(Temporal.class);
+ switch (temporalAnn.value()) {
+ case DATE:
+ return JdbcType.DATE;
+ case TIME:
+ return JdbcType.TIME;
+ case TIMESTAMP:
+ return JdbcType.TIMESTAMP;
+ }
+ }
- private Class> typeHandler;
+ if (property.getType().isEnum()) {
+ Enumerated enumeratedAnn = property.findAnnotation(Enumerated.class);
+ if (null != enumeratedAnn) {
+ switch (enumeratedAnn.value()) {
+ case ORDINAL:
+ return JdbcType.INTEGER;
+ case STRING:
+ return JdbcType.VARCHAR;
+ }
+ }
+ return JdbcType.VARCHAR;
+ }
- private boolean primaryKey;
+ if (property.isAnnotationPresent(Lob.class)) {
+ if (CharSequence.class.isAssignableFrom(property.getType())) {
+ return JdbcType.CLOB;
+ }
+ return JdbcType.BLOB;
+ }
- private boolean version;
+ JdbcType jdbcType = JAVA_TYPE_MAPPING.get(property.getType());
- public Column(String name) {
- this.name = Identifier.toIdentifier(name);
+ return (null != jdbcType) ? jdbcType : JdbcType.UNDEFINED;
}
- public Column(String name, JdbcType jdbcType) {
- this.name = Identifier.toIdentifier(name);
- this.jdbcType = jdbcType;
+ private Class> processTypeHandler(MybatisPersistentProperty property) {
+ TypeHandler typeHandler = property.findAnnotation(TypeHandler.class);
+ if (null != typeHandler) {
+ return typeHandler.value();
+ }
+
+ if (property.isEnumerated()) {
+ Enumerated enumeratedAnn = property.getRequiredAnnotation(Enumerated.class);
+ switch (enumeratedAnn.value()) {
+ case ORDINAL:
+ return EnumOrdinalTypeHandler.class;
+ case STRING:
+ return EnumTypeHandler.class;
+ }
+ }
+
+ if (property.getType() == Long.class && this.getJdbcType() == JdbcType.TIMESTAMP) {
+ return UnixTimestampDateTypeHandler.class;
+ }
+ if (property.getType() == Date.class && this.getJdbcType() == JdbcType.BIGINT) {
+ return DateUnixTimestampTypeHandler.class;
+ }
+ return null;
+ }
+
+ @Override
+ public Model getModel() {
+ return this.model;
+ }
+
+ public String getColumnAlias() {
+ return this.columnAlias;
}
- public Column(Identifier name, JdbcType jdbcType) {
+ public Identifier getName() {
+ return this.name;
+ }
+
+ public void setName(Identifier name) {
this.name = name;
+ }
+
+ public String getPropertyName() {
+ return this.propertyName;
+ }
+
+ public void setPropertyName(String propertyName) {
+ this.propertyName = propertyName;
+ }
+
+ public JdbcType getJdbcType() {
+ return this.jdbcType;
+ }
+
+ public void setJdbcType(JdbcType jdbcType) {
this.jdbcType = jdbcType;
}
- public boolean isString() {
- return this.javaType == String.class
- || (null != this.javaType && CharSequence.class.isAssignableFrom(this.javaType));
+ public Class> getJavaType() {
+ return this.javaType;
}
- public boolean hasJdbcType() {
- return null != this.jdbcType;
+ public void setJavaType(Class> javaType) {
+ this.javaType = javaType;
}
- public boolean hasJavaType() {
- return null != this.jdbcType;
+ public Class> getTypeHandler() {
+ return this.typeHandler;
}
- public boolean hasTypeHandler() {
- return null != this.typeHandler;
+ public void setTypeHandler(Class> typeHandler) {
+ this.typeHandler = typeHandler;
}
- public String getJdbcTypeString() {
- if (null == this.jdbcType) {
- return null;
- }
- return this.jdbcType.name();
+ @Override
+ protected Column clone() throws CloneNotSupportedException {
+ return (Column) super.clone();
}
public String getJavaTypeString() {
@@ -104,11 +310,15 @@ public class Column {
return this.javaType.getName();
}
- public String getTypeHandlerString() {
- if (null == this.typeHandler) {
- return null;
- }
- return this.typeHandler.getName();
+ public boolean isString() {
+ JdbcType jdbcType = this.getJdbcType();
+ return jdbcType == JdbcType.VARCHAR || jdbcType == JdbcType.CHAR || jdbcType == JdbcType.CLOB
+ || jdbcType == JdbcType.NVARCHAR || jdbcType == JdbcType.NCHAR || jdbcType == JdbcType.LONGNVARCHAR
+ || jdbcType == JdbcType.LONGVARCHAR;
+ }
+
+ public MybatisPersistentProperty getProperty() {
+ return this.property;
}
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ColumnResult.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Component.java
similarity index 74%
rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ColumnResult.java
rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Component.java
index 337f3ab190933a99b05781f66c69cffd43d0f06f..f005b059698004a02902152dc1a35e04e68d6464 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ColumnResult.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Component.java
@@ -17,27 +17,18 @@ package org.springframework.data.mybatis.mapping.model;
import java.io.Serializable;
-import lombok.Data;
-
/**
* .
*
* @author JARVIS SONG
- * @since 2.0.0
+ * @since 2.0.2
*/
-@Data
-public class ColumnResult implements Serializable {
-
- private boolean primaryKey;
-
- private String property;
-
- private String column;
-
- private String javaType;
-
- private String jdbcType;
+public interface Component extends Serializable {
- private String typeHandler;
+ /**
+ * Belong to.
+ * @return model
+ */
+ Model getModel();
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/CompositePrimaryKey.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/CompositePrimaryKey.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff6450e8d119ff8a5bb13e9014eae43900cc430a
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/CompositePrimaryKey.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.mapping.model;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.springframework.data.mapping.PersistentProperty;
+import org.springframework.data.mybatis.mapping.MybatisPersistentEntity;
+import org.springframework.data.util.StreamUtils;
+
+/**
+ * .
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public class CompositePrimaryKey implements PrimaryKey {
+
+ private final Map columns = new LinkedHashMap<>();
+
+ private final Model model;
+
+ public CompositePrimaryKey(Model model, MybatisPersistentEntity> entity) {
+ this.model = model;
+
+ StreamUtils.createStreamFromIterator(entity.iterator()).filter(PersistentProperty::isIdProperty).forEach(p -> {
+
+ if (p.isEmbeddable()) {
+ MybatisPersistentEntity> embeddedEntity = model.getMappingContext()
+ .getRequiredPersistentEntity(p.getType());
+ embeddedEntity.forEach(ep -> {
+
+ Column column = new Column(model, ep);
+ column.setPropertyName(p.getName() + '.' + ep.getName());
+ this.addColumn(column);
+ });
+ }
+ else {
+ Column column = new Column(model, p);
+ this.addColumn(column);
+ }
+
+ });
+
+ }
+
+ public void addColumn(Column column) {
+ this.columns.put(column.getName().getCanonicalName(), column);
+ }
+
+ @Override
+ public boolean isComposited() {
+ return true;
+ }
+
+ @Override
+ public Collection getColumns() {
+ return this.columns.values();
+ }
+
+ @Override
+ public Class> getType() {
+ return this.model.getMappingEntity().getIdClass();
+ }
+
+ @Override
+ public Column findColumn(String name) {
+ return this.columns.get(name);
+ }
+
+ @Override
+ public Model getModel() {
+ return this.model;
+ }
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Domain.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Domain.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a32e978ffcfdc10d73e80e723e11130942433a7
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Domain.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.mapping.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import javax.persistence.Entity;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+
+import org.springframework.data.mapping.PropertyPath;
+import org.springframework.data.mybatis.mapping.MybatisMappingContext;
+import org.springframework.data.mybatis.mapping.MybatisPersistentEntity;
+import org.springframework.data.util.StreamUtils;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+/**
+ * .
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public class Domain implements Model {
+
+ private static final long serialVersionUID = 4850421315538416089L;
+
+ protected final MybatisMappingContext mappingContext;
+
+ protected final MybatisPersistentEntity> entity;
+
+ protected final String alias;
+
+ protected Table table;
+
+ protected Model owner;
+
+ protected PrimaryKey primaryKey;
+
+ protected Map normalColumns; // columnName -> column
+
+ protected Map versionColumns;
+
+ protected List embeddings;
+
+ protected List oneToOneAssociations;
+
+ protected List manyToOneAssociations;
+
+ protected List oneToManyAssociations;
+
+ protected List manyToManyAssociations;
+
+ public Domain(MybatisMappingContext mappingContext, Model owner, Class> entityClass, String alias) {
+ this.mappingContext = mappingContext;
+ this.owner = owner;
+ this.entity = mappingContext.getRequiredPersistentEntity(entityClass);
+ if (null != owner) {
+ this.alias = owner.getAlias() + '.' + alias;
+ }
+ else {
+ this.alias = alias;
+ }
+
+ this.internalInitialize();
+ }
+
+ public void initialize() {
+ if (null != this.owner) {
+ return;
+ }
+
+ this.initializeOneToOneAssociations();
+ this.initializeManyToOneAssociations();
+ this.initializeOneToManyAssociations();
+ this.initializeManyToManyAssociations();
+ }
+
+ private void internalInitialize() {
+ this.initializeTable();
+ this.initializePrimaryKey();
+ this.initializeNormalColumns();
+ this.initializeVersionColumns();
+ this.initializeEmbeddedDomains();
+ }
+
+ private void initializeManyToManyAssociations() {
+ this.manyToManyAssociations = StreamUtils.createStreamFromIterator(this.entity.iterator())
+ .filter(p -> p.isAnnotationPresent(ManyToMany.class))
+ .map(p -> new ManyToManyAssociation(this.mappingContext, this, p, p.getName()))
+ .collect(Collectors.toList());
+ }
+
+ private void initializeOneToManyAssociations() {
+ this.oneToManyAssociations = StreamUtils.createStreamFromIterator(this.entity.iterator())
+ .filter(p -> p.isAnnotationPresent(OneToMany.class))
+ .map(p -> new OneToManyAssociation(this.mappingContext, this, p, p.getName()))
+ .collect(Collectors.toList());
+ }
+
+ private void initializeOneToOneAssociations() {
+ this.oneToOneAssociations = StreamUtils.createStreamFromIterator(this.entity.iterator())
+ .filter(p -> p.isAnnotationPresent(OneToOne.class))
+ .map(p -> new OneToOneAssociation(this.mappingContext, this, p, p.getName()))
+ .collect(Collectors.toList());
+ }
+
+ private void initializeManyToOneAssociations() {
+ this.manyToOneAssociations = StreamUtils.createStreamFromIterator(this.entity.iterator())
+ .filter(p -> p.isAnnotationPresent(ManyToOne.class))
+ .map(p -> new ManyToOneAssociation(this.mappingContext, this, p, p.getName()))
+ .collect(Collectors.toList());
+ }
+
+ private void initializeEmbeddedDomains() {
+ this.embeddings = StreamUtils.createStreamFromIterator(this.entity.iterator())
+ .filter(p -> !p.isIdProperty() && !p.isAssociation() && p.isEmbeddable())
+ .map(p -> new EmbeddedDomain(this.mappingContext, this, p, p.getName())).collect(Collectors.toList());
+ }
+
+ private void initializeVersionColumns() {
+ this.versionColumns = StreamUtils.createStreamFromIterator(this.entity.iterator())
+ .filter(p -> p.isVersionProperty()).map(p -> new VersionColumn(this, p))
+ .collect(Collectors.toMap(c -> c.getName().getCanonicalName(), c -> c));
+
+ }
+
+ private void initializeNormalColumns() {
+ this.normalColumns = StreamUtils.createStreamFromIterator(this.entity.iterator())
+ .filter(p -> !p.isIdProperty() && !p.isAssociation() && !p.isEmbeddable() && !p.isVersionProperty())
+ .map(p -> new Column(this, p)).collect(Collectors.toMap(c -> c.getName().getCanonicalName(), c -> c));
+ }
+
+ private void initializePrimaryKey() {
+ if (!this.entity.hasIdProperty()) {
+ return;
+ }
+ if (!this.entity.isCompositePrimaryKey()) {
+ this.primaryKey = new SinglePrimaryKey(this, this.entity.getRequiredIdProperty());
+ return;
+ }
+
+ // composited primary key
+ this.primaryKey = new CompositePrimaryKey(this, this.entity);
+ }
+
+ private void initializeTable() {
+ String schema = null;
+ String catalog = null;
+ String name = null;
+ if (this.entity.isAnnotationPresent(javax.persistence.Table.class)) {
+ javax.persistence.Table tableAnn = this.entity.getRequiredAnnotation(javax.persistence.Table.class);
+ schema = tableAnn.schema();
+ catalog = tableAnn.catalog();
+ name = tableAnn.name();
+ }
+ if (StringUtils.isEmpty(name)) {
+ Entity entityAnn = this.entity.findAnnotation(Entity.class);
+ name = ((null != entityAnn) && StringUtils.hasText(entityAnn.name())) ? entityAnn.name()
+ : this.entity.getType().getSimpleName();
+ }
+ this.table = new Table(schema, catalog, name);
+ }
+
+ @Override
+ public Column findColumn(String name) {
+ if (null != this.primaryKey) {
+ Column column = this.primaryKey.findColumn(name);
+ if (null != column) {
+ return column;
+ }
+ }
+ if (!CollectionUtils.isEmpty(this.normalColumns)) {
+ Column column = this.normalColumns.get(name);
+ if (null != column) {
+ return column;
+ }
+ }
+ if (!CollectionUtils.isEmpty(this.versionColumns)) {
+ Column column = this.versionColumns.get(name);
+ if (null != column) {
+ return column;
+ }
+ }
+ if (!CollectionUtils.isEmpty(this.embeddings)) {
+ for (EmbeddedDomain embeddedDomain : this.embeddings) {
+ Column c = embeddedDomain.findColumn(name);
+ if (null != c) {
+ return c;
+ }
+ }
+
+ }
+
+ return null;
+ }
+
+ @Override
+ public Column findColumnByPropertyName(String propertyName) {
+ Column column = null;
+ if (null != this.primaryKey) {
+ column = this.primaryKey.getColumns().stream().filter(c -> c.getPropertyName().equals(propertyName))
+ .findFirst().orElse(null);
+ }
+ if (null == column && !CollectionUtils.isEmpty(this.normalColumns)) {
+ column = this.normalColumns.values().stream().filter(c -> c.getPropertyName().equals(propertyName))
+ .findFirst().orElse(null);
+ }
+ if (null == column && !CollectionUtils.isEmpty(this.versionColumns)) {
+ column = this.versionColumns.values().stream().filter(c -> c.getPropertyName().equals(propertyName))
+ .findFirst().orElse(null);
+ }
+ if (null == column && !CollectionUtils.isEmpty(this.embeddings)) {
+ column = this.embeddings.stream()
+ .map(embeddedDomain -> embeddedDomain.findColumnByPropertyName(propertyName)).filter(c -> null != c)
+ .findFirst().orElse(null);
+ }
+ return column;
+ }
+
+ @Override
+ public Column findColumn(PropertyPath propertyPath) {
+ if (null == propertyPath) {
+ return null;
+ }
+ String path = propertyPath.toDotPath();
+ return this.findColumnByPropertyName(path);
+ }
+
+ @Override
+ public List findColumnByTypeHandler(Class> typeHandlerClass) {
+ List columns = new ArrayList<>();
+ if (null != this.primaryKey) {
+ columns.addAll(this.primaryKey.getColumns().stream().filter(c -> c.getTypeHandler() == typeHandlerClass)
+ .collect(Collectors.toList()));
+ }
+
+ if (null != this.normalColumns) {
+ columns.addAll(this.normalColumns.values().stream().filter(c -> c.getTypeHandler() == typeHandlerClass)
+ .collect(Collectors.toList()));
+ }
+
+ if (null != this.versionColumns) {
+ columns.addAll(this.versionColumns.values().stream().filter(c -> c.getTypeHandler() == typeHandlerClass)
+ .collect(Collectors.toList()));
+ }
+
+ if (!CollectionUtils.isEmpty(this.embeddings)) {
+ for (EmbeddedDomain embeddedDomain : this.embeddings) {
+ columns.addAll(embeddedDomain.findColumnByTypeHandler(typeHandlerClass));
+ }
+
+ }
+
+ return columns;
+ }
+
+ @Override
+ public MybatisMappingContext getMappingContext() {
+ return this.mappingContext;
+ }
+
+ @Override
+ public String getAlias() {
+ return this.alias;
+ }
+
+ @Override
+ public Model getOwner() {
+ return this.owner;
+ }
+
+ @Override
+ public Table getTable() {
+ return this.table;
+ }
+
+ @Override
+ public MybatisPersistentEntity> getMappingEntity() {
+ return this.entity;
+ }
+
+ @Override
+ public PrimaryKey getPrimaryKey() {
+ return this.primaryKey;
+ }
+
+ @Override
+ public Collection getNormalColumns() {
+ return (Collection) this.normalColumns.values();
+ }
+
+ @Override
+ public Collection getVersionColumns() {
+ return (Collection) this.versionColumns.values();
+ }
+
+ @Override
+ public Collection getEmbeddings() {
+ return (Collection) this.embeddings;
+ }
+
+ @Override
+ public Collection getOneToOneAssociations() {
+ return (Collection) this.oneToOneAssociations;
+ }
+
+ @Override
+ public Collection getManyToOneAssociations() {
+ return (Collection) this.manyToOneAssociations;
+ }
+
+ @Override
+ public Collection getOneToManyAssociations() {
+ return (Collection) this.oneToManyAssociations;
+ }
+
+ @Override
+ public Collection getManyToManyAssociations() {
+ return (Collection) this.manyToManyAssociations;
+ }
+
+ public String getTableAlias() {
+ return this.alias;
+ }
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisRepositoryPrepareProcessor.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/EmbeddedDomain.java
similarity index 38%
rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisRepositoryPrepareProcessor.java
rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/EmbeddedDomain.java
index eebd93d2a426237bbc94687ec95b82b527c49433..b878340d5bdd5b6b2049f64043daf8ab653c654b 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisRepositoryPrepareProcessor.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/EmbeddedDomain.java
@@ -13,42 +13,38 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.data.mybatis.repository.query;
+package org.springframework.data.mybatis.mapping.model;
-import org.apache.ibatis.session.Configuration;
-
-import org.springframework.aop.framework.ProxyFactory;
-import org.springframework.data.mybatis.dialect.Dialect;
import org.springframework.data.mybatis.mapping.MybatisMappingContext;
-import org.springframework.data.repository.core.RepositoryInformation;
-import org.springframework.data.repository.core.support.RepositoryProxyPostProcessor;
+import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
/**
- * {@link RepositoryProxyPostProcessor} that sets up interceptors to read metadata
- * information from the invoked method.
+ * .
*
* @author JARVIS SONG
- * @since 2.0.0
+ * @since 2.0.2
*/
-public class MybatisRepositoryPrepareProcessor implements RepositoryProxyPostProcessor {
+public class EmbeddedDomain extends Domain implements Embedding {
+
+ private static final long serialVersionUID = 1341386972281765879L;
- private final MybatisMappingContext mappingContext;
+ private final MybatisPersistentProperty property;
- private final Configuration configuration;
+ public EmbeddedDomain(MybatisMappingContext mappingContext, Model owner, MybatisPersistentProperty property,
+ String alias) {
+ super(mappingContext, owner, property.getType(), alias);
- private final Dialect dialect;
+ this.property = property;
+ }
- public MybatisRepositoryPrepareProcessor(MybatisMappingContext mappingContext, Configuration configuration,
- Dialect dialect) {
- this.mappingContext = mappingContext;
- this.configuration = configuration;
- this.dialect = dialect;
+ public MybatisPersistentProperty getProperty() {
+ return this.property;
}
@Override
- public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) {
- new SimpleMybatisPrecompiler(this.mappingContext, this.configuration, this.dialect, repositoryInformation)
- .precompile();
+ public String getTableAlias() {
+ String alias = super.getTableAlias();
+ return alias.substring(0, alias.lastIndexOf("."));
}
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Embedding.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Embedding.java
new file mode 100644
index 0000000000000000000000000000000000000000..76d80ae371dda9e5d6350b6ae35c733d3c005c51
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Embedding.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.mapping.model;
+
+/**
+ * .
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public interface Embedding extends Model {
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ForeignKey.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ForeignKey.java
new file mode 100644
index 0000000000000000000000000000000000000000..c7c9bd990de7f502ebbe6b6fc40fcfff5e6f89d2
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ForeignKey.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.mapping.model;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.JoinColumns;
+
+import org.springframework.data.mapping.MappingException;
+import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
+import org.springframework.util.StringUtils;
+
+/**
+ * .
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public class ForeignKey implements Component {
+
+ private static final long serialVersionUID = 2476229243396329609L;
+
+ private final List columns = new LinkedList<>();
+
+ private final Model model;
+
+ private final ManyToOneAssociation assModel;
+
+ public ForeignKey(Model model, ManyToOneAssociation assModel, MybatisPersistentProperty property) {
+ this.model = model;
+ this.assModel = assModel;
+
+ Set joinColumnAnns = new HashSet<>();
+ JoinColumns joinColumnsAnn = property.findAnnotation(JoinColumns.class);
+ if (null != joinColumnsAnn && joinColumnsAnn.value().length > 0) {
+ joinColumnAnns.addAll(Arrays.asList(joinColumnsAnn.value()));
+ }
+ javax.persistence.JoinColumn joinColumnAnn = property.findAnnotation(javax.persistence.JoinColumn.class);
+ if (null != joinColumnAnn) {
+ joinColumnAnns.add(joinColumnAnn);
+ }
+
+ if (!joinColumnAnns.isEmpty()) {
+ joinColumnAnns.stream().map(jc -> this.processJoinColumn(property, jc.name(), jc.referencedColumnName()))
+ .forEach(jc -> this.columns.add(jc));
+ }
+ else {
+ this.columns.add(this.processJoinColumn(property, null, null));
+ }
+ }
+
+ private JoinColumn processJoinColumn(MybatisPersistentProperty property, String columnName,
+ String referencedColumnName) {
+ Model targetModel = this.model.getMappingContext().getRequiredModel(property.getActualType());
+ PrimaryKey primaryKey = this.model.getPrimaryKey();
+ if (StringUtils.isEmpty(referencedColumnName) && !(primaryKey instanceof SinglePrimaryKey)) {
+ throw new MappingException("Could not find referenced column name for: " + property);
+ }
+
+ referencedColumnName = StringUtils.hasText(referencedColumnName) ? referencedColumnName
+ : primaryKey.getColumns().iterator().next().getName().getCanonicalName();
+ Column referencedColumn = targetModel.findColumn(referencedColumnName);
+ if (null == referencedColumn) {
+ throw new MappingException("Could not find referenced column by " + referencedColumnName);
+ }
+
+ Column foreign = new Column(this.assModel, referencedColumn.getProperty());
+ foreign.setName(referencedColumn.getName());
+ foreign.setJavaType(referencedColumn.getJavaType());
+ foreign.setJdbcType(referencedColumn.getJdbcType());
+ foreign.setTypeHandler(referencedColumn.getTypeHandler());
+ Column local = new Column(this.model, property);
+ local.setName(Identifier.toIdentifier(
+ StringUtils.hasText(columnName) ? columnName : property.getName() + '_' + foreign.getName().getText()));
+ local.setJavaType(foreign.getJavaType());
+ local.setJdbcType(foreign.getJdbcType());
+ local.setTypeHandler(foreign.getTypeHandler());
+
+ return new JoinColumn(local, foreign);
+ }
+
+ @Override
+ public Model getModel() {
+ return this.model;
+ }
+
+ public List getColumns() {
+ return this.columns;
+ }
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Identifier.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Identifier.java
index 3e8a59695b6d385fd222581eba9cae10d839156f..207bce775bede5caa8194495c58445b1d01dce9d 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Identifier.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Identifier.java
@@ -98,7 +98,7 @@ public class Identifier implements Comparable {
if (null != this.dialect) {
return this.render(this.dialect);
}
- return this.isQuoted() ? ('`' + this.getText() + '`') : this.getText();
+ return this.isQuoted() ? ('"' + this.getText() + '"') : this.getText();
}
public String getCanonicalName() {
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/JoinColumn.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/JoinColumn.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d67a41ce7eba60277ef8c4da85f303f568c4b24
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/JoinColumn.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.mapping.model;
+
+/**
+ * .
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public class JoinColumn implements Component {
+
+ private static final long serialVersionUID = -8697900456930913224L;
+
+ protected final Column local;
+
+ protected final Column foreign;
+
+ public JoinColumn(Column local, Column foreign) {
+ this.local = local;
+ this.foreign = foreign;
+ }
+
+ @Override
+ public Model getModel() {
+ return null;
+ }
+
+ public Column getLocal() {
+ return this.local;
+ }
+
+ public Column getForeign() {
+ return this.foreign;
+ }
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/JoinTable.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/JoinTable.java
new file mode 100644
index 0000000000000000000000000000000000000000..1af63c4c647be3bdcd9b214f89e8628b906bda30
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/JoinTable.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.mapping.model;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.springframework.data.mapping.MappingException;
+import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
+import org.springframework.util.StringUtils;
+
+/**
+ * .
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public class JoinTable implements Component {
+
+ private final Model model;
+
+ private final Model targetModel;
+
+ private final ManyToManyAssociation assModel;
+
+ private Table table;
+
+ private final List joinColumns = new LinkedList<>();
+
+ private final List inverseJoinColumns = new LinkedList<>();
+
+ public JoinTable(Model model, ManyToManyAssociation assModel, MybatisPersistentProperty property) {
+ this.model = model;
+ this.assModel = assModel;
+ this.targetModel = model.getMappingContext().getRequiredModel(property.getActualType());
+ this.initialize(property);
+ }
+
+ private void initialize(MybatisPersistentProperty property) {
+ String schema = null;
+ String catalog = null;
+ String name = null;
+ if (property.isAnnotationPresent(javax.persistence.JoinTable.class)) {
+ javax.persistence.JoinTable tableAnn = property.getRequiredAnnotation(javax.persistence.JoinTable.class);
+ schema = tableAnn.schema();
+ catalog = tableAnn.catalog();
+ name = tableAnn.name();
+ }
+ if (StringUtils.isEmpty(name)) {
+ name = this.model.getTable().getName().getText() + '_' + this.assModel.getTable().getName().getText();
+ }
+ this.table = new Table(schema, catalog, name);
+
+ if (property.isAnnotationPresent(javax.persistence.JoinTable.class)) {
+ javax.persistence.JoinTable tableAnn = property.getRequiredAnnotation(javax.persistence.JoinTable.class);
+ if (null != tableAnn.joinColumns() && tableAnn.joinColumns().length > 0) {
+ if (tableAnn.joinColumns().length > 0) {
+ for (javax.persistence.JoinColumn joinColumn : tableAnn.joinColumns()) {
+ this.joinColumns.add(this.processJoinColumn(this.model, joinColumn.name(),
+ joinColumn.referencedColumnName()));
+ }
+ }
+ if (null != tableAnn.inverseJoinColumns() && tableAnn.inverseJoinColumns().length > 0) {
+ for (javax.persistence.JoinColumn inverseJoinColumn : tableAnn.inverseJoinColumns()) {
+ this.inverseJoinColumns.add(this.processJoinColumn(this.assModel, inverseJoinColumn.name(),
+ inverseJoinColumn.referencedColumnName()));
+ }
+
+ }
+ }
+ }
+
+ if (this.joinColumns.isEmpty()) {
+ this.joinColumns.add(this.processJoinColumn(this.model, null, null));
+ }
+ if (this.inverseJoinColumns.isEmpty()) {
+ this.inverseJoinColumns.add(this.processJoinColumn(this.assModel, null, null));
+ }
+
+ }
+
+ private JoinColumn processJoinColumn(Model targetModel, String name, String referencedColumnName) {
+ PrimaryKey primaryKey = targetModel.getPrimaryKey();
+ if (StringUtils.isEmpty(referencedColumnName) && !(primaryKey instanceof SinglePrimaryKey)) {
+ throw new MappingException("Could not find referenced column name for: " + targetModel.getAlias());
+ }
+ referencedColumnName = StringUtils.hasText(referencedColumnName) ? referencedColumnName
+ : primaryKey.getColumns().iterator().next().getName().getCanonicalName();
+ Column referencedColumn = targetModel.findColumn(referencedColumnName);
+ if (null == referencedColumn) {
+ throw new MappingException("Could not find referenced column by " + referencedColumnName);
+ }
+
+ Column foreign = new Column(targetModel, referencedColumn.getProperty());
+ foreign.setName(referencedColumn.getName());
+ foreign.setJavaType(referencedColumn.getJavaType());
+ foreign.setJdbcType(referencedColumn.getJdbcType());
+ foreign.setTypeHandler(referencedColumn.getTypeHandler());
+
+ Column local = new Column(targetModel, referencedColumn.getProperty());
+ local.setName(Identifier.toIdentifier(StringUtils.hasText(name) ? name
+ : targetModel.getTable().getName().getText() + '_' + foreign.getName().getText()));
+ local.setJavaType(foreign.getJavaType());
+ local.setJdbcType(foreign.getJdbcType());
+ local.setTypeHandler(foreign.getTypeHandler());
+ return new JoinColumn(local, foreign);
+ }
+
+ @Override
+ public Model getModel() {
+ return this.model;
+ }
+
+ public Table getTable() {
+ return this.table;
+ }
+
+ public List getJoinColumns() {
+ return this.joinColumns;
+ }
+
+ public List getInverseJoinColumns() {
+ return this.inverseJoinColumns;
+ }
+
+ public Model getTargetModel() {
+ return this.targetModel;
+ }
+
+ public String getTableAlias() {
+ return "ass_" + this.assModel.getTableAlias();
+ }
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ManyToManyAssociation.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ManyToManyAssociation.java
new file mode 100644
index 0000000000000000000000000000000000000000..6c6623e56a85aa57b11872c7616a26d3f1744aaf
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ManyToManyAssociation.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.mapping.model;
+
+import javax.persistence.FetchType;
+import javax.persistence.ManyToMany;
+
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.data.mybatis.annotation.Fetch;
+import org.springframework.data.mybatis.annotation.FetchMode;
+import org.springframework.data.mybatis.mapping.MybatisMappingContext;
+import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
+
+/**
+ * .
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public class ManyToManyAssociation extends Domain implements Association {
+
+ private static final long serialVersionUID = -4694636482266575894L;
+
+ private final MybatisPersistentProperty property;
+
+ protected FetchType fetchType;
+
+ protected FetchMode fetchMode;
+
+ protected final JoinTable joinTable;
+
+ public ManyToManyAssociation(MybatisMappingContext mappingContext, Model owner, MybatisPersistentProperty property,
+ String alias) {
+ super(mappingContext, owner, property.getActualType(), alias);
+ this.property = property;
+ this.fetchType = (FetchType) AnnotationUtils.getValue(property.findAnnotation(ManyToMany.class), "fetch");
+ Fetch fetch = property.findAnnotation(Fetch.class);
+ if (null != fetch) {
+ this.fetchMode = fetch.value();
+ }
+ else {
+ this.fetchMode = FetchMode.SELECT; // default
+ }
+ this.joinTable = new JoinTable(owner, this, property);
+ }
+
+ public MybatisPersistentProperty getProperty() {
+ return this.property;
+ }
+
+ public String getFetchType() {
+ if (null == this.fetchType) {
+ return null;
+ }
+ return this.fetchType.name().toLowerCase();
+ }
+
+ public FetchMode getFetchMode() {
+ return this.fetchMode;
+ }
+
+ public JoinTable getJoinTable() {
+ return this.joinTable;
+ }
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ManyToOneAssociation.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ManyToOneAssociation.java
new file mode 100644
index 0000000000000000000000000000000000000000..f597be809191e21794358df2f7ee60d1879bd240
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/ManyToOneAssociation.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.mapping.model;
+
+import java.lang.annotation.Annotation;
+
+import javax.persistence.FetchType;
+import javax.persistence.ManyToOne;
+
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.data.mybatis.annotation.Fetch;
+import org.springframework.data.mybatis.annotation.FetchMode;
+import org.springframework.data.mybatis.mapping.MybatisMappingContext;
+import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
+
+/**
+ * .
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public class ManyToOneAssociation extends Domain implements Association {
+
+ private static final long serialVersionUID = 2812139190023990667L;
+
+ private final MybatisPersistentProperty property;
+
+ protected FetchType fetchType;
+
+ protected FetchMode fetchMode;
+
+ protected ForeignKey foreignKey;
+
+ public ManyToOneAssociation(MybatisMappingContext mappingContext, Model owner, MybatisPersistentProperty property,
+ String alias) {
+ super(mappingContext, owner, property.getType(), alias);
+ this.fetchType = (FetchType) AnnotationUtils.getValue(property.findAnnotation(this.getAnnotation()), "fetch");
+ this.property = property;
+ Fetch fetch = property.findAnnotation(Fetch.class);
+ if (null != fetch) {
+ this.fetchMode = fetch.value();
+ }
+ else {
+ this.fetchMode = FetchMode.SELECT; // default
+ }
+
+ this.foreignKey = new ForeignKey(owner, this, property);
+
+ }
+
+ public String fetchType() {
+ if (null == this.fetchType) {
+ return null;
+ }
+ return this.fetchType.name().toLowerCase();
+ }
+
+ protected Class extends Annotation> getAnnotation() {
+ return ManyToOne.class;
+ }
+
+ public boolean isLeftJoin() {
+ return this.fetchMode == FetchMode.JOIN;
+ }
+
+ public FetchType getFetchType() {
+ return this.fetchType;
+ }
+
+ public FetchMode getFetchMode() {
+ return this.fetchMode;
+ }
+
+ public ForeignKey getForeignKey() {
+ return this.foreignKey;
+ }
+
+ public MybatisPersistentProperty getProperty() {
+ return this.property;
+ }
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Collection.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Model.java
similarity index 34%
rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Collection.java
rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Model.java
index 9d818d907a0b8f9901fed67efa84d06fc279581d..7bceda7442b84ef72f50c3d7b5f6b4c7d21199a8 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Collection.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Model.java
@@ -16,92 +16,53 @@
package org.springframework.data.mybatis.mapping.model;
import java.io.Serializable;
-import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
-import lombok.Data;
-import lombok.experimental.Accessors;
-
-import org.springframework.util.StringUtils;
+import org.springframework.data.mapping.PropertyPath;
+import org.springframework.data.mybatis.mapping.MybatisMappingContext;
+import org.springframework.data.mybatis.mapping.MybatisPersistentEntity;
/**
- * Collection association.
+ * .
*
* @author JARVIS SONG
- * @since 2.1.0
+ * @since 2.0.2
*/
-@Data
-@Accessors(chain = true)
-public class Collection implements Serializable {
-
- private String property;
-
- private String ofType;
-
- private String column;
-
- private String select;
-
- private String fetch;
-
- private JoinTable joinTable;
-
- private List joinColumns = new ArrayList<>();
-
- private String targetTable;
+public interface Model extends Serializable {
- private boolean manyToMany;
+ MybatisMappingContext getMappingContext();
- private String order;
+ String getAlias();
- public Collection addJoinColumn(JoinColumn jc) {
- this.joinColumns.add(jc);
- return this;
- }
+ Model getOwner();
- public boolean isOrderBy() {
- return StringUtils.hasText(this.order);
- }
+ Table getTable();
- @Data
- @Accessors(chain = true)
- public static class JoinTable {
+ MybatisPersistentEntity> getMappingEntity();
- private String tableName;
+ PrimaryKey getPrimaryKey();
- private List joinColumns = new ArrayList<>();
+ Collection getNormalColumns();
- private List inverseJoinColumns = new ArrayList<>();
+ Collection getVersionColumns();
- public JoinTable(String tableName) {
- this.tableName = tableName;
- }
+ Collection getEmbeddings();
- public JoinTable addJoinColumn(JoinColumn jc) {
- this.joinColumns.add(jc);
- return this;
- }
+ Collection getOneToOneAssociations();
- public JoinTable addInverseJoinColumns(JoinColumn jc) {
- this.inverseJoinColumns.add(jc);
- return this;
- }
+ Collection getManyToOneAssociations();
- }
+ Collection getOneToManyAssociations();
- @Data
- @Accessors(chain = true)
- public static class JoinColumn {
+ Collection getManyToManyAssociations();
- private String name;
+ Column findColumn(String columnName);
- private String referencedColumnName;
+ Column findColumn(PropertyPath propertyPath);
- public JoinColumn(String name, String referencedColumnName) {
- this.name = name;
- this.referencedColumnName = referencedColumnName;
- }
+ Column findColumnByPropertyName(String propertyName);
- }
+ List findColumnByTypeHandler(Class> typeHandlerClass);
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/OneToManyAssociation.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/OneToManyAssociation.java
new file mode 100644
index 0000000000000000000000000000000000000000..697a784411ff8df896bc4d1e8ff0428678bea905
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/OneToManyAssociation.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.mapping.model;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumns;
+import javax.persistence.OneToMany;
+
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.data.mapping.MappingException;
+import org.springframework.data.mybatis.annotation.Fetch;
+import org.springframework.data.mybatis.annotation.FetchMode;
+import org.springframework.data.mybatis.mapping.MybatisMappingContext;
+import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
+import org.springframework.util.StringUtils;
+
+/**
+ * .
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public class OneToManyAssociation extends Domain implements Association {
+
+ private static final long serialVersionUID = -5958192304583654899L;
+
+ private final MybatisPersistentProperty property;
+
+ protected FetchType fetchType;
+
+ protected FetchMode fetchMode;
+
+ protected final List joinColumns = new LinkedList<>();
+
+ protected final Model targetModel;
+
+ public OneToManyAssociation(MybatisMappingContext mappingContext, Model owner, MybatisPersistentProperty property,
+ String alias) {
+ super(mappingContext, owner, property.getActualType(), alias);
+ this.property = property;
+ this.fetchType = (FetchType) AnnotationUtils.getValue(property.findAnnotation(OneToMany.class), "fetch");
+ Fetch fetch = property.findAnnotation(Fetch.class);
+ if (null != fetch) {
+ this.fetchMode = fetch.value();
+ }
+ else {
+ this.fetchMode = FetchMode.SELECT; // default
+ }
+
+ this.targetModel = mappingContext.getRequiredModel(property.getActualType());
+
+ JoinColumns joinColumnsAnn = property.findAnnotation(JoinColumns.class);
+ if (null != joinColumnsAnn && joinColumnsAnn.value().length > 0) {
+ for (javax.persistence.JoinColumn joinColumnAnn : joinColumnsAnn.value()) {
+ this.joinColumns.add(this.processJoinColumn(this.targetModel, joinColumnAnn.name(),
+ joinColumnAnn.referencedColumnName()));
+ }
+ }
+ javax.persistence.JoinColumn joinColumnAnn = property.findAnnotation(javax.persistence.JoinColumn.class);
+ if (null != joinColumnAnn) {
+ this.joinColumns.add(this.processJoinColumn(this.targetModel, joinColumnAnn.name(),
+ joinColumnAnn.referencedColumnName()));
+ }
+
+ if (this.joinColumns.isEmpty()) {
+ this.joinColumns.add(this.processJoinColumn(this.targetModel, null, null));
+ }
+
+ }
+
+ private JoinColumn processJoinColumn(Model targetModel, String name, String referencedColumnName) {
+ PrimaryKey primaryKey = targetModel.getPrimaryKey();
+ if (StringUtils.isEmpty(referencedColumnName) && !(primaryKey instanceof SinglePrimaryKey)) {
+ throw new MappingException("Could not find referenced column name for: " + targetModel.getAlias());
+ }
+ referencedColumnName = StringUtils.hasText(referencedColumnName) ? referencedColumnName
+ : primaryKey.getColumns().iterator().next().getName().getCanonicalName();
+ Column referencedColumn = targetModel.findColumn(referencedColumnName);
+ if (null == referencedColumn) {
+ throw new MappingException("Could not find referenced column by " + referencedColumnName);
+ }
+
+ Column foreign = new Column(targetModel, referencedColumn.getProperty());
+ foreign.setName(referencedColumn.getName());
+ foreign.setJavaType(referencedColumn.getJavaType());
+ foreign.setJdbcType(referencedColumn.getJdbcType());
+ foreign.setTypeHandler(referencedColumn.getTypeHandler());
+
+ Column local = new Column(targetModel, referencedColumn.getProperty());
+ local.setName(Identifier.toIdentifier(StringUtils.hasText(name) ? name
+ : targetModel.getTable().getName().getText() + '_' + foreign.getName().getText()));
+ local.setJavaType(foreign.getJavaType());
+ local.setJdbcType(foreign.getJdbcType());
+ local.setTypeHandler(foreign.getTypeHandler());
+ return new JoinColumn(local, foreign);
+ }
+
+ public MybatisPersistentProperty getProperty() {
+ return this.property;
+ }
+
+ public String getFetchType() {
+ if (null == this.fetchType) {
+ return null;
+ }
+ return this.fetchType.name().toLowerCase();
+ }
+
+ public FetchMode getFetchMode() {
+ return this.fetchMode;
+ }
+
+ public List getJoinColumns() {
+ return this.joinColumns;
+ }
+
+ public Model getTargetModel() {
+ return this.targetModel;
+ }
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/OneToOneAssociation.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/OneToOneAssociation.java
new file mode 100644
index 0000000000000000000000000000000000000000..e5849d03f130f5846166f3b1b40012de925009ce
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/OneToOneAssociation.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.mapping.model;
+
+import java.lang.annotation.Annotation;
+
+import javax.persistence.OneToOne;
+
+import org.springframework.data.mybatis.mapping.MybatisMappingContext;
+import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
+
+/**
+ * .
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public class OneToOneAssociation extends ManyToOneAssociation {
+
+ private static final long serialVersionUID = 240806944716674713L;
+
+ public OneToOneAssociation(MybatisMappingContext mappingContext, Model owner, MybatisPersistentProperty property,
+ String alias) {
+ super(mappingContext, owner, property, alias);
+ }
+
+ @Override
+ protected Class extends Annotation> getAnnotation() {
+ return OneToOne.class;
+ }
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/PrimaryKey.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/PrimaryKey.java
new file mode 100644
index 0000000000000000000000000000000000000000..229959e400f5e3b3bf0ae5cee5b9eb30a74111c5
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/PrimaryKey.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.mapping.model;
+
+import java.util.Collection;
+
+/**
+ * .
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public interface PrimaryKey extends Component {
+
+ /**
+ * Default sequence name.
+ */
+ String DEFAULT_SEQUENCE_NAME = "seq_spring_data_mybatis";
+
+ boolean isComposited();
+
+ Collection getColumns();
+
+ Class> getType();
+
+ Column findColumn(String name);
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/SinglePrimaryKey.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/SinglePrimaryKey.java
new file mode 100644
index 0000000000000000000000000000000000000000..c28a879431179b30b43239672a46aca0812b5922
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/SinglePrimaryKey.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.mapping.model;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.SequenceGenerators;
+
+import org.springframework.data.mybatis.dialect.Dialect;
+import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
+import org.springframework.util.StringUtils;
+
+/**
+ * .
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public class SinglePrimaryKey implements PrimaryKey {
+
+ private final Column column;
+
+ private final Model model;
+
+ private final MybatisPersistentProperty property;
+
+ private boolean generatedKeys;
+
+ private String keySql;
+
+ private String executeOrder;
+
+ public SinglePrimaryKey(Model model, MybatisPersistentProperty property) {
+ this.model = model;
+ this.property = property;
+
+ this.column = new Column(model, property);
+
+ this.processGeneratedPrimaryKey();
+
+ }
+
+ private void processGeneratedPrimaryKey() {
+ this.generatedKeys = this.property.isAnnotationPresent(GeneratedValue.class);
+ if (!this.generatedKeys) {
+ return;
+ }
+
+ GeneratedValue gv = this.property.findAnnotation(GeneratedValue.class);
+ Dialect dialect = this.model.getMappingContext().getDialect();
+ if (gv.strategy() == GenerationType.IDENTITY || (gv.strategy() == GenerationType.AUTO
+ && "identity".equals(dialect.getNativeIdentifierGeneratorStrategy()))) {
+ // identity
+ this.keySql = dialect.getIdentityColumnSupport().getIdentitySelectString(this.model.getTable().toString(),
+ this.column.getName().getCanonicalName(), this.column.getJdbcType().TYPE_CODE);
+ this.executeOrder = "AFTER";
+ }
+ else if (gv.strategy() == GenerationType.SEQUENCE || (gv.strategy() == GenerationType.AUTO
+ && "sequence".equals(dialect.getNativeIdentifierGeneratorStrategy()))) {
+ String sequenceName = DEFAULT_SEQUENCE_NAME;
+ if (StringUtils.hasText(gv.generator())) {
+ // search sequence generator
+ Map sequenceGenerators = new HashMap<>();
+ SequenceGenerators sequenceGeneratorsAnn = this.property
+ .findPropertyOrOwnerAnnotation(SequenceGenerators.class);
+ if (null != sequenceGeneratorsAnn && sequenceGeneratorsAnn.value().length > 0) {
+ sequenceGenerators.putAll(Stream.of(sequenceGeneratorsAnn.value())
+ .filter(sg -> StringUtils.hasText(sg.sequenceName()))
+ .collect(Collectors.toMap(SequenceGenerator::name, SequenceGenerator::sequenceName)));
+ }
+ SequenceGenerator sg = this.property.findPropertyOrOwnerAnnotation(SequenceGenerator.class);
+ if (null != sg && StringUtils.hasText(sg.sequenceName())) {
+ sequenceGenerators.put(sg.name(), sg.sequenceName());
+ }
+
+ String sn = sequenceGenerators.get(gv.generator());
+ if (StringUtils.hasText(sn)) {
+ sequenceName = sn;
+ }
+ }
+ this.keySql = dialect.getSequenceNextValString(sequenceName);
+ this.executeOrder = "BEFORE";
+ }
+ else {
+ throw new UnsupportedOperationException("unsupported generated value id strategy: " + gv.strategy());
+ }
+ }
+
+ @Override
+ public boolean isComposited() {
+ return false;
+ }
+
+ @Override
+ public Collection getColumns() {
+ return Arrays.asList(this.column);
+ }
+
+ @Override
+ public Class> getType() {
+ return this.property.getType();
+ }
+
+ @Override
+ public Column findColumn(String name) {
+ return name.equals(this.column.getName().getCanonicalName()) ? this.column : null;
+ }
+
+ @Override
+ public Model getModel() {
+ return this.model;
+ }
+
+ public boolean isGeneratedKeys() {
+ return this.generatedKeys;
+ }
+
+ public String getKeySql() {
+ return this.keySql;
+ }
+
+ public String getExecuteOrder() {
+ return this.executeOrder;
+ }
+
+ public boolean excludeInsertId() {
+ return this.generatedKeys && !"BEFORE".equals(this.executeOrder);
+ }
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Table.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Table.java
index 1dc275fa2611a5e50b303b4d43dbc435febc7464..6e2046b2bbe3da6b4f449fb6aaa0b5308a143249 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Table.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/Table.java
@@ -15,23 +15,25 @@
*/
package org.springframework.data.mybatis.mapping.model;
+import java.io.Serializable;
+
import lombok.Getter;
+import lombok.experimental.Accessors;
/**
- * Table model.
+ * .
*
* @author JARVIS SONG
- * @since 2.0.0
+ * @since 2.0.2
*/
-public class Table {
+@Getter
+@Accessors(chain = true)
+public class Table implements Serializable {
- @Getter
private Identifier schema;
- @Getter
private Identifier catalog;
- @Getter
private Identifier name;
public Table(String schema, String catalog, String name) {
@@ -44,7 +46,8 @@ public class Table {
this.name = Identifier.toIdentifier(name);
}
- public String getFullName() {
+ @Override
+ public String toString() {
return ((null != this.schema) ? (this.schema.getCanonicalName() + '.') : "") + //
((null != this.catalog) ? (this.catalog.getCanonicalName() + '.') : "") + //
this.name.getCanonicalName();
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/VersionColumn.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/VersionColumn.java
new file mode 100644
index 0000000000000000000000000000000000000000..fe69e95d7fff085c7df0e386d03ec483b855c861
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/mapping/model/VersionColumn.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.mapping.model;
+
+import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
+
+/**
+ * .
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public class VersionColumn extends Column {
+
+ private static final long serialVersionUID = 8187675205177183423L;
+
+ public VersionColumn(Model model, MybatisPersistentProperty property) {
+ super(model, property);
+ }
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/AbstractMybatisPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/AbstractMybatisPrecompiler.java
new file mode 100644
index 0000000000000000000000000000000000000000..4fac08b1f699167c73177e517e63f27e026223e3
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/AbstractMybatisPrecompiler.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.precompiler;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import com.samskivert.mustache.Mustache;
+import com.samskivert.mustache.Mustache.InvertibleLambda;
+import com.samskivert.mustache.Mustache.Lambda;
+import com.samskivert.mustache.Template.Fragment;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.builder.xml.XMLMapperBuilder;
+import org.apache.ibatis.executor.ErrorContext;
+import org.apache.ibatis.session.Configuration;
+
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.data.mapping.MappingException;
+import org.springframework.data.mybatis.dialect.pagination.SQLServer2005LimitHandler;
+import org.springframework.data.mybatis.dialect.pagination.SQLServer2012LimitHandler;
+import org.springframework.data.mybatis.mapping.MybatisMappingContext;
+import org.springframework.data.mybatis.mapping.model.Identifier;
+import org.springframework.data.mybatis.mapping.model.Model;
+import org.springframework.data.mybatis.repository.query.DefaultCollector;
+import org.springframework.data.mybatis.repository.support.SqlSessionRepositorySupport;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * Abstract mybatis mapper precompiler.
+ *
+ * @author JARVIS SONG
+ */
+@Slf4j
+abstract class AbstractMybatisPrecompiler implements MybatisPrecompiler {
+
+ protected static final String SCOPE_STATEMENT_NAME = "statementName";
+
+ protected static final String SCOPE_RESULT_MAP = "resultMap";
+
+ protected final MybatisMappingContext mappingContext;
+
+ protected final Model domain;
+
+ protected final Mustache.Compiler mustache;
+
+ protected AbstractMybatisPrecompiler(MybatisMappingContext mappingContext, Model domain) {
+ this.mappingContext = mappingContext;
+ this.domain = domain;
+ this.mustache = Mustache.compiler().withLoader(name -> {
+ InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(this.getTemplatePath(name));
+ return new InputStreamReader(inputStream, StandardCharsets.UTF_8);
+ }).escapeHTML(false).withCollector(new DefaultCollector());
+ }
+
+ @Override
+ public void compile() {
+ this.compileMapper(this.domain.getMappingEntity().getName(), this.prepareStatements());
+ }
+
+ protected abstract Collection prepareStatements();
+
+ protected String render(String name, Map scopes) {
+ if (null == scopes) {
+ scopes = new HashMap<>();
+ }
+ scopes.put("domain", this.domain);
+ scopes.put("quote", (Lambda) (frag, out) -> out.write(this.quote(frag.execute())));
+ scopes.put("testNotNull", this.lambdaTestNotNull());
+ scopes.put("escapeQuotes", (Lambda) (frag, out) -> out.write(frag.execute().replace("\"", "\\\"")));
+ scopes.put("lowercaseFunction", this.mappingContext.getDialect().getLowercaseFunction());
+ scopes.put("SQLServer2005",
+ this.mappingContext.getDialect().getLimitHandler().getClass() == SQLServer2005LimitHandler.class);
+ scopes.put("SQLServer2012",
+ this.mappingContext.getDialect().getLimitHandler().getClass() == SQLServer2012LimitHandler.class);
+ try (InputStream is = new ClassPathResource(this.getTemplatePath(name)).getInputStream();
+ InputStreamReader source = new InputStreamReader(is, StandardCharsets.UTF_8)) {
+ return this.mustache.compile(source).execute(scopes);
+ }
+ catch (IOException ex) {
+ throw new MappingException("Could not render the statement: " + name, ex);
+ }
+ }
+
+ protected void compileMapper(String namespace, Collection statements) {
+ this.compileMapper(this.getResource("basic", namespace), namespace, statements);
+ }
+
+ protected void compileMapper(String resource, String namespace, Collection statements) {
+ if (CollectionUtils.isEmpty(statements)) {
+ return;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put("namespace", namespace);
+ scopes.put("statements", statements);
+ scopes.put("resource", resource + this.getResourceSuffix());
+ String mapper = this.render("Mapper", scopes);
+
+ if (log.isDebugEnabled()) {
+ log.debug(mapper);
+ }
+ Configuration configuration = this.mappingContext.getSqlSessionTemplate().getConfiguration();
+ try (InputStream is = new ByteArrayInputStream(mapper.getBytes(StandardCharsets.UTF_8))) {
+ XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(is, configuration,
+ resource + this.getResourceSuffix(), configuration.getSqlFragments());
+ xmlMapperBuilder.parse();
+ }
+ catch (Exception ex) {
+ throw new MappingException(ex.getMessage(), ex);
+ }
+ finally {
+ ErrorContext.instance().reset();
+ }
+ }
+
+ protected boolean checkSqlFragment(String name) {
+ return this.mappingContext.getSqlSessionTemplate().getConfiguration().getSqlFragments()
+ .containsKey(this.domain.getMappingEntity().getName() + SqlSessionRepositorySupport.DOT + name);
+ }
+
+ protected boolean checkResultMap(String name) {
+ return this.mappingContext.getSqlSessionTemplate().getConfiguration()
+ .hasResultMap(this.domain.getMappingEntity().getName() + SqlSessionRepositorySupport.DOT + name);
+ }
+
+ protected boolean checkStatement(String name) {
+ return this.checkStatement(this.domain.getMappingEntity().getName(), name);
+ }
+
+ protected boolean checkStatement(String namespace, String name) {
+ return this.mappingContext.getSqlSessionTemplate().getConfiguration()
+ .hasStatement(namespace + SqlSessionRepositorySupport.DOT + name, false);
+ }
+
+ protected String getResource(String dir, String namespace) {
+ return dir + '/' + namespace.replace('.', '/');
+ }
+
+ protected String getResourceSuffix() {
+ return ".xml";
+ }
+
+ protected String getTemplatePath(String name) {
+ return "org/springframework/data/mybatis/repository/query/template/" + name + ".mustache";
+ }
+
+ protected String quote(String name) {
+ return Identifier.toIdentifier(name, true).render(this.mappingContext.getDialect());
+ }
+
+ Mustache.InvertibleLambda lambdaTestNotNull() {
+ return new InvertibleLambda() {
+ @Override
+ public void execute(Fragment frag, Writer out) throws IOException {
+ out.write(this.testClause(frag.execute().trim(), true, true));
+ }
+
+ @Override
+ public void executeInverse(Fragment frag, Writer out) throws IOException {
+ out.write(this.testClause(frag.execute().trim(), false, false));
+ }
+
+ protected String testClause(String propertyName, boolean and, boolean not) {
+ String[] parts = propertyName.split("\\.");
+ String[] conditions = new String[parts.length];
+ String prev = null;
+ for (int i = 0; i < parts.length; i++) {
+ conditions[i] = ((null != prev) ? (prev + ".") : "") + parts[i];
+ prev = conditions[i];
+ }
+ String test = Stream.of(conditions).map(c -> c.trim() + (not ? " !" : " =") + "= null")
+ .collect(Collectors.joining(and ? " and " : " or "));
+ return test;
+ }
+ };
+ }
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/MybatisPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/MybatisPrecompiler.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f6515f39b258507627c1b4833b19c7d7e2423fd
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/MybatisPrecompiler.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.precompiler;
+
+/**
+ * Spring data mybatis mapper precompiler.
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public interface MybatisPrecompiler {
+
+ void compile();
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisQueryPrepareProcessor.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/MybatisQueryPrepareProcessor.java
similarity index 65%
rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisQueryPrepareProcessor.java
rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/MybatisQueryPrepareProcessor.java
index 575f3595d7b11ab6f5da9212e7ee2a09887f59f7..ee76df31479547467ce4b8bd18605bcb9c7a26c4 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisQueryPrepareProcessor.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/MybatisQueryPrepareProcessor.java
@@ -13,12 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.data.mybatis.repository.query;
+package org.springframework.data.mybatis.precompiler;
-import org.apache.ibatis.session.Configuration;
-
-import org.springframework.data.mybatis.dialect.Dialect;
import org.springframework.data.mybatis.mapping.MybatisMappingContext;
+import org.springframework.data.mybatis.repository.query.PartTreeMybatisQuery;
+import org.springframework.data.mybatis.repository.query.SimpleMybatisQuery;
import org.springframework.data.repository.core.support.QueryCreationListener;
import org.springframework.data.repository.query.RepositoryQuery;
@@ -26,41 +25,29 @@ import org.springframework.data.repository.query.RepositoryQuery;
* Prepare mybatis mapper statement when a query created.
*
* @author JARVIS SONG
- * @since 2.0.0
+ * @since 2.0.1
*/
public class MybatisQueryPrepareProcessor implements QueryCreationListener {
private final MybatisMappingContext mappingContext;
- private final Configuration configuration;
-
- private final Dialect dialect;
+ public MybatisQueryPrepareProcessor(MybatisMappingContext mappingContext) {
- public MybatisQueryPrepareProcessor(MybatisMappingContext mappingContext, Configuration configuration,
- Dialect dialect) {
this.mappingContext = mappingContext;
- this.configuration = configuration;
- this.dialect = dialect;
}
@Override
public void onCreation(RepositoryQuery query) {
if (query instanceof SimpleMybatisQuery) {
- new SimpleMybatisQueryPrecompiler(this.mappingContext, this.configuration, this.dialect,
- (SimpleMybatisQuery) query).precompile();
- return;
- }
- if (query instanceof PartTreeMybatisQuery) {
- new PartTreeMyBatisQueryPrecompiler(this.mappingContext, this.configuration, this.dialect,
- (PartTreeMybatisQuery) query).precompile();
+ new SimpleMybatisQueryPrecompiler(this.mappingContext, (SimpleMybatisQuery) query).compile();
return;
}
- if (query instanceof StoredProcedureMybatisQuery) {
+ if (query instanceof PartTreeMybatisQuery) {
+ new PartTreeMybatisQueryPrecompiler(this.mappingContext, (PartTreeMybatisQuery) query).compile();
return;
}
-
}
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/PartTreeMyBatisQueryPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/PartTreeMybatisQueryPrecompiler.java
similarity index 54%
rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/PartTreeMyBatisQueryPrecompiler.java
rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/PartTreeMybatisQueryPrecompiler.java
index 54c4e40ae8d7ed8a4a027b872bb0795994792052..fea596181ff9526c91af9f945a53dec13e8d8520 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/PartTreeMyBatisQueryPrecompiler.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/PartTreeMybatisQueryPrecompiler.java
@@ -13,34 +13,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.data.mybatis.repository.query;
+package org.springframework.data.mybatis.precompiler;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import javax.persistence.EmbeddedId;
import com.samskivert.mustache.Mustache.Lambda;
import lombok.Getter;
-import org.apache.ibatis.session.Configuration;
-import org.springframework.data.mybatis.dialect.Dialect;
+import org.springframework.data.mapping.MappingException;
+import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mybatis.dialect.pagination.RowSelection;
-import org.springframework.data.mybatis.dialect.pagination.SQLServer2005LimitHandler;
-import org.springframework.data.mybatis.dialect.pagination.SQLServer2012LimitHandler;
import org.springframework.data.mybatis.mapping.MybatisMappingContext;
-import org.springframework.data.mybatis.mapping.MybatisPersistentEntity;
-import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
import org.springframework.data.mybatis.mapping.model.Column;
+import org.springframework.data.mybatis.repository.query.MybatisParameters;
import org.springframework.data.mybatis.repository.query.MybatisParameters.MybatisParameter;
+import org.springframework.data.mybatis.repository.query.MybatisQueryMethod;
+import org.springframework.data.mybatis.repository.query.PartTreeMybatisQuery;
import org.springframework.data.mybatis.repository.support.ResidentStatementName;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.Part.IgnoreCaseType;
import org.springframework.data.repository.query.parser.PartTree;
+import org.springframework.data.util.Streamable;
import org.springframework.util.StringUtils;
/**
@@ -48,129 +49,109 @@ import org.springframework.util.StringUtils;
*
* @author JARVIS SONG
*/
-class PartTreeMyBatisQueryPrecompiler extends MybatisQueryMethodPrecompiler {
+class PartTreeMybatisQueryPrecompiler extends AbstractMybatisPrecompiler {
private final PartTreeMybatisQuery query;
- private AtomicInteger argumentCounter = new AtomicInteger(0);
-
- PartTreeMyBatisQueryPrecompiler(MybatisMappingContext mappingContext, Configuration configuration, Dialect dialect,
- PartTreeMybatisQuery query) {
- super(mappingContext, configuration, dialect, query);
+ private final AtomicInteger argumentCounter = new AtomicInteger(0);
+ PartTreeMybatisQueryPrecompiler(MybatisMappingContext mappingContext, PartTreeMybatisQuery query) {
+ super(mappingContext,
+ mappingContext.getRequiredModel(query.getQueryMethod().getEntityInformation().getJavaType()));
this.query = query;
}
@Override
- protected String mainQueryString() {
- return null;
+ protected Collection prepareStatements() {
+
+ String statement = this.doPrepareStatement();
+ return StringUtils.isEmpty(statement) ? Collections.emptyList() : Collections.singletonList(statement);
}
@Override
- protected String doPrecompile() {
+ protected String getResource(String dir, String namespace) {
+ return "tree/" + this.query.getStatementId().replace('.', '/');
+ }
+
+ private String doPrepareStatement() {
PartTree tree = this.query.getTree();
MybatisQueryMethod method = this.query.getQueryMethod();
-
if (tree.isDelete()) {
- return this.addDeleteStatement(tree, method);
+ return this.deleteStatement();
}
if (tree.isCountProjection()) {
- return this.addCountStatement();
+ return this.countProjectionStatement();
}
if (tree.isExistsProjection()) {
- return this.addExistsStatement();
+ return this.existsProjectionStatement();
}
if (method.isPageQuery()) {
- return this.addPageStatement(true);
+ return this.pageQueryStatement();
}
if (method.isSliceQuery()) {
- return this.addPageStatement(false);
+ return this.sliceQueryStatement();
}
if (method.isCollectionQuery() || method.isStreamQuery()) {
- return this.addCollectionStatement();
+ return this.collectionQueryStatement();
}
-
if (method.isQueryForEntity()) {
- return this.buildSelectStatementSegment(this.query.getStatementName(), false);
+ return this.selectQueryStatement();
}
-
return null;
}
- private String addDeleteStatement(PartTree tree, MybatisQueryMethod method) {
-
+ private String deleteStatement() {
Map scopes = new HashMap<>();
- scopes.put("statementName", this.query.getStatementName());
- scopes.put("table", this.getTableName());
- scopes.put("tree", this.convert(tree));
-
- if (method.isCollectionQuery()) {
- // need to return the deleted entities collection
- return this.render("PartTreeDelete", scopes) + this.buildSelectStatementSegment(
- ResidentStatementName.QUERY_PREFIX + this.query.getStatementName(), false);
+ scopes.put("tree", this.convert(this.query.getTree(), false));
+ if (this.query.getQueryMethod().isCollectionQuery()) {
+ return this.render("PartTreeDelete", scopes) + this.render("PartTreeInnerSelect", this
+ .innerSelectQueryScopes(ResidentStatementName.QUERY_PREFIX + this.query.getStatementName(), false));
}
-
return this.render("PartTreeDelete", scopes);
-
}
- private String addCountStatement() {
- return this.buildCountStatementSegment(this.query.getStatementName());
+ private String countProjectionStatement() {
+ return this.render("PartTreeInnerCount", this.innerCountQueryScopes(this.query.getStatementName()));
}
- private String addExistsStatement() {
- return this.buildCountStatementSegment(this.query.getStatementName());
+ private String existsProjectionStatement() {
+ return this.countProjectionStatement();
}
- private String addPageStatement(boolean includeCount) {
- String sql = this.buildSelectStatementSegment(this.query.getStatementName(), true);
- sql += this.buildSelectStatementSegment(ResidentStatementName.UNPAGED_PREFIX + this.query.getStatementName(),
- false);
- if (includeCount) {
- String count = this.buildCountStatementSegment(this.query.getCountStatementName());
- return sql + count;
- }
- return sql;
+ private String pageQueryStatement() {
+ return this.render("PartTreeInnerSelect", this.innerSelectQueryScopes(this.query.getStatementName(), true))
+ + this.render("PartTreeInnerSelect",
+ this.innerSelectQueryScopes(
+ ResidentStatementName.UNPAGED_PREFIX + this.query.getStatementName(), false))
+ + this.render("PartTreeInnerCount", this.innerCountQueryScopes(this.query.getCountStatementName()));
}
- private String addCollectionStatement() {
- return this.buildSelectStatementSegment(this.query.getStatementName(),
- this.query.getQueryMethod().getParameters().hasPageableParameter());
+ private String sliceQueryStatement() {
+ return this.render("PartTreeInnerSelect", this.innerSelectQueryScopes(this.query.getStatementName(), true))
+ + this.render("PartTreeInnerSelect", this.innerSelectQueryScopes(
+ ResidentStatementName.UNPAGED_PREFIX + this.query.getStatementName(), false));
}
- private String buildCountStatementSegment(String statementName) {
- PartTree tree = this.query.getTree();
- Map scopes = new HashMap<>();
- scopes.put("statementName", statementName);
- scopes.put("table", this.getTableName());
- scopes.put("tree", this.convert(tree));
- scopes.put("columns", tree.isLimiting() ? "1" : "COUNT(*)");
- scopes.put("limiting", tree.isLimiting());
- if (tree.isLimiting()) {
- RowSelection selection = new RowSelection(0, tree.getMaxResults());
- scopes.put("limitHandler", (Lambda) (frag, out) -> {
- out.write(this.dialect.getLimitHandler().processSql(frag.execute(), selection));
- });
- scopes.put("SQLServer2005", this.dialect.getLimitHandler().getClass() == SQLServer2005LimitHandler.class);
- scopes.put("SQLServer2012", this.dialect.getLimitHandler().getClass() == SQLServer2012LimitHandler.class);
- }
+ private String collectionQueryStatement() {
+ return this.render("PartTreeInnerSelect", this.innerSelectQueryScopes(this.query.getStatementName(),
+ this.query.getQueryMethod().getParameters().hasPageableParameter()));
+ }
- return this.render("PartTreeCount", scopes);
+ private String selectQueryStatement() {
+ return this.render("PartTreeInnerSelect", this.innerSelectQueryScopes(this.query.getStatementName(), false));
}
- private String buildSelectStatementSegment(String statementName, boolean pageable) {
+ private Map innerSelectQueryScopes(String statementName, boolean pageable) {
PartTree tree = this.query.getTree();
MybatisQueryMethod method = this.query.getQueryMethod();
Map scopes = new HashMap<>();
- scopes.put("statementName", statementName);
- scopes.put("table", this.getTableName());
- scopes.put("tree", this.convert(tree));
+ scopes.put("innerStatementName", statementName);
- String columns = "*";
+ String columns = "";
if (StringUtils.hasText(method.getSelectColumns())) {
- String[] selectColumns = method.getSelectColumns().split(",");
- columns = Stream.of(selectColumns).map(String::trim).filter(StringUtils::hasText).map(
- sc -> this.persistentEntity.getRequiredPersistentProperty(sc).getColumn().getName().render(dialect))
+ String[] selectedColumns = method.getSelectColumns().split(",");
+ columns = Arrays.stream(selectedColumns).map(String::trim).filter(StringUtils::hasText).map(
+ sc -> this.domain.findColumnByPropertyName(sc).getName().render(this.mappingContext.getDialect()))
.collect(Collectors.joining(","));
}
scopes.put("columns", columns);
@@ -186,7 +167,7 @@ class PartTreeMyBatisQueryPrecompiler extends MybatisQueryMethodPrecompiler {
}
else if (null != method.getResultType()) {
scopes.put("isResultMap", false);
- if (method.getResultType() == Void.class) {
+ if (method.getResultType() == Void.class || method.getResultType() == void.class) {
scopes.put("result", method.getActualResultType());
}
else {
@@ -209,46 +190,78 @@ class PartTreeMyBatisQueryPrecompiler extends MybatisQueryMethodPrecompiler {
if (null == selection) {
selection = new RowSelection(true);
}
-
RowSelection rowSelection = selection;
- scopes.put("limitHandler", (Lambda) (frag, out) -> {
- out.write(this.dialect.getLimitHandler().processSql(frag.execute(), rowSelection));
- });
- scopes.put("SQLServer2005", this.dialect.getLimitHandler().getClass() == SQLServer2005LimitHandler.class);
- scopes.put("SQLServer2012", this.dialect.getLimitHandler().getClass() == SQLServer2012LimitHandler.class);
+ scopes.put("limitHandler", (Lambda) (frag, out) -> out.write(
+ this.mappingContext.getDialect().getLimitHandler().processSql(frag.execute(), rowSelection)));
}
-
scopes.put("pageable", pageable);
- return render("PartTreeSelect", scopes);
+ return scopes;
}
- public List convert(PartTree tree) {
- this.argumentCounter.set(0);
- return tree.stream().map(orPart -> new OrPart(orPart, this.persistentEntity, this.mappingContext,
- this.argumentCounter, this.query.getQueryMethod(), this.dialect)).collect(Collectors.toList());
+ private Map innerCountQueryScopes(String statementName) {
+ PartTree tree = this.query.getTree();
+ MybatisQueryMethod method = this.query.getQueryMethod();
+ Map scopes = new HashMap<>();
+ scopes.put("innerStatementName", statementName);
+ scopes.put("limiting", tree.isLimiting());
+ scopes.put("columns", tree.isLimiting() ? "1" : "COUNT(*)");
+ if (tree.isLimiting()) {
+ RowSelection selection = new RowSelection(0, tree.getMaxResults());
+ scopes.put("limitHandler", (Lambda) (frag, out) -> out
+ .write(this.mappingContext.getDialect().getLimitHandler().processSql(frag.execute(), selection)));
+ }
+ return scopes;
}
@Override
- protected String getResourceSuffix() {
- return "_tree_" + this.query.getStatementName() + super.getResourceSuffix();
+ protected String render(String name, Map scopes) {
+ if (null == scopes) {
+ scopes = new HashMap<>();
+ }
+ scopes.putIfAbsent(SCOPE_STATEMENT_NAME, this.query.getStatementName());
+ scopes.putIfAbsent("tree", this.convert(this.query.getTree(), true));
+ return super.render(name, scopes);
}
- @Getter
- public static class OrPart {
+ private Tree convert(PartTree tree, boolean includeAlias) {
+ this.argumentCounter.set(0); // reset the argument counter
+ return new Tree(tree, includeAlias);
+ }
+
+ public class Tree implements Streamable {
+
+ private final List orParts;
- private List parts;
+ Tree(PartTree tree, boolean includeAlias) {
+ this.orParts = tree.stream().map(orPart -> new OrPart(orPart, includeAlias)).collect(Collectors.toList());
+ }
+
+ @Override
+ public Iterator iterator() {
+ return this.orParts.iterator();
+ }
+
+ }
+
+ public class OrPart implements Streamable {
- OrPart(PartTree.OrPart or, MybatisPersistentEntity> persistentEntity, MybatisMappingContext mappingContext,
- AtomicInteger argumentCounter, MybatisQueryMethod method, Dialect dialect) {
- this.parts = or.stream()
- .map(part -> new AndPart(part, persistentEntity, mappingContext, argumentCounter, method, dialect))
- .collect(Collectors.toList());
+ private final List andParts;
+
+ OrPart(PartTree.OrPart orPart, boolean includeAlias) {
+ this.andParts = orPart.stream().map(part -> new AndPart(part, includeAlias)).collect(Collectors.toList());
+ }
+
+ @Override
+ public Iterator iterator() {
+ return this.andParts.iterator();
}
}
@Getter
- public static class AndPart {
+ public class AndPart {
+
+ private final boolean includeAlias;
private final Column column;
@@ -256,8 +269,6 @@ class PartTreeMyBatisQueryPrecompiler extends MybatisQueryMethodPrecompiler {
private boolean ignoreCase;
- private String lowercaseFunction;
-
private boolean opBetween;
private boolean opNotNull;
@@ -312,29 +323,25 @@ class PartTreeMyBatisQueryPrecompiler extends MybatisQueryMethodPrecompiler {
private boolean arrayParameter;
- AndPart(Part part, MybatisPersistentEntity> persistentEntity, MybatisMappingContext mappingContext,
- AtomicInteger argumentCounter, MybatisQueryMethod method, Dialect dialect) {
- MybatisPersistentProperty persistentProperty = persistentEntity
- .getRequiredPersistentProperty(part.getProperty().getSegment());
- if (persistentProperty.isAnnotationPresent(EmbeddedId.class) || persistentProperty.isEmbeddable()) {
- MybatisPersistentEntity> leafEntity = mappingContext
- .getRequiredPersistentEntity(part.getProperty().getLeafProperty().getOwningType());
- persistentProperty = leafEntity
- .getPersistentProperty(part.getProperty().getLeafProperty().getSegment());
+ AndPart(Part part, boolean includeAlias) {
+ this.includeAlias = includeAlias;
+ PropertyPath propertyPath = part.getProperty();
+ this.column = PartTreeMybatisQueryPrecompiler.this.domain.findColumn(propertyPath);
+ if (null == this.column) {
+ throw new MappingException("Could not find column for " + propertyPath);
}
+
if (part.shouldIgnoreCase() == IgnoreCaseType.ALWAYS
- || (part.shouldIgnoreCase() == IgnoreCaseType.WHEN_POSSIBLE && null != persistentProperty
- && CharSequence.class.isAssignableFrom(persistentProperty.getType()))) {
+ || (part.shouldIgnoreCase() == IgnoreCaseType.WHEN_POSSIBLE && this.column.isString())) {
this.ignoreCase = true;
- this.lowercaseFunction = dialect.getLowercaseFunction();
}
- this.column = persistentProperty.getColumn();
this.arguments = new String[part.getNumberOfArguments()];
if (part.getNumberOfArguments() > 0) {
- MybatisParameters parameters = method.getParameters();
+ MybatisParameters parameters = PartTreeMybatisQueryPrecompiler.this.query.getQueryMethod()
+ .getParameters();
for (int i = 0; i < part.getNumberOfArguments(); i++) {
- int counter = argumentCounter.getAndIncrement();
+ int counter = PartTreeMybatisQueryPrecompiler.this.argumentCounter.getAndIncrement();
MybatisParameter bindableParameter = parameters.getBindableParameter(counter);
this.arguments[i] = bindableParameter.getName().orElse("__p" + (bindableParameter.getIndex() + 1));
this.arrayParameter = bindableParameter.getType().isArray();
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/SimpleMybatisPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/SimpleMybatisPrecompiler.java
new file mode 100644
index 0000000000000000000000000000000000000000..73ae2aff9f32fbd8017a62b0495f1bf67cd35d2e
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/SimpleMybatisPrecompiler.java
@@ -0,0 +1,473 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.precompiler;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import com.samskivert.mustache.Mustache.Lambda;
+
+import org.springframework.data.mybatis.dialect.pagination.RowSelection;
+import org.springframework.data.mybatis.mapping.MybatisMappingContext;
+import org.springframework.data.mybatis.mapping.model.ManyToManyAssociation;
+import org.springframework.data.mybatis.mapping.model.ManyToOneAssociation;
+import org.springframework.data.mybatis.mapping.model.Model;
+import org.springframework.data.mybatis.mapping.model.OneToManyAssociation;
+import org.springframework.data.mybatis.repository.support.ResidentStatementName;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+/**
+ * Simple mybatis mapper precompiler.
+ *
+ * @author JARVIS SONG
+ * @since 2.0.2
+ */
+public class SimpleMybatisPrecompiler extends AbstractMybatisPrecompiler {
+
+ public SimpleMybatisPrecompiler(MybatisMappingContext mappingContext, Model domain) {
+ super(mappingContext, domain);
+ }
+
+ @Override
+ protected Collection prepareStatements() {
+ List statements = new ArrayList<>();
+ statements.add(this.columnListFragment());
+ statements.add(this.fromFragment());
+ statements.add(this.selectFragment());
+ statements.add(this.whereClauseByIdFragment());
+ statements.add(this.whereClauseByIdsFragment());
+ statements.add(this.standardSortFragment());
+ statements.add(this.queryByExampleWhereClauseFragment());
+
+ statements.add(this.resultMap());
+
+ statements.add(this.insertStatement());
+ statements.add(this.insertSelectiveStatement());
+ statements.add(this.updateStatement());
+ statements.add(this.updateByIdStatement());
+ statements.add(this.updateSelectiveStatement());
+ statements.add(this.updateSelectiveByIdStatement());
+ statements.add(this.deleteByIdStatement());
+ statements.add(this.deleteByIdsStatement());
+ statements.add(this.deleteAllStatement());
+ statements.add(this.getByIdStatement());
+ statements.add(this.findStatement());
+ statements.add(this.findByPageStatement());
+ statements.add(this.countAllStatement());
+ statements.add(this.countStatement());
+ statements.add(this.queryByExampleStatement());
+ statements.add(this.queryByExampleForPageStatement());
+ statements.add(this.countByExampleStatement());
+
+ this.resultMapOneToManySelectStatement();
+ this.resultMapManyToManySelectStatement();
+ this.associativeTableStatement();
+
+ // Basic
+ // statements.add(this.basicColumnListFragment());
+ // statements.add(this.basicResultMap());
+
+ return statements.stream().filter(StringUtils::hasText).collect(Collectors.toList());
+ }
+
+ private void resultMapOneToManySelectStatement() {
+ if (CollectionUtils.isEmpty(this.domain.getOneToManyAssociations())) {
+ return;
+ }
+ this.domain.getOneToManyAssociations().forEach(ass -> {
+ String statementName = "__association_" + this.domain.getTable() + '_'
+ + ((OneToManyAssociation) ass).getProperty().getName();
+ if (this.checkStatement(ass.getMappingEntity().getName(), statementName)) {
+ return;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, statementName);
+ scopes.put(SCOPE_RESULT_MAP, ResidentStatementName.RESULT_MAP);
+ scopes.put("ass", ass);
+ String ns = ass.getMappingEntity().getName();
+ this.compileMapper("select/" + ns.replace('.', '/') + "/" + statementName, ns,
+ Collections.singletonList(this.render("ResultMapOneToManySelect", scopes)));
+ });
+ }
+
+ private void resultMapManyToManySelectStatement() {
+ if (CollectionUtils.isEmpty(this.domain.getManyToManyAssociations())) {
+ return;
+ }
+ this.domain.getManyToManyAssociations().forEach(ass -> {
+ String statementName = "__association_" + this.domain.getTable() + '_'
+ + ((ManyToManyAssociation) ass).getProperty().getName();
+ String ns = ass.getMappingEntity().getName();
+ if (this.checkStatement(ns, statementName)) {
+ return;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, statementName);
+ scopes.put(SCOPE_RESULT_MAP, ResidentStatementName.RESULT_MAP);
+ scopes.put("ass", ass);
+ this.compileMapper("select/" + ns.replace('.', '/') + "/" + statementName, ns,
+ Collections.singletonList(this.render("ResultMapManyToManySelect", scopes)));
+ });
+ }
+
+ private void associativeTableStatement() {
+ if (CollectionUtils.isEmpty(this.domain.getManyToManyAssociations())) {
+ return;
+ }
+ this.domain.getManyToManyAssociations().forEach(ass -> {
+ String namespace = "associative." + ((ManyToManyAssociation) ass).getJoinTable().getTable().toString();
+ if (this.checkStatement(namespace, ResidentStatementName.INSERT)) {
+ return;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put("ass", ass);
+
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.INSERT);
+ this.compileMapper("associative/" + namespace.replace('.', '/') + "/insert", namespace,
+ Collections.singletonList(this.render("AssociativeInsert", scopes)));
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.UPDATE);
+ this.compileMapper("associative/" + namespace.replace('.', '/') + "/update", namespace,
+ Collections.singletonList(this.render("AssociativeUpdate", scopes)));
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.DELETE);
+ this.compileMapper("associative/" + namespace.replace('.', '/') + "/delete", namespace,
+ Collections.singletonList(this.render("AssociativeDelete", scopes)));
+ });
+
+ }
+
+ private String basicColumnListFragment() {
+ if (this.checkSqlFragment(ResidentStatementName.BASIC_COLUMN_LIST)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.BASIC_COLUMN_LIST);
+ return this.render("BasicColumnList", scopes);
+ }
+
+ private String allColumnListFragment() {
+ if (this.checkSqlFragment(ResidentStatementName.ALL_COLUMN_LIST)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.ALL_COLUMN_LIST);
+ return this.render("AllColumnList", scopes);
+ }
+
+ private String columnListFragment() {
+ if (this.checkSqlFragment(ResidentStatementName.COLUMN_LIST)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.COLUMN_LIST);
+ return this.render("ColumnList", scopes);
+ }
+
+ private String fromFragment() {
+ if (this.checkSqlFragment(ResidentStatementName.FROM)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.FROM);
+ return this.render("From", scopes);
+ }
+
+ private String selectFragment() {
+ if (this.checkSqlFragment(ResidentStatementName.SELECT)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.SELECT);
+ return this.render("Select", scopes);
+ }
+
+ private String whereClauseByIdFragment() {
+ if (this.checkSqlFragment(ResidentStatementName.WHERE_BY_ID_CLAUSE)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.WHERE_BY_ID_CLAUSE);
+ return this.render("WhereClauseById", scopes);
+ }
+
+ private String whereClauseByIdsFragment() {
+ if (this.checkSqlFragment(ResidentStatementName.WHERE_BY_IDS_CLAUSE)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.WHERE_BY_IDS_CLAUSE);
+ return this.render("WhereClauseByIds", scopes);
+ }
+
+ private String standardSortFragment() {
+ if (this.checkSqlFragment(ResidentStatementName.STANDARD_SORT)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.STANDARD_SORT);
+ return this.render("StandardSort", scopes);
+ }
+
+ private String queryByExampleWhereClauseFragment() {
+ if (this.checkSqlFragment(ResidentStatementName.QUERY_BY_EXAMPLE_WHERE_CLAUSE)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.QUERY_BY_EXAMPLE_WHERE_CLAUSE);
+ scopes.put("replaceDotToUnderline", (Lambda) (frag, out) -> out.write(frag.execute().trim().replace('.', '_')));
+
+ List columns = new LinkedList<>();
+ if (null != this.domain.getPrimaryKey()) {
+ columns.addAll(this.domain.getPrimaryKey().getColumns());
+ }
+ if (!CollectionUtils.isEmpty(this.domain.getNormalColumns())) {
+ columns.addAll(this.domain.getNormalColumns());
+ }
+ if (!CollectionUtils.isEmpty(this.domain.getVersionColumns())) {
+ columns.addAll(this.domain.getVersionColumns());
+ }
+ if (!CollectionUtils.isEmpty(this.domain.getEmbeddings())) {
+ this.domain.getEmbeddings().stream().forEach(embedding -> {
+ if (null != embedding.getPrimaryKey()) {
+ columns.addAll(embedding.getPrimaryKey().getColumns());
+ }
+ if (!CollectionUtils.isEmpty(embedding.getNormalColumns())) {
+ columns.addAll(embedding.getNormalColumns());
+ }
+ if (!CollectionUtils.isEmpty(embedding.getVersionColumns())) {
+ columns.addAll(embedding.getVersionColumns());
+ }
+ });
+ }
+ if (!CollectionUtils.isEmpty(this.domain.getManyToOneAssociations())) {
+ this.domain.getManyToOneAssociations().stream().forEach(association -> {
+ ManyToOneAssociation ass = (ManyToOneAssociation) association;
+ if (!ass.isLeftJoin()) {
+ return;
+ }
+
+ if (null != ass.getPrimaryKey()) {
+ columns.addAll(ass.getPrimaryKey().getColumns());
+ }
+ if (!CollectionUtils.isEmpty(ass.getNormalColumns())) {
+ columns.addAll(ass.getNormalColumns());
+ }
+ if (!CollectionUtils.isEmpty(ass.getVersionColumns())) {
+ columns.addAll(ass.getVersionColumns());
+ }
+
+ });
+ }
+
+ scopes.put("combinedColumns", columns);
+
+ return this.render("QueryByExampleWhereClause", scopes);
+ }
+
+ private String basicResultMap() {
+ if (this.checkResultMap(ResidentStatementName.BASIC_RESULT_MAP)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.BASIC_RESULT_MAP);
+ return this.render("BasicResultMap", scopes);
+ }
+
+ private String resultMap() {
+ if (this.checkResultMap(ResidentStatementName.RESULT_MAP)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.RESULT_MAP);
+ return this.render("ResultMap", scopes);
+ }
+
+ private String insertStatement() {
+ if (this.checkStatement(ResidentStatementName.INSERT)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.INSERT);
+ return this.render("Insert", scopes);
+ }
+
+ private String insertSelectiveStatement() {
+ if (this.checkStatement(ResidentStatementName.INSERT_SELECTIVE)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.INSERT_SELECTIVE);
+ return this.render("InsertSelective", scopes);
+ }
+
+ private String updateStatement() {
+ if (this.checkStatement(ResidentStatementName.UPDATE)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.UPDATE);
+ scopes.put("byId", false);
+ return this.render("Update", scopes);
+ }
+
+ private String updateByIdStatement() {
+ if (this.checkStatement(ResidentStatementName.UPDATE_BY_ID)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.UPDATE_BY_ID);
+ scopes.put("byId", true);
+ return this.render("Update", scopes);
+ }
+
+ private String updateSelectiveStatement() {
+ if (this.checkStatement(ResidentStatementName.UPDATE_SELECTIVE)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.UPDATE_SELECTIVE);
+ scopes.put("byId", false);
+ return this.render("UpdateSelective", scopes);
+ }
+
+ private String updateSelectiveByIdStatement() {
+ if (this.checkStatement(ResidentStatementName.UPDATE_SELECTIVE_BY_ID)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.UPDATE_SELECTIVE_BY_ID);
+ scopes.put("byId", true);
+ return this.render("UpdateSelective", scopes);
+ }
+
+ private String deleteByIdStatement() {
+ if (this.checkStatement(ResidentStatementName.DELETE_BY_ID)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.DELETE_BY_ID);
+ return this.render("DeleteById", scopes);
+ }
+
+ private String deleteByIdsStatement() {
+ if (this.checkStatement(ResidentStatementName.DELETE_BY_IDS)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.DELETE_BY_IDS);
+ return this.render("DeleteByIds", scopes);
+ }
+
+ private String deleteAllStatement() {
+ if (this.checkStatement(ResidentStatementName.DELETE_ALL)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.DELETE_ALL);
+ // FIXME: change to use truncate?
+ return this.render("DeleteAll", scopes);
+ }
+
+ private String getByIdStatement() {
+ if (this.checkStatement(ResidentStatementName.GET_BY_ID)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.GET_BY_ID);
+ scopes.put(SCOPE_RESULT_MAP, ResidentStatementName.RESULT_MAP);
+ return this.render("GetById", scopes);
+ }
+
+ private String findStatement() {
+ if (this.checkStatement(ResidentStatementName.FIND)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.FIND);
+ scopes.put(SCOPE_RESULT_MAP, ResidentStatementName.RESULT_MAP);
+ scopes.put("conditionQuery", ""); // TODO
+ return this.render("Find", scopes);
+ }
+
+ private String findByPageStatement() {
+ if (this.checkStatement(ResidentStatementName.FIND_BY_PAGER)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.FIND_BY_PAGER);
+ scopes.put(SCOPE_RESULT_MAP, ResidentStatementName.RESULT_MAP);
+ scopes.put("limitHandler", (Lambda) (frag, out) -> out.write(
+ this.mappingContext.getDialect().getLimitHandler().processSql(frag.execute(), new RowSelection(true))));
+ scopes.put("conditionQuery", ""); // TODO
+ return this.render("FindByPage", scopes);
+ }
+
+ private String countAllStatement() {
+ if (this.checkStatement(ResidentStatementName.COUNT_ALL)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.COUNT_ALL);
+ return this.render("CountAll", scopes);
+ }
+
+ private String countStatement() {
+ if (this.checkStatement(ResidentStatementName.COUNT)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.COUNT);
+ return this.render("Count", scopes);
+ }
+
+ private String queryByExampleStatement() {
+ if (this.checkStatement(ResidentStatementName.QUERY_BY_EXAMPLE)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.QUERY_BY_EXAMPLE);
+ scopes.put(SCOPE_RESULT_MAP, ResidentStatementName.RESULT_MAP);
+ return this.render("QueryByExample", scopes);
+ }
+
+ private String queryByExampleForPageStatement() {
+ if (this.checkStatement(ResidentStatementName.QUERY_BY_EXAMPLE_FOR_PAGE)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.QUERY_BY_EXAMPLE_FOR_PAGE);
+ scopes.put(SCOPE_RESULT_MAP, ResidentStatementName.RESULT_MAP);
+ scopes.put("limitHandler", (Lambda) (frag, out) -> out.write(
+ this.mappingContext.getDialect().getLimitHandler().processSql(frag.execute(), new RowSelection(true))));
+ return this.render("QueryByExampleForPage", scopes);
+ }
+
+ private String countByExampleStatement() {
+ if (this.checkStatement(ResidentStatementName.COUNT_QUERY_BY_EXAMPLE)) {
+ return null;
+ }
+ Map scopes = new HashMap<>();
+ scopes.put(SCOPE_STATEMENT_NAME, ResidentStatementName.COUNT_QUERY_BY_EXAMPLE);
+ return this.render("CountQueryByExample", scopes);
+ }
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisQueryPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/SimpleMybatisQueryPrecompiler.java
similarity index 49%
rename from spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisQueryPrecompiler.java
rename to spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/SimpleMybatisQueryPrecompiler.java
index 1442e5f6b613358db1b30b5dd60023f53a604151..88ac73812b4d04c58b72346c99764a7f21f78fb7 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisQueryPrecompiler.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/precompiler/SimpleMybatisQueryPrecompiler.java
@@ -13,22 +13,36 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.data.mybatis.repository.query;
+package org.springframework.data.mybatis.precompiler;
import java.lang.reflect.Constructor;
import java.lang.reflect.Parameter;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import org.apache.ibatis.session.Configuration;
+import com.samskivert.mustache.Mustache.Lambda;
+import lombok.AllArgsConstructor;
+import lombok.Data;
import org.springframework.data.mapping.MappingException;
-import org.springframework.data.mybatis.dialect.Dialect;
import org.springframework.data.mybatis.dialect.pagination.RowSelection;
import org.springframework.data.mybatis.mapping.MybatisMappingContext;
+import org.springframework.data.mybatis.repository.query.DeclaredQuery;
+import org.springframework.data.mybatis.repository.query.MybatisParameters;
+import org.springframework.data.mybatis.repository.query.MybatisParameters.MybatisParameter;
+import org.springframework.data.mybatis.repository.query.MybatisQueryMethod;
+import org.springframework.data.mybatis.repository.query.QueryUtils;
+import org.springframework.data.mybatis.repository.query.SimpleMybatisQuery;
+import org.springframework.data.mybatis.repository.query.StringQuery;
+import org.springframework.data.mybatis.repository.query.StringQuery.ParameterBinding;
import org.springframework.data.mybatis.repository.support.ResidentParameterName;
import org.springframework.data.mybatis.repository.support.ResidentStatementName;
import org.springframework.util.ClassUtils;
@@ -36,13 +50,11 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
- * Precompiler for {@link SimpleMybatisQuery}.
+ * .
*
* @author JARVIS SONG
*/
-class SimpleMybatisQueryPrecompiler extends MybatisQueryMethodPrecompiler {
-
- private final SimpleMybatisQuery query;
+class SimpleMybatisQueryPrecompiler extends AbstractMybatisPrecompiler {
private static Pattern patternIndex = Pattern.compile("[(\\d+)]");
@@ -50,38 +62,156 @@ class SimpleMybatisQueryPrecompiler extends MybatisQueryMethodPrecompiler {
private static Pattern patternString = Pattern.compile("'.+'");
- SimpleMybatisQueryPrecompiler(MybatisMappingContext mappingContext, Configuration configuration, Dialect dialect,
- SimpleMybatisQuery query) {
+ private static final Pattern SELECT_ALL_FROM = Pattern.compile("^\\s*select\\s+\\*\\s+from\\s+.*",
+ Pattern.CASE_INSENSITIVE);
- super(mappingContext, configuration, dialect, query);
+ private final SimpleMybatisQuery query;
+ SimpleMybatisQueryPrecompiler(MybatisMappingContext mappingContext, SimpleMybatisQuery query) {
+ super(mappingContext,
+ mappingContext.getRequiredModel(query.getQueryMethod().getEntityInformation().getJavaType()));
this.query = query;
}
@Override
- protected String mainQueryString() {
- return this.queryString(this.query.getQuery());
+ protected Collection prepareStatements() {
+
+ String statement = this.doPrepareStatement();
+ return StringUtils.isEmpty(statement) ? Collections.emptyList() : Collections.singletonList(statement);
}
- private String queryString(DeclaredQuery query) {
+ private String doPrepareStatement() {
+ if (this.checkStatement(this.query.getStatementName())) {
+ return null;
+ }
- String sql = query.getQueryString();
+ switch (this.query.getSqlCommandType()) {
+
+ case INSERT:
+ return this.insertStatement();
+ case UPDATE:
+ return this.updateStatement();
+ case DELETE:
+ return this.deleteStatement();
+ case SELECT:
+ return this.selectStatement();
+ default:
+ throw new MappingException("Unsupported SQL Command Type: " + this.query.getSqlCommandType().name());
+ }
+ }
+
+ private String selectStatement() {
+ MybatisQueryMethod method = this.query.getQueryMethod();
+
+ Map scopes = new HashMap<>();
+ String sql = this.queryString(this.query.getQuery());
+
+ if (QueryUtils.hasConstructorExpression(sql)) {
+ String constructorExpression = QueryUtils.getConstructorExpression(sql);
+ String className = constructorExpression.substring(3, constructorExpression.lastIndexOf('(')).trim();
+ Class> clz;
+ try {
+ clz = ClassUtils.forName(className, this.getClass().getClassLoader());
+ }
+ catch (ClassNotFoundException ex) {
+ throw new MappingException(
+ "Could not find class " + className + " from constructor expression: " + sql);
+ }
+ String columns = constructorExpression.substring(constructorExpression.lastIndexOf('(') + 1,
+ constructorExpression.length() - 1);
+ String[] columnList = columns.split(",");
+ sql = sql.replace(constructorExpression, Arrays.stream(columnList).map(
+ c -> String.format("%s AS %s", c.trim(), this.mappingContext.getDialect().quoteCertainly(c.trim())))
+ .collect(Collectors.joining(",")));
+ sql = QueryUtils.quoteFieldAliases(sql, this.mappingContext.getDialect());
+
+ Constructor> constructor = Arrays.stream(clz.getDeclaredConstructors())
+ .filter(c -> c.getParameterCount() == columnList.length).findFirst().orElseThrow(
+ () -> new MappingException("Could not find constructor for: " + constructorExpression));
- sql = QueryUtils.quoteFieldAliases(sql, this.dialect);
+ List constructorParameters = new LinkedList<>();
+
+ for (int i = 0; i < constructor.getParameterCount(); i++) {
+ Parameter parameter = constructor.getParameters()[i];
+ constructorParameters.add(new ConstructorParameter(columnList[i], parameter.getType().getName()));
+ }
+ scopes.put("constructorParameters", constructorParameters);
+ scopes.put("hasConstructor", true);
+ scopes.put("isResultMap", true);
+ scopes.put("result", ResidentStatementName.RESULT_MAP_PREFIX + this.query.getStatementName());
+ scopes.put("resultMapType", className);
+ }
+
+ MybatisParameters parameters = method.getParameters();
+ if (parameters.hasSortParameter()) {
+ scopes.put("hasSort", true);
+ }
+
+ if (method.isPageQuery()) {
+ scopes.put("isPageQuery", true);
+ scopes.put("countStatementName", this.query.getCountStatementName());
+ scopes.put("countQuery", this.queryString(this.query.getCountQuery()));
+ }
+
+ if (method.isPageQuery() || parameters.hasPageableParameter() || method.isSliceQuery()) {
+ scopes.put("pageable", true);
+ scopes.put("isUnpagedQuery", true);
+ scopes.put("unpagedStatementName", ResidentStatementName.UNPAGED_PREFIX + this.query.getStatementName());
+ scopes.put("unpagedQuery", sql);
+
+ RowSelection rowSelection = new RowSelection(true);
+ scopes.put("limitHandler", (Lambda) (frag, out) -> out.write(
+ this.mappingContext.getDialect().getLimitHandler().processSql(frag.execute(), rowSelection)));
+
+ }
+
+ if (null != method.getResultMap() || SELECT_ALL_FROM.matcher(sql.toLowerCase()).matches()) {
+ scopes.putIfAbsent("isResultMap", true);
+ if (null != method.getResultMap()) {
+ scopes.putIfAbsent("result", method.getResultMap());
+ }
+ else {
+ scopes.putIfAbsent("result", ResidentStatementName.RESULT_MAP);
+ }
+ }
+ else {
+ scopes.putIfAbsent("isResultMap", false);
+ scopes.putIfAbsent("result", method.getActualResultType());
+ }
+
+ scopes.put("query", sql);
+ return this.render("SimpleQuerySelect", scopes);
+ }
+
+ private String deleteStatement() {
+ return this.render("SimpleQueryDelete", null);
+ }
- List parameterBindings = query.getParameterBindings();
+ private String updateStatement() {
+ return this.render("SimpleQueryUpdate", null);
+ }
+
+ private String insertStatement() {
+ return this.render("SimpleQueryInsert", null);
+ }
+
+ private String queryString(DeclaredQuery query) {
+ String sql = query.getQueryString();
+ sql = QueryUtils.quoteFieldAliases(sql, this.mappingContext.getDialect());
+
+ List parameterBindings = query.getParameterBindings();
if (CollectionUtils.isEmpty(parameterBindings)) {
return sql;
}
- for (StringQuery.ParameterBinding parameterBinding : parameterBindings) {
- String replace = null;
+
+ for (ParameterBinding parameterBinding : parameterBindings) {
+ String replace;
String bindName = null;
String typeHandler = "";
if (StringUtils.hasText(parameterBinding.getName())) {
replace = ":" + parameterBinding.getRequiredName();
bindName = parameterBinding.getName();
-
}
else {
replace = "?" + parameterBinding.getPosition();
@@ -103,12 +233,12 @@ class SimpleMybatisQueryPrecompiler extends MybatisQueryMethodPrecompiler {
}
}
else {
- MybatisParameters.MybatisParameter mp = this.query.getQueryMethod().getParameters()
+ MybatisParameter mp = this.query.getQueryMethod().getParameters()
.getBindableParameter(parameterBinding.getRequiredPosition() - 1);
bindName = mp.getName()
.orElse(ResidentParameterName.POSITION_PREFIX + parameterBinding.getPosition());
- }
+ }
}
if (StringUtils.hasText(typeHandler)) {
@@ -150,7 +280,7 @@ class SimpleMybatisQueryPrecompiler extends MybatisQueryMethodPrecompiler {
break;
}
- sql = sql.replace(replace, String.format(" #{__bind_%s}",
+ sql = sql.replace(replace, String.format("#{__bind_%s}",
bindName, like, bindName));
continue;
@@ -158,92 +288,34 @@ class SimpleMybatisQueryPrecompiler extends MybatisQueryMethodPrecompiler {
}
sql = sql.replace(replace, String.format("#{%s%s}", bindName, typeHandler));
+
}
return sql;
-
}
@Override
- protected String select() {
-
- MybatisQueryMethod method = this.query.getQueryMethod();
- String sql = this.mainQueryString();
- String unpaged = "";
- String sort = "";
- String count = "";
- String resultMap = null;
- String result = "";
-
- if (QueryUtils.hasConstructorExpression(sql)) {
- String constructorExpression = QueryUtils.getConstructorExpression(sql);
-
- String className = constructorExpression.substring(3, constructorExpression.lastIndexOf("(")).trim();
- Class> clz;
- try {
- clz = ClassUtils.forName(className, this.getClass().getClassLoader());
-
- }
- catch (ClassNotFoundException ex) {
- throw new MappingException(
- "Could not find class: " + className + " from constructor expression: " + sql);
- }
- String columns = constructorExpression.substring(constructorExpression.lastIndexOf("(") + 1,
- constructorExpression.length() - 1);
- String[] columnList = columns.split(",");
-
- sql = sql.replace(constructorExpression,
- Stream.of(columnList)
- .map(c -> String.format("%s as %s", c.trim(), dialect.quoteCertainly(c.trim())))
- .collect(Collectors.joining(",")));
- sql = QueryUtils.quoteFieldAliases(sql, this.dialect);
- StringBuilder results = new StringBuilder();
- results.append("");
- Constructor> constructor = Stream.of(clz.getDeclaredConstructors())
- .filter(c -> c.getParameterCount() == columnList.length).findFirst().orElseThrow(
- () -> new MappingException("Could not find constructor for: " + constructorExpression));
-
- for (int i = 0; i < constructor.getParameterCount(); i++) {
- Parameter parameter = constructor.getParameters()[i];
- results.append(String.format("", columnList[i].trim(),
- parameter.getType().getName()));
- }
-
- results.append("");
- resultMap = ResidentStatementName.RESULT_MAP_PREFIX + this.query.getStatementName();
-
- result = String.format("%s", resultMap, className,
- results.toString());
-
- resultMap = String.format(" resultMap=\"%s\"", resultMap);
- }
-
- MybatisParameters parameters = method.getParameters();
- if (parameters.hasSortParameter()) {
- sort = this.buildStandardOrderBySegment();
- }
-
- if (method.isPageQuery()) {
- count = String.format("",
- this.query.getCountStatementName(), this.queryString(this.query.getCountQuery()));
+ protected String render(String name, Map scopes) {
+ if (null == scopes) {
+ scopes = new HashMap<>();
}
+ scopes.putIfAbsent(SCOPE_STATEMENT_NAME, this.query.getStatementName());
+ scopes.putIfAbsent("query", this.queryString(this.query.getQuery()));
+ return super.render(name, scopes);
+ }
- if (method.isPageQuery() || parameters.hasPageableParameter() || method.isSliceQuery()) {
- unpaged = String.format("",
- ResidentStatementName.UNPAGED_PREFIX + this.query.getStatementName(),
- (null != resultMap) ? resultMap : this.resultMapOrType(sql), sql + sort);
- sql = this.dialect.getLimitHandler().processSql(sql + sort, new RowSelection(true));
- }
+ @Override
+ protected String getResource(String dir, String namespace) {
+ return "simple/" + this.query.getStatementId().replace('.', '/');
+ }
- String select = String.format("", this.query.getStatementName(),
- (null != resultMap) ? resultMap : this.resultMapOrType(sql), sql);
+ @Data
+ @AllArgsConstructor
+ public static class ConstructorParameter {
- return result + select + unpaged + count;
+ private String column;
- }
+ private String javaType;
- @Override
- protected String getResourceSuffix() {
- return "_simple_" + this.query.getQueryMethod().getStatementName() + super.getResourceSuffix();
}
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/AuditingBeanDefinitionParser.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/AuditingBeanDefinitionParser.java
index 3419c143673fed786f5070006eb415bd6691be05..4352b6fb8e7ac5c15027195ac721c5abc7ef89ee 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/AuditingBeanDefinitionParser.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/AuditingBeanDefinitionParser.java
@@ -21,7 +21,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.data.auditing.config.AuditingHandlerBeanDefinitionParser;
import org.springframework.data.mapping.context.MappingContext;
-import org.springframework.data.mybatis.domain.support.MybatisAuditingHandler;
+import org.springframework.data.mybatis.auditing.MybatisAuditingHandler;
import org.springframework.util.StringUtils;
/**
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisAuditingRegistrar.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisAuditingRegistrar.java
index 25ac77bcf9975a79512605cd4fcec263fb3f4235..c7933dd58311cd0f01534761ab4e57f7c3e04c83 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisAuditingRegistrar.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisAuditingRegistrar.java
@@ -25,7 +25,8 @@ import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport;
import org.springframework.data.auditing.config.AuditingConfiguration;
-import org.springframework.data.mybatis.domain.support.MybatisAuditingHandler;
+import org.springframework.data.mybatis.auditing.MybatisAuditingHandler;
+import org.springframework.data.mybatis.mapping.MybatisMappingContext;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -42,6 +43,20 @@ class MybatisAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
return EnableMybatisAuditing.class;
}
+ @Override
+ protected String getAuditingHandlerBeanName() {
+ return "mybatisAuditingHandler";
+ }
+
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
+
+ Assert.notNull(annotationMetadata, "AnnotationMetadata must not be null!");
+ Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
+
+ super.registerBeanDefinitions(annotationMetadata, registry);
+ }
+
@Override
protected MybatisAuditingConfiguration getConfiguration(AnnotationMetadata annotationMetadata) {
return new MybatisAnnotationAuditingConfiguration(annotationMetadata, this.getAnnotation());
@@ -50,17 +65,13 @@ class MybatisAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
@Override
protected void registerAuditListenerBeanDefinition(BeanDefinition auditingHandlerDefinition,
BeanDefinitionRegistry registry) {
+
if (!registry.containsBeanDefinition(BeanDefinitionNames.MYBATIS_MAPPING_CONTEXT_BEAN_NAME)) {
registry.registerBeanDefinition(BeanDefinitionNames.MYBATIS_MAPPING_CONTEXT_BEAN_NAME, //
- new RootBeanDefinition(MybatisMappingContextFactoryBean.class));
+ new RootBeanDefinition(MybatisMappingContext.class));
}
}
- @Override
- protected String getAuditingHandlerBeanName() {
- return "mybatisAuditingHandler";
- }
-
@Override
protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) {
Assert.notNull(configuration, "AuditingConfiguration must not be null!");
@@ -73,6 +84,7 @@ class MybatisAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
@Override
protected BeanDefinitionBuilder configureDefaultAuditHandlerAttributes(AuditingConfiguration configuration,
BeanDefinitionBuilder builder) {
+
BeanDefinitionBuilder beanDefinitionBuilder = super.configureDefaultAuditHandlerAttributes(configuration,
builder);
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisMappingContextFactoryBean.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisMappingContextFactoryBean.java
deleted file mode 100644
index 4d67d923c923279be09be140ddc98186766940ba..0000000000000000000000000000000000000000
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisMappingContextFactoryBean.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2012-2019 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.data.mybatis.repository.config;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import lombok.extern.slf4j.Slf4j;
-import org.apache.ibatis.session.Configuration;
-import org.mybatis.spring.SqlSessionTemplate;
-
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.FactoryBean;
-import org.springframework.beans.factory.ListableBeanFactory;
-import org.springframework.beans.factory.config.AbstractFactoryBean;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.data.mapping.model.SnakeCaseFieldNamingStrategy;
-import org.springframework.data.mybatis.mapping.MybatisMappingContext;
-import org.springframework.lang.Nullable;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
-
-/**
- * {@link FactoryBean} to setup {@link MybatisMappingContext} instances from Spring
- * configuration.
- *
- * @author JARVIS SONG
- */
-@Slf4j
-class MybatisMappingContextFactoryBean extends AbstractFactoryBean
- implements ApplicationContextAware {
-
- private final Map, Class>> mapping;
-
- private @Nullable ListableBeanFactory beanFactory;
-
- private Configuration configuration;
-
- MybatisMappingContextFactoryBean(Map, Class>> mapping, SqlSessionTemplate sqlSessionTemplate) {
- this.mapping = mapping;
- this.configuration = sqlSessionTemplate.getConfiguration();
- }
-
- @Override
- public Class> getObjectType() {
- return MybatisMappingContext.class;
- }
-
- @Override
- protected MybatisMappingContext createInstance() throws Exception {
- if (log.isDebugEnabled()) {
- log.debug("Initializing MybatisMappingContext...");
- }
- Set extends Class>> initialEntitySet;
- if (null == this.mapping) {
- initialEntitySet = new HashSet<>();
- }
- else {
- initialEntitySet = new HashSet<>(this.mapping.values());
- }
-
- MultiValueMap, Class>> entityRepositoryMapping = new LinkedMultiValueMap<>();
- for (Map.Entry, Class>> entry : this.mapping.entrySet()) {
- Class> repository = entry.getKey();
- Class> entity = entry.getValue();
- entityRepositoryMapping.add(entity, repository);
- }
-
- MybatisMappingContext context = new MybatisMappingContext();
- if (this.configuration.isMapUnderscoreToCamelCase()) {
- context.setFieldNamingStrategy(new SnakeCaseFieldNamingStrategy());
- }
-
- context.setInitialEntitySet(initialEntitySet);
- context.setEntityRepositoryMapping(entityRepositoryMapping);
- context.initialize();
- if (log.isDebugEnabled()) {
- log.debug("Finished initializing MybatisMappingContext!");
- }
-
- return context;
- }
-
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- this.beanFactory = applicationContext;
- }
-
-}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisMappingContextParser.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisMappingContextParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1bb7c50df4665511779a40a29c0773ad5a5b725
--- /dev/null
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisMappingContextParser.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mybatis.repository.config;
+
+import java.util.Set;
+
+import org.w3c.dom.Element;
+
+import org.springframework.beans.factory.BeanDefinitionStoreException;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.data.mybatis.mapping.MybatisEntityClassScanner;
+import org.springframework.data.mybatis.mapping.MybatisMappingContext;
+import org.springframework.util.StringUtils;
+
+/**
+ * Spring Data Mybatis XML namespace parser for the {@code mybatis:mapping} element.
+ *
+ * @author JARVIS SONG
+ */
+class MybatisMappingContextParser extends AbstractSingleBeanDefinitionParser {
+
+ @Override
+ protected Class> getBeanClass(Element element) {
+ return MybatisMappingContext.class;
+ }
+
+ @Override
+ protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
+ throws BeanDefinitionStoreException {
+ String id = super.resolveId(element, definition, parserContext);
+
+ return StringUtils.hasText(id) ? id : BeanDefinitionNames.MYBATIS_MAPPING_CONTEXT_BEAN_NAME;
+ }
+
+ @Override
+ protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+ String packages = element.getAttribute("entity-base-packages");
+ if (StringUtils.hasText(packages)) {
+ try {
+ Set> entityClasses = MybatisEntityClassScanner
+ .scan(StringUtils.commaDelimitedListToStringArray(packages));
+
+ builder.addPropertyValue("initialEntitySet", entityClasses);
+ }
+ catch (Exception ex) {
+ throw new IllegalArgumentException(String.format(
+ "encountered exception while scanning for entity classes in package(s) [%s]", packages), ex);
+ }
+ }
+
+ String sqlSessionTemplateRef = element.getAttribute("sql-session-template-ref");
+ if (StringUtils.hasText(sqlSessionTemplateRef)) {
+ builder.addConstructorArgReference(sqlSessionTemplateRef);
+ }
+
+ String fieldNamingStrategyRef = element.getAttribute("field-naming-strategy-ref");
+ if (StringUtils.hasText(fieldNamingStrategyRef)) {
+ builder.addPropertyReference("fieldNamingStrategy", fieldNamingStrategyRef);
+ }
+
+ }
+
+}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoriesRegistrar.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoriesRegistrar.java
index bc3fcb1819899b7d8c863315a3a905dc5dbd3df3..8c0809a7f28fd07368b733442406b305c891f8fb 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoriesRegistrar.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoriesRegistrar.java
@@ -17,20 +17,9 @@ package org.springframework.data.mybatis.repository.config;
import java.lang.annotation.Annotation;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-import org.springframework.beans.factory.support.BeanNameGenerator;
-import org.springframework.context.EnvironmentAware;
-import org.springframework.context.ResourceLoaderAware;
-import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
-import org.springframework.core.env.Environment;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.core.type.AnnotationMetadata;
-import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
-import org.springframework.data.repository.config.RepositoryConfigurationDelegate;
+import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
-import org.springframework.data.repository.config.RepositoryConfigurationUtils;
-import org.springframework.util.Assert;
/**
* {@link ImportBeanDefinitionRegistrar} to enable {@link EnableMybatisRepositories}
@@ -38,61 +27,16 @@ import org.springframework.util.Assert;
*
* @author JARVIS SONG
*/
-class MybatisRepositoriesRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
-
- private Environment environment;
-
- private ResourceLoader resourceLoader;
-
- @Override
- public void setEnvironment(Environment environment) {
-
- this.environment = environment;
- }
-
- @Override
- public void setResourceLoader(ResourceLoader resourceLoader) {
-
- this.resourceLoader = resourceLoader;
- }
+class MybatisRepositoriesRegistrar extends RepositoryBeanDefinitionRegistrarSupport {
@Override
- public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry,
- BeanNameGenerator generator) {
-
- Assert.notNull(metadata, "AnnotationMetadata must not be null!");
- Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
- Assert.notNull(this.resourceLoader, "ResourceLoader must not be null!");
-
- // Guard against calls for sub-classes
- if (metadata.getAnnotationAttributes(this.getAnnotation().getName()) == null) {
- return;
- }
-
- AnnotationRepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource(
- metadata, this.getAnnotation(), this.resourceLoader, this.environment, registry, generator);
-
- RepositoryConfigurationExtension extension = this.getExtension();
- RepositoryConfigurationUtils.exposeRegistration(extension, registry, configurationSource);
-
- RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configurationSource,
- this.resourceLoader, this.environment);
-
- delegate.registerRepositoriesIn(registry, extension);
- }
-
- private RepositoryConfigurationExtension getExtension() {
- return new MybatisRepositoryConfigExtension(this.resourceLoader);
- }
-
- private Class extends Annotation> getAnnotation() {
+ protected Class extends Annotation> getAnnotation() {
return EnableMybatisRepositories.class;
}
@Override
- public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
- this.registerBeanDefinitions(annotationMetadata, registry,
- ConfigurationClassPostProcessor.IMPORT_BEAN_NAME_GENERATOR);
+ protected RepositoryConfigurationExtension getExtension() {
+ return new MybatisRepositoryConfigExtension();
}
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryConfigExtension.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryConfigExtension.java
index f40cc6416890ff03d94767998a44e4646bb10aa6..3dee9c98f3ec636f822a2f9c181318b9ea336418 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryConfigExtension.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryConfigExtension.java
@@ -20,9 +20,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
-import java.util.Map;
import java.util.Optional;
-import java.util.stream.Collectors;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
@@ -31,22 +29,14 @@ import javax.persistence.MappedSuperclass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.annotation.AnnotationAttributes;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.data.mapping.MappingException;
-import org.springframework.data.mybatis.dialect.DialectFactoryBean;
import org.springframework.data.mybatis.repository.MybatisRepository;
import org.springframework.data.mybatis.repository.support.MybatisRepositoryFactoryBean;
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
-import org.springframework.data.repository.config.RepositoryConfiguration;
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
import org.springframework.data.repository.config.RepositoryConfigurationSource;
import org.springframework.data.repository.config.XmlRepositoryConfigurationSource;
-import org.springframework.data.repository.core.support.AbstractRepositoryMetadata;
import org.springframework.data.repository.util.TxUtils;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;
/**
@@ -61,18 +51,10 @@ public class MybatisRepositoryConfigExtension extends RepositoryConfigurationExt
private static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = TxUtils.DEFAULT_TRANSACTION_MANAGER;
- private static final String DEFAULT_SQL_SESSION_TEMPLATE_BEAN_NAME = "sqlSessionTemplate";
-
private static final String ENABLE_DEFAULT_TRANSACTIONS_ATTRIBUTE = "enableDefaultTransactions";
private static final String ESCAPE_CHARACTER_PROPERTY = "escapeCharacter";
- private final ResourceLoader resourceLoader;
-
- public MybatisRepositoryConfigExtension(ResourceLoader resourceLoader) {
- this.resourceLoader = resourceLoader;
- }
-
@Override
public String getModuleName() {
return "MyBatis";
@@ -98,38 +80,14 @@ public class MybatisRepositoryConfigExtension extends RepositoryConfigurationExt
return Arrays.asList(Entity.class, MappedSuperclass.class, Embeddable.class);
}
- @Override
- public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource config) {
- super.registerBeansForRoot(registry, config);
-
- Object source = config.getSource();
- Optional sqlSessionTemplateRef = config.getAttribute("sqlSessionTemplateRef");
-
- registerIfNotAlreadyRegistered(() -> BeanDefinitionBuilder.rootBeanDefinition(DialectFactoryBean.class)
- .addConstructorArgReference(sqlSessionTemplateRef.orElse(DEFAULT_SQL_SESSION_TEMPLATE_BEAN_NAME))
- .getBeanDefinition(), registry, BeanDefinitionNames.DIALECT_BEAN_NAME, source);
-
- registerIfNotAlreadyRegistered(
- () -> BeanDefinitionBuilder.rootBeanDefinition(MybatisMappingContextFactoryBean.class)
- .addConstructorArgValue(this.scanDomains(config))
- .addConstructorArgReference(
- sqlSessionTemplateRef.orElse(DEFAULT_SQL_SESSION_TEMPLATE_BEAN_NAME))
- .getBeanDefinition(),
- registry, BeanDefinitionNames.MYBATIS_MAPPING_CONTEXT_BEAN_NAME, source);
- }
-
@Override
public void postProcess(BeanDefinitionBuilder builder, RepositoryConfigurationSource source) {
Optional transactionManagerRef = source.getAttribute("transactionManagerRef");
builder.addPropertyValue("transactionManager",
transactionManagerRef.orElse(DEFAULT_TRANSACTION_MANAGER_BEAN_NAME));
- Optional sqlSessionTemplateRef = source.getAttribute("sqlSessionTemplateRef");
- builder.addPropertyReference("sqlSessionTemplate",
- sqlSessionTemplateRef.orElse(DEFAULT_SQL_SESSION_TEMPLATE_BEAN_NAME));
builder.addPropertyValue(ESCAPE_CHARACTER_PROPERTY, getEscapeCharacter(source).orElse('\\'));
builder.addPropertyReference("mappingContext", BeanDefinitionNames.MYBATIS_MAPPING_CONTEXT_BEAN_NAME);
- builder.addPropertyReference("dialect", BeanDefinitionNames.DIALECT_BEAN_NAME);
}
@Override
@@ -147,55 +105,11 @@ public class MybatisRepositoryConfigExtension extends RepositoryConfigurationExt
}
}
- private Map extends Class>, ? extends Class>> scanDomains(RepositoryConfigurationSource source) {
- StopWatch watch = new StopWatch();
-
- if (log.isDebugEnabled()) {
- log.debug("Scanning domains for repositories in packages {}.",
- source.getBasePackages().stream().collect(Collectors.joining(", ")));
- }
- watch.start();
-
- Collection> repositoryConfigurations = getRepositoryConfigurations(
- source, this.resourceLoader, false);
-
- if (CollectionUtils.isEmpty(repositoryConfigurations)) {
- return Collections.emptyMap();
- }
-
- Map extends Class>, ? extends Class>> mapping = repositoryConfigurations.stream()
- .collect(Collectors.toMap(configuration -> {
- try {
- return Class.forName(configuration.getRepositoryInterface());
- }
- catch (ClassNotFoundException ex) {
- throw new MappingException(ex.getMessage(), ex);
- }
- }, configuration -> {
- try {
- Class> repositoryClass = Class.forName(configuration.getRepositoryInterface());
- return AbstractRepositoryMetadata.getMetadata(repositoryClass).getDomainType();
- }
- catch (ClassNotFoundException ex) {
- throw new MappingException(ex.getMessage(), ex);
- }
- }));
-
- watch.stop();
-
- if (log.isInfoEnabled()) {
- log.info("Finished Domains scanning in {}ms. Found {} domains.", //
- watch.getLastTaskTimeMillis(), mapping.size());
- }
-
- return mapping;
- }
-
private static Optional getEscapeCharacter(RepositoryConfigurationSource source) {
try {
return source.getAttribute(ESCAPE_CHARACTER_PROPERTY, Character.class);
}
- catch (IllegalArgumentException ___) {
+ catch (IllegalArgumentException ex) {
return Optional.empty();
}
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryNameSpaceHandler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryNameSpaceHandler.java
index 55649cdb41b66db1d022164f60ebf992c07b10b7..12b78c18bdabbbd84f46325b503d618c75c38644 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryNameSpaceHandler.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/MybatisRepositoryNameSpaceHandler.java
@@ -16,6 +16,7 @@
package org.springframework.data.mybatis.repository.config;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
+import org.springframework.data.repository.config.RepositoryBeanDefinitionParser;
/**
* Simple namespace handler for {@literal repositories} namespace.
@@ -27,9 +28,10 @@ public class MybatisRepositoryNameSpaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
- RepositoryBeanDefinitionParser repositoryBeanDefinitionParser = new RepositoryBeanDefinitionParser();
- registerBeanDefinitionParser("repositories", repositoryBeanDefinitionParser);
+ registerBeanDefinitionParser("mapping", new MybatisMappingContextParser());
+ registerBeanDefinitionParser("repositories",
+ new RepositoryBeanDefinitionParser(new MybatisRepositoryConfigExtension()));
registerBeanDefinitionParser("auditing",
new AuditingBeanDefinitionParser(BeanDefinitionNames.MYBATIS_MAPPING_CONTEXT_BEAN_NAME));
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/RepositoryBeanDefinitionParser.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/RepositoryBeanDefinitionParser.java
deleted file mode 100644
index 036e7407b2e58cf04de8fbed35db8bc765505b73..0000000000000000000000000000000000000000
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/config/RepositoryBeanDefinitionParser.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2012-2019 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.data.mybatis.repository.config;
-
-import org.w3c.dom.Element;
-
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.parsing.BeanComponentDefinition;
-import org.springframework.beans.factory.parsing.ReaderContext;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-import org.springframework.beans.factory.xml.BeanDefinitionParser;
-import org.springframework.beans.factory.xml.ParserContext;
-import org.springframework.beans.factory.xml.XmlReaderContext;
-import org.springframework.core.env.Environment;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.data.config.ConfigurationUtils;
-import org.springframework.data.repository.config.RepositoryConfigurationDelegate;
-import org.springframework.data.repository.config.RepositoryConfigurationUtils;
-import org.springframework.data.repository.config.XmlRepositoryConfigurationSource;
-import org.springframework.lang.Nullable;
-
-/**
- * Base class to implement repository namespaces.
- *
- * @author JARVIS SONG
- * @since 2.0.0
- */
-public class RepositoryBeanDefinitionParser implements BeanDefinitionParser {
-
- @Override
- @Nullable
- public BeanDefinition parse(Element element, ParserContext parser) {
- XmlReaderContext readerContext = parser.getReaderContext();
-
- try {
-
- ResourceLoader resourceLoader = ConfigurationUtils.getRequiredResourceLoader(readerContext);
- Environment environment = readerContext.getEnvironment();
- BeanDefinitionRegistry registry = parser.getRegistry();
-
- XmlRepositoryConfigurationSource configSource = new XmlRepositoryConfigurationSource(element, parser,
- environment);
- RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configSource, resourceLoader,
- environment);
-
- MybatisRepositoryConfigExtension extension = new MybatisRepositoryConfigExtension(resourceLoader);
-
- RepositoryConfigurationUtils.exposeRegistration(extension, registry, configSource);
-
- for (BeanComponentDefinition definition : delegate.registerRepositoriesIn(registry, extension)) {
- readerContext.fireComponentRegistered(definition);
- }
-
- }
- catch (RuntimeException ex) {
- handleError(ex, element, readerContext);
- }
-
- return null;
- }
-
- private void handleError(Exception e, Element source, ReaderContext reader) {
- reader.error(e.getMessage(), reader.extractSource(source), e);
- }
-
-}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/AbstractMybatisPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/AbstractMybatisPrecompiler.java
deleted file mode 100644
index a932f14acaa6b96c4db12654be6f5e464a77f3c3..0000000000000000000000000000000000000000
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/AbstractMybatisPrecompiler.java
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Copyright 2012-2019 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.data.mybatis.repository.query;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
-import javax.persistence.EmbeddedId;
-import javax.persistence.JoinColumn;
-import javax.persistence.JoinTable;
-import javax.persistence.ManyToOne;
-import javax.persistence.OneToOne;
-
-import com.samskivert.mustache.Mustache;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.ibatis.builder.xml.XMLMapperBuilder;
-import org.apache.ibatis.mapping.SqlCommandType;
-import org.apache.ibatis.session.Configuration;
-
-import org.springframework.data.mapping.AssociationHandler;
-import org.springframework.data.mapping.MappingException;
-import org.springframework.data.mapping.PropertyHandler;
-import org.springframework.data.mybatis.dialect.Dialect;
-import org.springframework.data.mybatis.mapping.MybatisMappingContext;
-import org.springframework.data.mybatis.mapping.MybatisPersistentEntity;
-import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
-import org.springframework.data.mybatis.mapping.model.Column;
-import org.springframework.data.mybatis.repository.support.ResidentParameterName;
-import org.springframework.data.repository.core.RepositoryInformation;
-import org.springframework.data.repository.query.parser.Part;
-import org.springframework.util.StringUtils;
-
-/**
- * Abstract mybatis precompiler.
- *
- * @author JARVIS SONG
- */
-@Slf4j
-abstract class AbstractMybatisPrecompiler implements MybatisPrecompiler {
-
- protected final MybatisMappingContext mappingContext;
-
- protected final Configuration configuration;
-
- protected final String namespace;
-
- protected final MybatisPersistentEntity> persistentEntity;
-
- protected final Dialect dialect;
-
- protected Class> repositoryInterface;
-
- protected EscapeCharacter escape;
-
- private final Mustache.Compiler mustache;
-
- AbstractMybatisPrecompiler(MybatisMappingContext mappingContext, Configuration configuration, Dialect dialect,
- RepositoryInformation repositoryInformation) {
-
- this(mappingContext, configuration, dialect, repositoryInformation.getDomainType());
-
- this.repositoryInterface = repositoryInformation.getRepositoryInterface();
- }
-
- AbstractMybatisPrecompiler(MybatisMappingContext mappingContext, Configuration configuration, Dialect dialect,
- Class> domainType) {
- this.mappingContext = mappingContext;
- this.configuration = configuration;
- this.namespace = domainType.getName();
- this.persistentEntity = mappingContext.getRequiredPersistentEntity(domainType);
- this.dialect = dialect;
-
- this.mustache = Mustache.compiler().withLoader(name -> {
- String path = "org/springframework/data/mybatis/repository/query/template/" + name + ".mustache";
- InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(path);
- return new InputStreamReader(inputStream, StandardCharsets.UTF_8);
- }).escapeHTML(false).withCollector(new DefaultCollector());
- }
-
- protected String render(String name, Object context) {
- // Mustache.Compiler mustache = Mustache.compiler().escapeHTML(false);
- String path = "org/springframework/data/mybatis/repository/query/template/" + name + ".mustache";
- try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(path)) {
- try (InputStreamReader source = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
- return this.mustache.compile(source).execute(context);
- }
- catch (IOException ex) {
- throw new MappingException("Could not render the statement: " + name, ex);
- }
- }
- catch (IOException ex) {
- throw new MappingException("Could not render the statement: " + name, ex);
- }
- }
-
- @Override
- public void precompile() {
- String xml = this.doPrecompile();
-
- if (StringUtils.hasText(xml)) {
- this.compileMapper(this.namespace, xml);
- }
-
- }
-
- protected void compileMapper(String namespace, String content) {
- String xml = "\n"
- + "\n"
- + "\n" + content + "\n";
- if (log.isDebugEnabled()) {
- log.debug(xml);
- }
- try (InputStream inputStream = new ByteArrayInputStream(xml.getBytes())) {
- XMLMapperBuilder mapperBuilder = new XMLMapperBuilder(inputStream, this.configuration,
- this.namespace.replace('.', '/') + UUID.randomUUID().toString() + this.getResourceSuffix(),
- this.configuration.getSqlFragments());
- mapperBuilder.parse();
- }
- catch (IOException ex) {
- throw new MappingException(ex.getMessage(), ex);
- }
- }
-
- protected abstract String doPrecompile();
-
- protected String getResourceSuffix() {
- return ".precompile";
- }
-
- protected String getTableName() {
- return this.persistentEntity.getTable().getFullName();
- }
-
- protected Map mappingPropertyToColumn() {
- Map map = new LinkedHashMap<>();
-
- this.persistentEntity.doWithProperties((PropertyHandler) pp -> {
- if (pp.isAnnotationPresent(EmbeddedId.class) || pp.isEmbeddable()) {
- MybatisPersistentEntity> embeddedEntity = this.mappingContext
- .getRequiredPersistentEntity(pp.getActualType());
- embeddedEntity.doWithProperties((PropertyHandler) epp -> {
- map.put(String.format("%s.%s", pp.getName(), epp.getName()), epp.getColumn());
- });
- return;
- }
- map.put(pp.getName(), pp.getColumn());
- });
-
- this.persistentEntity.doWithAssociations((AssociationHandler) ass -> {
- MybatisPersistentProperty inverse = ass.getInverse();
-
- if (inverse.isAnnotationPresent(ManyToOne.class) || inverse.isAnnotationPresent(OneToOne.class)) {
-
- if (inverse.isAnnotationPresent(JoinTable.class)) {
- return;
- }
-
- MybatisPersistentEntity> targetEntity = this.mappingContext
- .getRequiredPersistentEntity(inverse.getActualType());
-
- String columnName = null;
- String referencedColumnName = null;
- JoinColumn joinColumn = inverse.findAnnotation(JoinColumn.class);
- if (null != joinColumn) {
- if (StringUtils.hasText(joinColumn.name())) {
- columnName = joinColumn.name();
- }
- if (StringUtils.hasText(joinColumn.referencedColumnName())) {
- referencedColumnName = joinColumn.referencedColumnName();
- }
-
- }
- if (StringUtils.isEmpty(columnName)) {
- columnName = inverse.getName() + "_"
- + targetEntity.getRequiredIdProperty().getColumn().getName().render(this.dialect);
- }
- if (StringUtils.isEmpty(referencedColumnName)) {
- referencedColumnName = targetEntity.getRequiredIdProperty().getColumn().getName()
- .render(this.dialect);
- }
- map.put(String.format("%s.%s", inverse.getName(), targetEntity.getRequiredIdProperty().getName()),
- new Column(columnName));
-
- }
-
- });
- map.forEach((s, column) -> column.getName().setDialect(this.dialect));
- return map;
- }
-
- protected List findProperties(MybatisPersistentEntity> entity) {
- List properties = new ArrayList<>();
- entity.doWithProperties((PropertyHandler) properties::add);
- return properties;
- }
-
- protected List findProperties() {
- return this.findProperties(this.persistentEntity);
- }
-
- protected SqlCommandType extractSqlCommandType(String queryString) {
- if (StringUtils.isEmpty(queryString)) {
- return SqlCommandType.UNKNOWN;
- }
-
- queryString = queryString.trim().toLowerCase();
- if (queryString.startsWith("insert")) {
- return SqlCommandType.INSERT;
- }
- if (queryString.startsWith("update")) {
- return SqlCommandType.UPDATE;
- }
- if (queryString.startsWith("delete")) {
- return SqlCommandType.DELETE;
- }
- if (queryString.startsWith("select")) {
- return SqlCommandType.SELECT;
- }
-
- return SqlCommandType.UNKNOWN;
- }
-
- protected boolean canUpperCase(MybatisPersistentProperty property) {
- return String.class.equals(property.getType());
- }
-
- protected String buildQueryByConditionOperator(Part.Type type) {
- switch (type) {
- case BETWEEN:
- return " BETWEEN ";
- case SIMPLE_PROPERTY:
- return "=";
- case NEGATING_SIMPLE_PROPERTY:
- return "]]>";
- case LESS_THAN:
- case BEFORE:
- return "";
- case LESS_THAN_EQUAL:
- return "";
- case GREATER_THAN:
- case AFTER:
- return "]]>";
- case GREATER_THAN_EQUAL:
- return ">=";
- case NOT_LIKE:
- case NOT_CONTAINING:
- return " NOT LIKE ";
- case LIKE:
- case STARTING_WITH:
- case ENDING_WITH:
- case CONTAINING:
- return " LIKE ";
- case IN:
- return " IN ";
- case NOT_IN:
- return " NOT IN ";
- }
-
- return "";
- }
-
- protected String buildQueryByConditionLeftSegment(String column, Part.IgnoreCaseType ignoreCaseType,
- MybatisPersistentProperty property) {
- switch (ignoreCaseType) {
-
- case ALWAYS:
- return this.dialect.getLowercaseFunction() + "(" + column + ")";
- case WHEN_POSSIBLE:
- if ((null != property) && this.canUpperCase(property)) {
- return this.dialect.getLowercaseFunction() + "(" + column + ")";
- }
- return column;
- case NEVER:
- default:
- return column;
- }
- }
-
- protected String buildQueryByConditionRightSegment(Part.Type type, Part.IgnoreCaseType ignoreCaseType,
- String[] properties, Column column) {
- switch (type) {
- case BETWEEN:
- return String.format("#{%s} and #{%s}", properties[0], properties[1]);
- case IS_NOT_NULL:
- return " IS NOT NULL";
- case IS_NULL:
- return " IS NULL";
- case STARTING_WITH:
- return this.buildLikeRightSegment(properties[0], false, true, ignoreCaseType);
- case ENDING_WITH:
- return this.buildLikeRightSegment(properties[0], true, false, ignoreCaseType);
- case NOT_CONTAINING:
- case CONTAINING:
- case LIKE:
- return this.buildLikeRightSegment(properties[0], true, true, ignoreCaseType);
- case NOT_IN:
- case IN:
- return String.format(
- "#{__item}",
- properties[0]);
- case TRUE:
- return " = 1";
- case FALSE:
- return " = 0";
- default:
- if (ignoreCaseType == Part.IgnoreCaseType.ALWAYS || ignoreCaseType == Part.IgnoreCaseType.WHEN_POSSIBLE) {
- if (null != column.getTypeHandler()) {
- return String.format("%s(#{%s,javaType=%s,typeHandler=%s})", this.dialect.getLowercaseFunction(),
- properties[0], column.getJavaType().getName(), column.getTypeHandler().getName());
- }
- return String.format("%s(#{%s})", this.dialect.getLowercaseFunction(), properties[0]);
- }
- if (null != column.getTypeHandler()) {
- return String.format("#{%s,javaType=%s,typeHandler=%s}", properties[0], column.getJavaType().getName(),
- column.getTypeHandler().getName());
- }
- return String.format("#{%s}", properties[0]);
-
- }
- }
-
- protected String buildLikeRightSegment(String property, boolean left, boolean right,
- Part.IgnoreCaseType ignoreCaseType) {
- return String.format("%s", property, (left ? "'%' + " : ""),
- property, (right ? " + '%'" : ""),
- (((ignoreCaseType == Part.IgnoreCaseType.ALWAYS)
- || (ignoreCaseType == Part.IgnoreCaseType.WHEN_POSSIBLE))
- ? String.format("%s(#{__bind_%s})", this.dialect.getLowercaseFunction(), property)
- : String.format("#{__bind_%s}", property)));
- }
-
- protected String buildStandardOrderBySegment() {
- String mapping = this.mappingPropertyToColumn().entrySet().stream()
- .map(entry -> String.format("'%s':'%s'", entry.getKey(),
- entry.getValue().getName().render(this.dialect)))
- .collect(Collectors.joining(","));
- String bind = String.format("", mapping);
- String sql = String.format("order by "
- + " "
- + "%s(" + "${__columnsMap[item.property]}"
- + ") " + "${item.direction.name().toLowerCase()}" + "",
- ResidentParameterName.SORT, this.dialect.getLowercaseFunction());
- return String.format("%s %s", ResidentParameterName.SORT, bind, sql);
- }
-
-}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisParameters.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisParameters.java
index a106f4fcc2a55b2946003e5bb0b24da9d1e22239..4896ecbfeba16d604bbfb25050996dafb25ecb55 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisParameters.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisParameters.java
@@ -54,7 +54,7 @@ public class MybatisParameters extends Parameters getReturnType() {
+ public Class> getReturnType() {
return this.method.getReturnType();
}
- String getActualResultType() {
+ public String getActualResultType() {
Class> type = this.getReturnType();
if (type == Map.class) {
return "map";
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisQueryMethodPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisQueryMethodPrecompiler.java
deleted file mode 100644
index 38e2236e4714d3a8e2fe0c99c36c3bc5961a4660..0000000000000000000000000000000000000000
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/MybatisQueryMethodPrecompiler.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2012-2019 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.data.mybatis.repository.query;
-
-import java.util.regex.Pattern;
-
-import org.apache.ibatis.session.Configuration;
-
-import org.springframework.data.mapping.MappingException;
-import org.springframework.data.mybatis.dialect.Dialect;
-import org.springframework.data.mybatis.mapping.MybatisMappingContext;
-import org.springframework.data.mybatis.repository.support.ResidentStatementName;
-
-/**
- * .
- *
- * @author JARVIS SONG
- */
-abstract class MybatisQueryMethodPrecompiler extends AbstractMybatisPrecompiler {
-
- private static final Pattern SELECT_ALL_FROM = Pattern.compile("^\\s*select\\s+\\*\\s+from\\s+.*",
- Pattern.CASE_INSENSITIVE);
-
- protected final AbstractMybatisQuery query;
-
- MybatisQueryMethodPrecompiler(MybatisMappingContext mappingContext, Configuration configuration, Dialect dialect,
- AbstractMybatisQuery query) {
- super(mappingContext, configuration, dialect, query.getQueryMethod().getEntityInformation().getJavaType());
-
- this.query = query;
- }
-
- @Override
- protected String doPrecompile() {
-
- if (this.configuration.hasStatement(this.query.getStatementId(), false)) {
- return "";
- }
-
- switch (this.query.getSqlCommandType()) {
-
- case INSERT:
- return this.insert();
- case UPDATE:
- return this.update();
- case DELETE:
- return this.delete();
- case SELECT:
- return this.select();
- default:
- throw new MappingException("Unsupported SQL Command Type: " + this.query.getSqlCommandType().name());
-
- }
-
- }
-
- protected String insert() {
- return String.format("%s", this.query.getStatementName(), this.mainQueryString());
- }
-
- protected String update() {
- return String.format("%s", this.query.getStatementName(), this.mainQueryString());
- }
-
- protected String delete() {
- return String.format("%s", this.query.getStatementName(), this.mainQueryString());
- }
-
- protected String select() {
- String sql = this.mainQueryString();
- return String.format("", this.query.getStatementName(),
- this.resultMapOrType(sql), sql);
- }
-
- protected String resultMapOrType(String sql) {
- MybatisQueryMethod method = this.query.getQueryMethod();
-
- return String.format("%s=\"%s\"",
- (null != method.getResultMap() || SELECT_ALL_FROM.matcher(sql.toLowerCase()).matches()) ? "resultMap"
- : "resultType",
- ((null != method.getResultMap()) ? method.getResultMap() : //
- (SELECT_ALL_FROM.matcher(sql).matches() ? //
- ResidentStatementName.RESULT_MAP : //
- method.getActualResultType())));
- }
-
- protected abstract String mainQueryString();
-
-}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisPrecompiler.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisPrecompiler.java
deleted file mode 100644
index e77309a9e291060bc97cc89c5b91b9ac27334698..0000000000000000000000000000000000000000
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisPrecompiler.java
+++ /dev/null
@@ -1,906 +0,0 @@
-/*
- * Copyright 2012-2019 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.data.mybatis.repository.query;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import javax.persistence.EmbeddedId;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.JoinColumn;
-import javax.persistence.JoinColumns;
-import javax.persistence.JoinTable;
-import javax.persistence.ManyToMany;
-import javax.persistence.ManyToOne;
-import javax.persistence.OneToMany;
-import javax.persistence.OneToOne;
-import javax.persistence.OrderBy;
-import javax.persistence.SequenceGenerator;
-import javax.persistence.SequenceGenerators;
-
-import com.samskivert.mustache.Mustache;
-import com.samskivert.mustache.Mustache.InvertibleLambda;
-import com.samskivert.mustache.Template.Fragment;
-import org.apache.ibatis.session.Configuration;
-
-import org.springframework.data.mapping.AssociationHandler;
-import org.springframework.data.mapping.MappingException;
-import org.springframework.data.mapping.PropertyHandler;
-import org.springframework.data.mybatis.annotation.Condition;
-import org.springframework.data.mybatis.annotation.Conditions;
-import org.springframework.data.mybatis.annotation.Example;
-import org.springframework.data.mybatis.dialect.Dialect;
-import org.springframework.data.mybatis.dialect.pagination.RowSelection;
-import org.springframework.data.mybatis.dialect.pagination.SQLServer2005LimitHandler;
-import org.springframework.data.mybatis.dialect.pagination.SQLServer2012LimitHandler;
-import org.springframework.data.mybatis.mapping.MybatisMappingContext;
-import org.springframework.data.mybatis.mapping.MybatisPersistentEntity;
-import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
-import org.springframework.data.mybatis.mapping.model.Association;
-import org.springframework.data.mybatis.mapping.model.Collection;
-import org.springframework.data.mybatis.mapping.model.Column;
-import org.springframework.data.mybatis.mapping.model.ColumnResult;
-import org.springframework.data.mybatis.repository.MybatisExampleRepository;
-import org.springframework.data.mybatis.repository.support.ResidentStatementName;
-import org.springframework.data.mybatis.repository.support.SqlSessionRepositorySupport;
-import org.springframework.data.repository.core.RepositoryInformation;
-import org.springframework.data.repository.query.parser.Part;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.StringUtils;
-
-/**
- * Simple mybatis precompiler.
- *
- * @author JARVIS SONG
- */
-class SimpleMybatisPrecompiler extends AbstractMybatisPrecompiler {
-
- static final String DEFAULT_SEQUENCE_NAME = "seq_spring_data_mybatis";
-
- SimpleMybatisPrecompiler(MybatisMappingContext mappingContext, Configuration configuration, Dialect dialect,
- RepositoryInformation repositoryInformation) {
- super(mappingContext, configuration, dialect, repositoryInformation);
- }
-
- @Override
- protected String doPrecompile() {
- StringBuilder builder = new StringBuilder();
-
- // SQL Fragments
- // __base_column_list
- builder.append(this.addBaseColumnListSQL());
- // __query_by_example_where_clause
- builder.append(this.addQueryByExampleWhereClauseSQL());
- // __standard_sort
- builder.append(this.addStandardSortSQL());
- // __where_clause_by_fixed_id
- builder.append(this.addWhereClauseByFixedIdSQL());
- // __where_clause_by_entity
- builder.append(this.addWhereClauseByEntitySQL());
- // __where_clause_by_id
- builder.append(this.addWhereClauseByIdSQL());
- // __where_clause_by_ids
- builder.append(this.addWhereClauseByIdsSQL());
- // ResultMap
- builder.append(this.addResultMap());
-
- // Statements
- builder.append(this.addInsertStatement(true));
- builder.append(this.addInsertStatement(false));
- builder.append(this.addUpdateStatement(true, true));
- builder.append(this.addUpdateStatement(true, false));
- builder.append(this.addUpdateStatement(false, true));
- builder.append(this.addUpdateStatement(false, false));
- builder.append(this.addDeleteByIdStatement());
- builder.append(this.addDeleteByIdsStatement());
- builder.append(this.addDeleteAllStatement());
- builder.append(this.addGetByIdStatement());
- builder.append(this.addFindStatement(true));
- builder.append(this.addFindStatement(false));
- builder.append(this.addCountAllStatement());
- builder.append(this.addCountStatement());
-
- builder.append(this.addQueryByExample());
- builder.append(this.addQueryByExampleForPage());
- builder.append(this.addCountQueryByExample());
-
- if (null != this.repositoryInterface
- && MybatisExampleRepository.class.isAssignableFrom(this.repositoryInterface)) {
- if (this.persistentEntity.isAnnotationPresent(Example.class)) {
-
- try {
- ClassUtils.forName(this.persistentEntity.getType().getName() + "Example",
- this.persistentEntity.getType().getClassLoader());
- }
- catch (ClassNotFoundException ex) {
- throw new MappingException(
- "Are you forget to generate " + this.persistentEntity.getType().getName() + "Example ?");
- }
-
- builder.append(this.addFindByExampleWhereClauseSQL());
- builder.append(this.addFindByExampleStatement());
- }
- else {
- throw new MappingException(String.format(
- "The %s extends MybatisExampleRepository, but could not find @Example on the entity: %s",
- this.repositoryInterface.getName(), this.persistentEntity.getType().getName()));
- }
- }
- return builder.toString();
- }
-
- protected boolean checkSqlFragment(String statementName) {
- return this.configuration.getSqlFragments()
- .containsKey(this.namespace + SqlSessionRepositorySupport.DOT + statementName);
- }
-
- protected boolean checkStatement(String statementName) {
- return this.configuration.hasStatement(this.namespace + SqlSessionRepositorySupport.DOT + statementName, false);
- }
-
- private String addBaseColumnListSQL() {
- if (this.checkSqlFragment(ResidentStatementName.BASE_COLUMN_LIST)) {
- return "";
- }
- Map params = new HashMap<>();
- params.put("statementName", ResidentStatementName.BASE_COLUMN_LIST);
- params.put("columns", this.mappingPropertyToColumn().values().stream()
- .map(c -> c.getName().render(this.dialect)).collect(Collectors.joining(",")));
- return this.render("BasicColumns", params);
- }
-
- private String addQueryByExampleWhereClauseSQL() {
- if (this.checkSqlFragment(ResidentStatementName.QUERY_BY_EXAMPLE_WHERE_CLAUSE)) {
- return "";
- }
- Map scopes = new HashMap<>();
- scopes.put("statementName", ResidentStatementName.QUERY_BY_EXAMPLE_WHERE_CLAUSE);
- scopes.put("properties", this.mappingPropertyToColumn().entrySet());
- scopes.put("testNotNull", this.lambdaTestNotNull());
- scopes.put("dialect", this.dialect);
- scopes.put("replaceDotToUnderline", this.lambdaReplaceDotToUnderline());
- scopes.put("regexLike", this.lambdaRegexLike());
- return this.render("QueryByExampleWhereClause", scopes);
- }
-
- private String addStandardSortSQL() {
- if (this.checkSqlFragment(ResidentStatementName.STANDARD_SORT)) {
- return "";
- }
- Map scopes = new HashMap<>();
- scopes.put("statementName", ResidentStatementName.STANDARD_SORT);
- scopes.put("columnsMap",
- this.mappingPropertyToColumn().entrySet().stream()
- .map(entry -> String.format("'%s':'%s'", entry.getKey(),
- entry.getValue().getName().render(this.dialect)))
- .collect(Collectors.joining(",")));
- scopes.put("lowercaseFunction", this.dialect.getLowercaseFunction());
- return this.render("StandardSort", scopes);
- }
-
- private String addWhereClauseByFixedIdSQL() {
- if (this.checkSqlFragment(ResidentStatementName.WHERE_BY_FIXED_ID_CLAUSE)) {
- return "";
- }
- MybatisPersistentProperty idProperty = this.persistentEntity.getRequiredIdProperty();
-
- Map scopes = new HashMap<>();
- scopes.put("statementName", ResidentStatementName.WHERE_BY_FIXED_ID_CLAUSE);
- scopes.put("embedded", idProperty.isAnnotationPresent(EmbeddedId.class));
- if ((Boolean) scopes.get("embedded")) {
- scopes.put("properties",
- this.findProperties(this.mappingContext.getRequiredPersistentEntity(idProperty.getActualType())));
- }
- else {
- scopes.put("properties", this.findProperties());
- }
- return this.render("WhereClauseByFixedId", scopes);
- }
-
- private String addWhereClauseByEntitySQL() {
- if (this.checkSqlFragment(ResidentStatementName.WHERE_BY_ENTITY_CLAUSE)) {
- return "";
- }
- MybatisPersistentProperty idProperty = this.persistentEntity.getRequiredIdProperty();
-
- Map scopes = new HashMap<>();
- scopes.put("idPropertyName", idProperty.getName());
- scopes.put("statementName", ResidentStatementName.WHERE_BY_ENTITY_CLAUSE);
- scopes.put("embedded", idProperty.isAnnotationPresent(EmbeddedId.class));
- if ((Boolean) scopes.get("embedded")) {
- scopes.put("properties",
- this.findProperties(this.mappingContext.getRequiredPersistentEntity(idProperty.getActualType())));
- }
- else {
- scopes.put("properties", this.findProperties());
- }
- return this.render("WhereClauseByEntity", scopes);
-
- }
-
- private String addWhereClauseByIdSQL() {
- if (this.checkSqlFragment(ResidentStatementName.WHERE_BY_ID_CLAUSE)) {
- return "";
- }
- MybatisPersistentProperty idProperty = this.persistentEntity.getRequiredIdProperty();
- Map scopes = new HashMap<>();
- scopes.put("idPropertyName", idProperty.getName());
- scopes.put("statementName", ResidentStatementName.WHERE_BY_ID_CLAUSE);
- scopes.put("embedded", idProperty.isAnnotationPresent(EmbeddedId.class));
- if ((Boolean) scopes.get("embedded")) {
- scopes.put("properties",
- this.findProperties(this.mappingContext.getRequiredPersistentEntity(idProperty.getActualType())));
- }
- else {
- scopes.put("properties", this.findProperties());
- }
- return this.render("WhereClauseById", scopes);
- }
-
- private String addWhereClauseByIdsSQL() {
- if (this.checkSqlFragment(ResidentStatementName.WHERE_BY_IDS_CLAUSE)
- || null == this.persistentEntity.getIdClass()) {
- return "";
- }
- MybatisPersistentProperty idProperty = this.persistentEntity.getRequiredIdProperty();
- Map scopes = new HashMap<>();
- scopes.put("statementName", ResidentStatementName.WHERE_BY_IDS_CLAUSE);
- scopes.put("idProperty", idProperty);
- scopes.put("embedded", idProperty.isAnnotationPresent(EmbeddedId.class));
- if ((Boolean) scopes.get("embedded")) {
- scopes.put("properties",
- this.findProperties(this.mappingContext.getRequiredPersistentEntity(idProperty.getActualType())));
- }
- return this.render("WhereClauseByIds", scopes);
-
- }
-
- private String addResultMap() {
- Map params = new HashMap<>();
- List results = new LinkedList<>();
- List embeddedAssociations = new ArrayList<>();
-
- this.persistentEntity.doWithProperties((PropertyHandler) pp -> {
- if (pp.isAnnotationPresent(EmbeddedId.class) || pp.isEmbeddable()) {
- MybatisPersistentEntity> embeddedEntity = this.mappingContext
- .getRequiredPersistentEntity(pp.getActualType());
- embeddedEntity.doWithProperties((PropertyHandler) epp -> {
- ColumnResult cr = this.columnResult(epp);
- cr.setPrimaryKey(pp.isAnnotationPresent(EmbeddedId.class));
- cr.setProperty(pp.getName() + "." + epp.getName());
- results.add(cr);
- });
-
- return;
- }
- results.add(this.columnResult(pp));
- });
- results.sort((o1, o2) -> o1.isPrimaryKey() ? -1 : 1);
- List associations = new ArrayList<>();
- List collections = new ArrayList<>();
- this.persistentEntity.doWithAssociations((AssociationHandler) ass -> {
- MybatisPersistentProperty inverse = ass.getInverse();
- if (inverse.isAnnotationPresent(ManyToOne.class) || inverse.isAnnotationPresent(OneToOne.class)) {
- MybatisPersistentEntity> targetEntity = this.mappingContext
- .getRequiredPersistentEntity(inverse.getActualType());
- String namespace = targetEntity.getType().getName();
-
- Association association = new Association().setProperty(inverse.getName())
- .setJavaType(inverse.getActualType().getName())
- .setTargetTable(targetEntity.getTable().getFullName());
- String fetch = null;
- ManyToOne manyToOne = inverse.findAnnotation(ManyToOne.class);
- if (null != manyToOne) {
- fetch = manyToOne.fetch().name().toLowerCase();
- }
- else {
- OneToOne oneToOne = inverse.findAnnotation(OneToOne.class);
- if (null != oneToOne) {
- fetch = oneToOne.fetch().name().toLowerCase();
- }
- }
- association.setFetch(fetch);
-
- List joinColumns = new ArrayList<>();
-
- JoinColumns joinColumnsAnn = inverse.findAnnotation(JoinColumns.class);
- if (null != joinColumnsAnn && null != joinColumnsAnn.value() && joinColumnsAnn.value().length > 0) {
- for (JoinColumn joinColumn : joinColumnsAnn.value()) {
- joinColumns.add(new Association.JoinColumn(
- StringUtils.hasText(joinColumn.name()) ? joinColumn.name()
- : targetEntity.getTable().getName() + "_"
- + targetEntity.getIdProperty().getColumn().getName()
- .render(this.dialect),
- StringUtils.hasText(joinColumn.referencedColumnName())
- ? joinColumn.referencedColumnName() : this.persistentEntity.getIdProperty()
- .getColumn().getName().render(this.dialect)));
- }
- }
- JoinColumn joinColumnAnn = inverse.findAnnotation(JoinColumn.class);
- if (null != joinColumnAnn) {
- joinColumns
- .add(new Association.JoinColumn(
- StringUtils.hasText(joinColumnAnn.name()) ? joinColumnAnn.name()
- : targetEntity.getTable().getName() + "_"
- + targetEntity.getIdProperty().getColumn().getName()
- .render(this.dialect),
- StringUtils.hasText(joinColumnAnn.referencedColumnName())
- ? joinColumnAnn.referencedColumnName() : this.persistentEntity
- .getIdProperty().getColumn().getName().render(this.dialect)));
- }
-
- if (joinColumns.isEmpty()) {
- joinColumns.add(new Association.JoinColumn(
- targetEntity.getTable().getName() + "_"
- + targetEntity.getIdProperty().getColumn().getName().render(this.dialect),
- this.persistentEntity.getIdProperty().getColumn().getName().render(this.dialect)));
- }
-
- association.setJoinColumns(joinColumns)
- .setSelect(namespace + '.' + this.addAssociationManyToOne(namespace, association));
-
- associations.add(association);
- }
-
- if (inverse.isAnnotationPresent(ManyToMany.class) || inverse.isAnnotationPresent(OneToMany.class)) {
- MybatisPersistentEntity> targetEntity = this.mappingContext
- .getRequiredPersistentEntity(inverse.getActualType());
-
- String namespace = targetEntity.getType().getName();
- Collection collection = new Collection().setProperty(inverse.getName())
- .setOfType(inverse.getActualType().getName())
- .setTargetTable(targetEntity.getTable().getFullName());
-
- OrderBy orderBy = inverse.findAnnotation(OrderBy.class);
- if (null != orderBy) {
- if (StringUtils.hasText(orderBy.value())) {
- collection.setOrder(orderBy.value());
- }
- else if (targetEntity.hasIdProperty() && !targetEntity.hasCompositeId()) {
- collection.setOrder(
- targetEntity.getIdProperty().getColumn().getName().render(this.dialect) + " ASC");
- }
- }
-
- ManyToMany manyToMany = inverse.findAnnotation(ManyToMany.class);
- if (null != manyToMany) {
- collection.setManyToMany(true).setFetch(manyToMany.fetch().name().toLowerCase());
- JoinTable joinTable = inverse.findAnnotation(JoinTable.class);
- if (null != joinTable) {
- Collection.JoinTable jt = new Collection.JoinTable(StringUtils.hasText(joinTable.name())
- ? joinTable.name() : (this.persistentEntity.getTable().getName() + "_"
- + targetEntity.getTable().getName()));
-
- JoinColumn[] joinColumns = joinTable.joinColumns();
- if (null == joinColumns || joinColumns.length == 0) {
- jt.addJoinColumn(new Collection.JoinColumn(
- this.persistentEntity.getTable().getName() + "_"
- + this.persistentEntity.getIdProperty().getColumn().getName()
- .render(this.dialect),
- this.persistentEntity.getIdProperty().getColumn().getName().render(this.dialect)));
- }
- else {
- for (JoinColumn joinColumn : joinColumns) {
- jt.addJoinColumn(new Collection.JoinColumn(joinColumn.name(),
- joinColumn.referencedColumnName()));
- }
- }
-
- JoinColumn[] inverseJoinColumns = joinTable.inverseJoinColumns();
- if (null == inverseJoinColumns || inverseJoinColumns.length == 0) {
- jt.addInverseJoinColumns(
- new Collection.JoinColumn(
- targetEntity.getTable().getName() + "_"
- + targetEntity.getIdProperty().getColumn().getName()
- .render(this.dialect),
- targetEntity.getIdProperty().getColumn().getName().render(this.dialect)));
- }
- else {
- for (JoinColumn joinColumn : inverseJoinColumns) {
- jt.addInverseJoinColumns(new Collection.JoinColumn(joinColumn.name(),
- joinColumn.referencedColumnName()));
- }
- }
- collection.setJoinTable(jt);
- }
- else {
- collection.setJoinTable(new Collection.JoinTable(
- this.persistentEntity.getTable().getName() + "_" + targetEntity.getTable().getName())
- .addJoinColumn(new Collection.JoinColumn(
- this.persistentEntity.getTable().getName() + "_"
- + this.persistentEntity.getIdProperty().getColumn().getName()
- .render(this.dialect),
- this.persistentEntity.getIdProperty().getColumn().getName()
- .render(this.dialect)))
- .addInverseJoinColumns(new Collection.JoinColumn(
- targetEntity.getTable().getName() + "_"
- + targetEntity.getIdProperty().getColumn().getName()
- .render(this.dialect),
- targetEntity.getIdProperty().getColumn().getName()
- .render(this.dialect))));
- }
- collection.setSelect(namespace + '.' + this.addAssociationManyToMany(namespace, collection));
- }
- else {
- OneToMany oneToMany = inverse.findAnnotation(OneToMany.class);
- if (null != oneToMany) {
- collection.setManyToMany(false).setFetch(oneToMany.fetch().name().toLowerCase());
-
- List joinColumns = new ArrayList<>();
-
- JoinColumns joinColumnsAnn = inverse.findAnnotation(JoinColumns.class);
- if (null != joinColumnsAnn && null != joinColumnsAnn.value()
- && joinColumnsAnn.value().length > 0) {
- for (JoinColumn joinColumn : joinColumnsAnn.value()) {
- joinColumns.add(new Collection.JoinColumn(
- StringUtils.hasText(joinColumn.name()) ? joinColumn.name()
- : this.persistentEntity.getTable().getName() + "_"
- + this.persistentEntity.getIdProperty().getColumn().getName()
- .render(this.dialect),
- StringUtils.hasText(joinColumn.referencedColumnName())
- ? joinColumn.referencedColumnName() : this.persistentEntity
- .getIdProperty().getColumn().getName().render(this.dialect)));
- }
- }
- JoinColumn joinColumnAnn = inverse.findAnnotation(JoinColumn.class);
- if (null != joinColumnAnn) {
- joinColumns.add(new Collection.JoinColumn(
- StringUtils.hasText(joinColumnAnn.name()) ? joinColumnAnn.name()
- : this.persistentEntity.getTable().getName() + "_"
- + this.persistentEntity.getIdProperty().getColumn().getName()
- .render(this.dialect),
- StringUtils.hasText(joinColumnAnn.referencedColumnName())
- ? joinColumnAnn.referencedColumnName() : this.persistentEntity
- .getIdProperty().getColumn().getName().render(this.dialect)));
- }
-
- if (joinColumns.isEmpty()) {
- joinColumns.add(new Collection.JoinColumn(
- this.persistentEntity.getTable().getName() + "_"
- + this.persistentEntity.getIdProperty().getColumn().getName()
- .render(this.dialect),
- this.persistentEntity.getIdProperty().getColumn().getName().render(this.dialect)));
- }
-
- collection.setJoinColumns(joinColumns)
- .setSelect(namespace + '.' + this.addAssociationOneToMany(namespace, collection));
- }
- }
- collections.add(collection);
- }
- });
-
- params.put("statementName", ResidentStatementName.RESULT_MAP);
- params.put("entityType", this.persistentEntity.getType().getName());
- params.put("results", results);
- params.put("embeddedAssociations", embeddedAssociations);
- params.put("associations", associations);
- params.put("collections", collections);
-
- // avoid custom __result_map in mapper file, but has not generate association
- // select statement.
- if (this.configuration.hasResultMap(this.namespace + '.' + ResidentStatementName.RESULT_MAP)) {
- return "";
- }
-
- return this.render("ResultMap", params);
- }
-
- private String addAssociationManyToOne(String namespace, Association association) {
- String statementName = "__association_to_one_" + this.persistentEntity.getName().replace('.', '_') + "_"
- + association.getProperty();
- Map scopes = new HashMap<>();
- scopes.put("statementName", statementName);
- scopes.put("resultMap", ResidentStatementName.RESULT_MAP);
- scopes.put("association", association);
- this.compileMapper(namespace, this.render("AssociationManyToOne", scopes));
-
- return statementName;
- }
-
- private String addAssociationManyToMany(String namespace, Collection collection) {
- String statementName = "__association_many_to_many_" + this.persistentEntity.getName().replace('.', '_') + "_"
- + collection.getProperty();
- Map scopes = new HashMap<>();
- scopes.put("statementName", statementName);
- scopes.put("resultMap", ResidentStatementName.RESULT_MAP);
- scopes.put("collection", collection);
- this.compileMapper(namespace, this.render("AssociationManyToMany", scopes));
-
- return statementName;
- }
-
- private String addAssociationOneToMany(String namespace, Collection collection) {
- String statementName = "__association_one_to_many_" + this.persistentEntity.getName().replace('.', '_') + "_"
- + collection.getProperty();
- Map scopes = new HashMap<>();
- scopes.put("statementName", statementName);
- scopes.put("resultMap", ResidentStatementName.RESULT_MAP);
- scopes.put("collection", collection);
- this.compileMapper(namespace, this.render("AssociationOneToMany", scopes));
-
- return statementName;
- }
-
- private String addInsertStatement(boolean selective) {
- if (this.checkStatement(selective ? ResidentStatementName.INSERT_SELECTIVE : ResidentStatementName.INSERT)) {
- return "";
- }
-
- MybatisPersistentProperty idProperty = this.persistentEntity.getIdProperty();
- String keyProperty = "";
- String keyColumn = "";
- boolean useGeneratedKeys = false;
- boolean excludeId = false;
-
- if (!this.persistentEntity.hasCompositeId() && null != idProperty) {
- keyProperty = idProperty.getName();
- keyColumn = idProperty.getColumn().getName().getText();
- if (idProperty.isAnnotationPresent(GeneratedValue.class)) {
- useGeneratedKeys = true;
- excludeId = true;
- }
- }
-
- Map scopes = new HashMap<>();
- scopes.put("statementName", selective ? ResidentStatementName.INSERT_SELECTIVE : ResidentStatementName.INSERT);
- scopes.put("properties", this.mappingPropertyToColumn().entrySet());
- scopes.put("table", this.getTableName());
- scopes.put("parameterType", this.persistentEntity.getType().getName());
- scopes.put("selective", selective);
- scopes.put("keyProperty", keyProperty);
- scopes.put("keyColumn", keyColumn);
- scopes.put("useGeneratedKeys", useGeneratedKeys);
- scopes.put("testNotNull", this.lambdaTestNotNull());
-
- if (useGeneratedKeys) {
- scopes.putAll(this.buildKeyGenerator(idProperty));
- }
-
- scopes.put("excludeId", !"BEFORE".equals(scopes.get("order")) && excludeId);
-
- return this.render("Insert", scopes);
-
- }
-
- private Map buildKeyGenerator(MybatisPersistentProperty idProperty) {
- Map result = new HashMap<>();
- boolean executeBefore;
- String sql;
- GeneratedValue gv = idProperty.getRequiredAnnotation(GeneratedValue.class);
- if (gv.strategy() == GenerationType.IDENTITY || (gv.strategy() == GenerationType.AUTO
- && "identity".equals(this.dialect.getNativeIdentifierGeneratorStrategy()))) {
- // identity
- sql = this.dialect.getIdentityColumnSupport().getIdentitySelectString(this.getTableName(),
- idProperty.getColumn().getName().getCanonicalName(),
- idProperty.getColumn().getJdbcType().TYPE_CODE);
- executeBefore = false;
- }
- else if (gv.strategy() == GenerationType.SEQUENCE || (gv.strategy() == GenerationType.AUTO
- && "sequence".equals(this.dialect.getNativeIdentifierGeneratorStrategy()))) {
- String sequenceName = DEFAULT_SEQUENCE_NAME;
- if (StringUtils.hasText(gv.generator())) {
- // search sequence generator
- Map sequenceGenerators = new HashMap<>();
- if (this.persistentEntity.isAnnotationPresent(SequenceGenerators.class)) {
- sequenceGenerators.putAll(Stream
- .of(this.persistentEntity.getRequiredAnnotation(SequenceGenerators.class).value())
- .filter(sg -> StringUtils.hasText(sg.sequenceName()))
- .collect(Collectors.toMap(SequenceGenerator::name, SequenceGenerator::sequenceName)));
- }
- if (this.persistentEntity.isAnnotationPresent(SequenceGenerator.class)) {
- SequenceGenerator sg = this.persistentEntity.getRequiredAnnotation(SequenceGenerator.class);
- if (StringUtils.hasText(sg.sequenceName())) {
- sequenceGenerators.put(sg.name(), sg.sequenceName());
- }
- }
- if (idProperty.isAnnotationPresent(SequenceGenerators.class)) {
- sequenceGenerators.putAll(Stream
- .of(idProperty.getRequiredAnnotation(SequenceGenerators.class).value())
- .filter((sg) -> StringUtils.hasText(sg.sequenceName()))
- .collect(Collectors.toMap(SequenceGenerator::name, SequenceGenerator::sequenceName)));
- }
- if (idProperty.isAnnotationPresent(SequenceGenerator.class)) {
- SequenceGenerator sg = idProperty.getRequiredAnnotation(SequenceGenerator.class);
- if (StringUtils.hasText(sg.sequenceName())) {
- sequenceGenerators.put(sg.name(), sg.sequenceName());
- }
- }
- String sn = sequenceGenerators.get(gv.generator());
- if (StringUtils.hasText(sn)) {
- sequenceName = sn;
- }
- }
- sql = this.dialect.getSequenceNextValString(sequenceName);
- executeBefore = true;
- }
- else {
- throw new UnsupportedOperationException("unsupported generated value id strategy: " + gv.strategy());
- }
- result.put("order", executeBefore ? "BEFORE" : "AFTER");
- result.put("keySql", sql);
- result.put("keyType", idProperty.getType().getName());
- return result;
- }
-
- private String addUpdateStatement(boolean selective, boolean byId) {
- String statement = (selective
- ? (byId ? ResidentStatementName.UPDATE_SELECTIVE_BY_ID : ResidentStatementName.UPDATE_SELECTIVE)
- : (byId ? ResidentStatementName.UPDATE_BY_ID : ResidentStatementName.UPDATE));
- if (this.checkStatement(statement) || null == this.persistentEntity.getIdClass()) {
- return "";
- }
- Map scopes = new HashMap<>();
- scopes.put("statementName", statement);
- scopes.put("selective", selective);
- scopes.put("properties", this.mappingPropertyToColumn().entrySet());
- scopes.put("table", this.getTableName());
- scopes.put("testNotNull", this.lambdaTestNotNull());
- scopes.put("byId", byId);
-
- return this.render("Update", scopes);
- }
-
- private String addDeleteByIdStatement() {
- if (this.checkStatement(ResidentStatementName.DELETE_BY_ID) || null == this.persistentEntity.getIdClass()) {
- return "";
- }
-
- Map scopes = new HashMap<>();
- scopes.put("statementName", ResidentStatementName.DELETE_BY_ID);
- scopes.put("parameterType", this.persistentEntity.getIdClass().getName());
- scopes.put("table", this.getTableName());
- return this.render("DeleteById", scopes);
- }
-
- private String addDeleteByIdsStatement() {
- if (this.checkStatement(ResidentStatementName.DELETE_BY_IDS)) {
- return "";
- }
- Map scopes = new HashMap<>();
- scopes.put("statementName", ResidentStatementName.DELETE_BY_IDS);
- scopes.put("table", this.getTableName());
- return this.render("DeleteByIds", scopes);
- }
-
- private String addDeleteAllStatement() {
- if (this.checkStatement(ResidentStatementName.DELETE_ALL)) {
- return "";
- }
- Map scopes = new HashMap<>();
- scopes.put("statementName", ResidentStatementName.DELETE_ALL);
- scopes.put("table", this.getTableName());
- return this.render("DeleteAll", scopes);
- }
-
- private String addGetByIdStatement() {
- if (this.checkStatement(ResidentStatementName.GET_BY_ID) || null == this.persistentEntity.getIdClass()) {
- return "";
- }
- Map scopes = new HashMap<>();
- scopes.put("statementName", ResidentStatementName.GET_BY_ID);
- scopes.put("table", this.getTableName());
- scopes.put("parameterType", this.persistentEntity.getIdClass().getName());
- scopes.put("resultMap", ResidentStatementName.RESULT_MAP);
- return this.render("GetById", scopes);
- }
-
- private String addFindStatement(boolean pageable) {
- if (this.checkStatement(((pageable) ? ResidentStatementName.FIND_BY_PAGER : ResidentStatementName.FIND))) {
- return "";
- }
- Map scopes = new HashMap<>();
- scopes.put("statementName", pageable ? ResidentStatementName.FIND_BY_PAGER : ResidentStatementName.FIND);
- scopes.put("resultMap", ResidentStatementName.RESULT_MAP);
- scopes.put("table", this.getTableName());
- scopes.put("pageable", pageable);
- if (pageable) {
- scopes.put("limitHandler", this.limitHandler());
- scopes.put("SQLServer2005", this.dialect.getLimitHandler().getClass() == SQLServer2005LimitHandler.class);
- scopes.put("SQLServer2012", this.dialect.getLimitHandler().getClass() == SQLServer2012LimitHandler.class);
- }
- scopes.put("conditionQuery", this.buildByConditionQueryCondition());
- return this.render("Find", scopes);
- }
-
- private String addCountAllStatement() {
- if (this.checkStatement(ResidentStatementName.COUNT_ALL)) {
- return "";
- }
- Map scopes = new HashMap<>();
- scopes.put("statementName", ResidentStatementName.COUNT_ALL);
- scopes.put("table", this.getTableName());
- return this.render("CountAll", scopes);
- }
-
- private String addCountStatement() {
- if (this.checkStatement(ResidentStatementName.COUNT)) {
- return "";
- }
-
- Map scopes = new HashMap<>();
- scopes.put("statementName", ResidentStatementName.COUNT);
- scopes.put("table", this.getTableName());
- scopes.put("conditionQuery", this.buildByConditionQueryCondition());
-
- return this.render("Count", scopes);
- }
-
- private String addQueryByExample() {
- if (this.checkStatement(ResidentStatementName.QUERY_BY_EXAMPLE)) {
- return "";
- }
- Map scopes = new HashMap<>();
- scopes.put("statementName", ResidentStatementName.QUERY_BY_EXAMPLE);
- scopes.put("table", this.getTableName());
- scopes.put("resultMap", ResidentStatementName.RESULT_MAP);
- return this.render("QueryByExample", scopes);
- }
-
- private String addQueryByExampleForPage() {
- if (this.checkStatement(ResidentStatementName.QUERY_BY_EXAMPLE_FOR_PAGE)) {
- return "";
- }
- Map scopes = new HashMap<>();
- scopes.put("statementName", ResidentStatementName.QUERY_BY_EXAMPLE_FOR_PAGE);
- scopes.put("table", this.getTableName());
- scopes.put("resultMap", ResidentStatementName.RESULT_MAP);
- scopes.put("limitHandler", this.limitHandler());
- scopes.put("SQLServer2005", this.dialect.getLimitHandler().getClass() == SQLServer2005LimitHandler.class);
- scopes.put("SQLServer2012", this.dialect.getLimitHandler().getClass() == SQLServer2012LimitHandler.class);
- return this.render("QueryByExampleForPage", scopes);
- }
-
- private String addCountQueryByExample() {
- if (this.checkStatement(ResidentStatementName.COUNT_QUERY_BY_EXAMPLE)) {
- return "";
- }
- Map scopes = new HashMap<>();
- scopes.put("statementName", ResidentStatementName.COUNT_QUERY_BY_EXAMPLE);
- scopes.put("table", this.getTableName());
- return this.render("CountQueryByExample", scopes);
- }
-
- private String addFindByExampleStatement() {
- if (this.configuration.hasStatement(this.namespace + '.' + ResidentStatementName.FIND_BY_EXAMPLE, false)) {
- return "";
- }
-
- Map scopes = new HashMap<>();
- scopes.put("statementName", ResidentStatementName.FIND_BY_EXAMPLE);
- scopes.put("tableName", this.getTableName());
- scopes.put("entityType", this.persistentEntity.getType().getName());
- scopes.put("resultMap", ResidentStatementName.RESULT_MAP);
-
- return this.render("FindByExample", scopes);
- }
-
- private String addFindByExampleWhereClauseSQL() {
- if (this.configuration.getSqlFragments().containsKey(this.namespace + ".__example_where_clause")) {
- return "";
- }
- return this.render("FindByExampleWhereClause", null);
- }
-
- Mustache.Lambda limitHandler() {
- return (frag, out) -> out
- .write(this.dialect.getLimitHandler().processSql(frag.execute(), new RowSelection(true)));
- }
-
- Mustache.Lambda lambdaRegexLike() {
- return (frag, out) -> {
- String[] split = frag.execute().trim().split(";;;");
- out.write(this.dialect.getRegexLikeFunction(split[0].trim(), split[1].trim()));
- };
- }
-
- Mustache.Lambda lambdaReplaceDotToUnderline() {
- return (frag, out) -> out.write(frag.execute().trim().replace('.', '_'));
- }
-
- Mustache.InvertibleLambda lambdaTestNotNull() {
- return new InvertibleLambda() {
- @Override
- public void execute(Fragment frag, Writer out) throws IOException {
- out.write(this.testClause(frag.execute().trim(), true, true));
- }
-
- @Override
- public void executeInverse(Fragment frag, Writer out) throws IOException {
- out.write(this.testClause(frag.execute().trim(), false, false));
- }
-
- protected String testClause(String propertyName, boolean and, boolean not) {
- String[] parts = propertyName.split("\\.");
- String[] conditions = new String[parts.length];
- String prev = null;
- for (int i = 0; i < parts.length; i++) {
- conditions[i] = ((null != prev) ? (prev + ".") : "") + parts[i];
- prev = conditions[i];
- }
- String test = Stream.of(conditions).map(c -> c.trim() + (not ? " !" : " =") + "= null")
- .collect(Collectors.joining(and ? " and " : " or "));
- return test;
- }
- };
- }
-
- private ColumnResult columnResult(MybatisPersistentProperty p) {
- Column column = p.getColumn();
- ColumnResult cr = new ColumnResult();
- cr.setPrimaryKey(p.isIdProperty());
- cr.setColumn(column.getName().render(this.dialect));
- cr.setProperty(p.getName());
- cr.setJavaType(column.getJavaTypeString());
- cr.setJdbcType(column.getJdbcTypeString());
- cr.setTypeHandler(column.getTypeHandlerString());
- return cr;
- }
-
- @Deprecated
- private String buildByConditionQueryCondition() {
-
- String sql = this.findProperties().stream().map(pp -> {
- Set set = new HashSet<>();
- Conditions conditions = pp.findAnnotation(Conditions.class);
- if (null != conditions && conditions.value().length > 0) {
- set.addAll(Arrays.asList(conditions.value()));
- }
- Condition condition = pp.findAnnotation(Condition.class);
- if (null != condition) {
- set.add(condition);
- }
- if (set.isEmpty()) {
- return "";
- }
-
- return set.stream().map(c -> {
- String[] properties = c.properties();
- if (properties.length == 0) {
- properties = new String[] { pp.getName() };
- }
-
- Part.Type type = Part.Type.valueOf(c.type().name());
- if (type.getNumberOfArguments() > 0 && type.getNumberOfArguments() != properties.length) {
- throw new MappingException("@Condition with type " + type + " needs " + type.getNumberOfArguments()
- + " arguments, but only find " + properties.length + " properties in this @Condition.");
- }
- String cond = Stream.of(properties).map(property -> String.format("__condition.%s != null", property))
- .collect(Collectors.joining(" AND "));
- Part.IgnoreCaseType ignoreCaseType = Part.IgnoreCaseType.valueOf(c.ignoreCaseType().name());
- String columnName = StringUtils.hasText(c.column()) ? c.column()
- : pp.getColumn().getName().render(this.dialect);
- String left = this.buildQueryByConditionLeftSegment(columnName, ignoreCaseType, pp);
- String operator = this.buildQueryByConditionOperator(type);
- String right = this.buildQueryByConditionRightSegment(type, ignoreCaseType, properties, pp.getColumn());
- return String.format(" AND %s %s %s", cond, left, operator, right);
- }).collect(Collectors.joining());
- }).collect(Collectors.joining());
- return String.format("%s", sql);
- }
-
-}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisQuery.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisQuery.java
index 600c669acd6dcbeac8713ef22326c460f65a99aa..0efac4cbc7770a9ca1520aa13cf8e3739aefab65 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisQuery.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/SimpleMybatisQuery.java
@@ -30,8 +30,9 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
* MyBatis {@link Query} from it.
*
* @author JARVIS SONG
+ * @since 2.0.0
*/
-final class SimpleMybatisQuery extends AbstractStringBasedMybatisQuery {
+public class SimpleMybatisQuery extends AbstractStringBasedMybatisQuery {
SimpleMybatisQuery(SqlSessionTemplate sqlSessionTemplate, MybatisQueryMethod method, String queryString,
String countQueryString, QueryMethodEvaluationContextProvider evaluationContextProvider,
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/StringQuery.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/StringQuery.java
index a8e162f60975581ab5a5d591193535919ef4c427..a6b3022445a38d314cb673b98968005b232e1012 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/StringQuery.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/query/StringQuery.java
@@ -39,8 +39,9 @@ import org.springframework.util.StringUtils;
* replacing SpEL expressions with synthetic bind parameters.
*
* @author JARVIS SONG
+ * @since 2.0.0
*/
-class StringQuery implements DeclaredQuery {
+public class StringQuery implements DeclaredQuery {
private final String query;
@@ -54,7 +55,7 @@ class StringQuery implements DeclaredQuery {
private final boolean usesJdbcStyleParameters;
- StringQuery(String query) {
+ public StringQuery(String query) {
Assert.hasText(query, "Query must not be null or empty!");
@@ -395,7 +396,7 @@ class StringQuery implements DeclaredQuery {
}
- static class ParameterBinding {
+ public static class ParameterBinding {
private final @Nullable String name;
@@ -435,7 +436,7 @@ class StringQuery implements DeclaredQuery {
return this.name;
}
- String getRequiredName() throws IllegalStateException {
+ public String getRequiredName() throws IllegalStateException {
String name = this.getName();
@@ -447,11 +448,11 @@ class StringQuery implements DeclaredQuery {
}
@Nullable
- Integer getPosition() {
+ public Integer getPosition() {
return this.position;
}
- int getRequiredPosition() throws IllegalStateException {
+ public int getRequiredPosition() throws IllegalStateException {
Integer position = this.getPosition();
@@ -510,7 +511,7 @@ class StringQuery implements DeclaredQuery {
}
- static class InParameterBinding extends ParameterBinding {
+ public static class InParameterBinding extends ParameterBinding {
InParameterBinding(String name, @Nullable String expression) {
super(name, null, expression);
@@ -539,7 +540,7 @@ class StringQuery implements DeclaredQuery {
}
- static class LikeParameterBinding extends ParameterBinding {
+ public static class LikeParameterBinding extends ParameterBinding {
private static final List SUPPORTED_TYPES = Arrays.asList(Part.Type.CONTAINING,
Part.Type.STARTING_WITH, Part.Type.ENDING_WITH, Part.Type.LIKE);
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisMappingContextEntityInformation.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisMappingContextEntityInformation.java
index f1688e491359b80ec34b554c82d4ae5374bc7ae0..9e5594f9f37355f24c0601b42745b63dec484ee2 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisMappingContextEntityInformation.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisMappingContextEntityInformation.java
@@ -18,6 +18,7 @@ package org.springframework.data.mybatis.repository.support;
import org.springframework.data.mybatis.mapping.MybatisMappingContext;
import org.springframework.data.mybatis.mapping.MybatisPersistentEntity;
import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
+import org.springframework.data.mybatis.mapping.model.Model;
import org.springframework.util.Assert;
/**
@@ -34,11 +35,15 @@ public class MybatisMappingContextEntityInformation extends MybatisEntity
private final MybatisPersistentEntity> entity;
+ private final Model model;
+
public MybatisMappingContextEntityInformation(Class domainClass, MybatisMappingContext mappingContext) {
super(domainClass);
Assert.notNull(mappingContext, "MappingContext must not be null.");
- this.entity = mappingContext.getRequiredPersistentEntity(domainClass);
+ // this.entity = mappingContext.getRequiredPersistentEntity(domainClass);
+ this.model = mappingContext.getRequiredModel(domainClass);
+ this.entity = this.model.getMappingEntity();
}
@@ -48,7 +53,7 @@ public class MybatisMappingContextEntityInformation extends MybatisEntity
@Override
public boolean hasCompositeId() {
- return this.entity.hasCompositeId();
+ return this.entity.isCompositePrimaryKey();
}
@Override
@@ -74,7 +79,7 @@ public class MybatisMappingContextEntityInformation extends MybatisEntity
@Override
public String getTableName() {
- return this.entity.getTable().getFullName();
+ return this.model.getTable().toString();
}
@Override
@@ -93,10 +98,7 @@ public class MybatisMappingContextEntityInformation extends MybatisEntity
return super.isNew(entity);
}
Object version = this.entity.getPropertyAccessor(entity).getProperty(this.entity.getRequiredVersionProperty());
- if (null == version) {
- return true;
- }
- return false;
+ return null == version;
}
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactory.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactory.java
index 4d0d77dcd39b459999fafd732fcad0398cde7c54..bfc345a10d6c8c054911de3e005052c363730307 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactory.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactory.java
@@ -24,13 +24,11 @@ import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.dao.InvalidDataAccessApiUsageException;
-import org.springframework.data.mybatis.dialect.Dialect;
import org.springframework.data.mybatis.mapping.MybatisMappingContext;
+import org.springframework.data.mybatis.precompiler.MybatisQueryPrepareProcessor;
import org.springframework.data.mybatis.repository.MybatisExampleRepository;
import org.springframework.data.mybatis.repository.query.EscapeCharacter;
import org.springframework.data.mybatis.repository.query.MybatisQueryLookupStrategy;
-import org.springframework.data.mybatis.repository.query.MybatisQueryPrepareProcessor;
-import org.springframework.data.mybatis.repository.query.MybatisRepositoryPrepareProcessor;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
@@ -58,19 +56,12 @@ public class MybatisRepositoryFactory extends RepositoryFactorySupport {
private final MybatisMappingContext mappingContext;
- private final SqlSessionTemplate sqlSessionTemplate;
-
- private final Dialect dialect;
-
private EntityPathResolver entityPathResolver;
private EscapeCharacter escapeCharacter = EscapeCharacter.DEFAULT;
- public MybatisRepositoryFactory(MybatisMappingContext mappingContext, SqlSessionTemplate sqlSessionTemplate,
- Dialect dialect) {
+ public MybatisRepositoryFactory(MybatisMappingContext mappingContext) {
this.mappingContext = mappingContext;
- this.sqlSessionTemplate = sqlSessionTemplate;
- this.dialect = dialect;
this.entityPathResolver = SimpleEntityPathResolver.INSTANCE;
this.addRepositoryProxyPostProcessor((factory, repositoryInformation) -> {
@@ -79,11 +70,7 @@ public class MybatisRepositoryFactory extends RepositoryFactorySupport {
}
});
- this.addRepositoryProxyPostProcessor(
- new MybatisRepositoryPrepareProcessor(mappingContext, sqlSessionTemplate.getConfiguration(), dialect));
- this.addQueryCreationListener(
- new MybatisQueryPrepareProcessor(mappingContext, sqlSessionTemplate.getConfiguration(), dialect));
-
+ this.addQueryCreationListener(new MybatisQueryPrepareProcessor(mappingContext));
}
private static boolean hasMethodReturningStream(Class> repositoryClass) {
@@ -107,7 +94,8 @@ public class MybatisRepositoryFactory extends RepositoryFactorySupport {
@Override
protected final MybatisRepositoryImplementation, ?> getTargetRepository(RepositoryInformation metadata) {
- MybatisRepositoryImplementation, ?> repository = this.getTargetRepository(metadata, this.sqlSessionTemplate);
+ MybatisRepositoryImplementation, ?> repository = this.getTargetRepository(metadata,
+ this.mappingContext.getSqlSessionTemplate());
repository.setEscapeCharacter(this.escapeCharacter);
return repository;
}
@@ -138,8 +126,8 @@ public class MybatisRepositoryFactory extends RepositoryFactorySupport {
@Override
protected Optional getQueryLookupStrategy(@Nullable QueryLookupStrategy.Key key,
QueryMethodEvaluationContextProvider evaluationContextProvider) {
- return Optional.of(MybatisQueryLookupStrategy.create(this.sqlSessionTemplate, this.mappingContext, key,
- evaluationContextProvider, this.escapeCharacter));
+ return Optional.of(MybatisQueryLookupStrategy.create(this.mappingContext, key, evaluationContextProvider,
+ this.escapeCharacter));
}
@Override
@@ -160,8 +148,7 @@ public class MybatisRepositoryFactory extends RepositoryFactorySupport {
.getEntityInformation(metadata.getDomainType());
Object querydslFragment = this.getTargetRepositoryViaReflection(QuerydslMybatisPredicateExecutor.class,
- entityInformation, this.entityPathResolver, this.mappingContext, this.sqlSessionTemplate,
- this.dialect);
+ entityInformation, this.entityPathResolver, this.mappingContext);
fragments = fragments.append(RepositoryFragment.implemented(querydslFragment));
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactoryBean.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactoryBean.java
index 77b3fc07d004ccf708ee3dd1c46d01119f847b18..8226f050f04770329369ca4da812b2b0a5eab1a2 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactoryBean.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/MybatisRepositoryFactoryBean.java
@@ -15,12 +15,9 @@
*/
package org.springframework.data.mybatis.repository.support;
-import org.mybatis.spring.SqlSessionTemplate;
-
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mapping.context.MappingContext;
-import org.springframework.data.mybatis.dialect.Dialect;
import org.springframework.data.mybatis.mapping.MybatisMappingContext;
import org.springframework.data.mybatis.repository.query.EscapeCharacter;
import org.springframework.data.querydsl.EntityPathResolver;
@@ -44,12 +41,8 @@ import org.springframework.util.Assert;
public class MybatisRepositoryFactoryBean, S, ID>
extends TransactionalRepositoryFactoryBeanSupport {
- private @Nullable SqlSessionTemplate sqlSessionTemplate;
-
private @Nullable MybatisMappingContext mappingContext;
- private @Nullable Dialect dialect;
-
private EntityPathResolver entityPathResolver;
private EscapeCharacter escapeCharacter = EscapeCharacter.DEFAULT;
@@ -66,23 +59,19 @@ public class MybatisRepositoryFactoryBean, S, ID>
@Override
public void afterPropertiesSet() {
Assert.state(null != this.mappingContext, "MybatisMappingContext must not be null!");
- Assert.state(null != this.sqlSessionTemplate, "SqlSessionTemplate must not be null!");
super.afterPropertiesSet();
}
@Override
protected RepositoryFactorySupport doCreateRepositoryFactory() {
- return this.createRepositoryFactory(this.mappingContext, this.sqlSessionTemplate, this.dialect);
+ return this.createRepositoryFactory(this.mappingContext);
}
- private RepositoryFactorySupport createRepositoryFactory(MybatisMappingContext mappingContext,
- SqlSessionTemplate sqlSessionTemplate, Dialect dialect) {
+ private RepositoryFactorySupport createRepositoryFactory(MybatisMappingContext mappingContext) {
Assert.state(null != this.mappingContext, "MybatisMappingContext must not be null!");
- Assert.state(null != this.sqlSessionTemplate, "SqlSessionTemplate must not be null!");
- MybatisRepositoryFactory repositoryFactory = new MybatisRepositoryFactory(mappingContext, sqlSessionTemplate,
- dialect);
+ MybatisRepositoryFactory repositoryFactory = new MybatisRepositoryFactory(mappingContext);
repositoryFactory.setEntityPathResolver(this.entityPathResolver);
repositoryFactory.setEscapeCharacter(this.escapeCharacter);
return repositoryFactory;
@@ -98,17 +87,9 @@ public class MybatisRepositoryFactoryBean, S, ID>
this.escapeCharacter = EscapeCharacter.of(escapeCharacter);
}
- public void setSqlSessionTemplate(@Nullable SqlSessionTemplate sqlSessionTemplate) {
- this.sqlSessionTemplate = sqlSessionTemplate;
- }
-
@Autowired
public void setEntityPathResolver(ObjectProvider resolver) {
this.entityPathResolver = resolver.getIfAvailable(() -> SimpleEntityPathResolver.INSTANCE);
}
- public void setDialect(@Nullable Dialect dialect) {
- this.dialect = dialect;
- }
-
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/Querydsl.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/Querydsl.java
index e982aa48d4e7e3fcc21d8aa68e6eeddfe18bce17..c860a42db58edda2b30396b778682746d744ee13 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/Querydsl.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/Querydsl.java
@@ -43,7 +43,6 @@ import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
-import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mybatis.dialect.Dialect;
import org.springframework.data.mybatis.dialect.H2Dialect;
@@ -54,16 +53,16 @@ import org.springframework.data.mybatis.dialect.SQLServer2012Dialect;
import org.springframework.data.mybatis.dialect.SQLServerDialect;
import org.springframework.data.mybatis.dialect.SQLiteDialect;
import org.springframework.data.mybatis.mapping.MybatisMappingContext;
-import org.springframework.data.mybatis.mapping.MybatisPersistentEntity;
-import org.springframework.data.mybatis.mapping.MybatisPersistentProperty;
import org.springframework.data.mybatis.mapping.handler.DateUnixTimestampTypeHandler;
import org.springframework.data.mybatis.mapping.handler.UnixTimestampDateTypeHandler;
import org.springframework.data.mybatis.mapping.model.Column;
+import org.springframework.data.mybatis.mapping.model.Model;
import org.springframework.data.mybatis.querydsl.MybatisSQLQuery;
import org.springframework.data.mybatis.querydsl.type.DateAsLongType;
import org.springframework.data.mybatis.querydsl.type.LongAsDateType;
import org.springframework.data.querydsl.QSort;
import org.springframework.util.Assert;
+import org.springframework.util.CollectionUtils;
/**
* .
@@ -122,21 +121,20 @@ public class Querydsl {
}
this.configuration = new Configuration(sqlTemplates);
- MybatisPersistentEntity> entity = mappingContext.getRequiredPersistentEntity(entityInformation.getJavaType());
- entity.doWithProperties((PropertyHandler) property -> {
- Column column = property.getColumn();
- if (null == column.getTypeHandler()) {
- return;
- }
- if (column.getTypeHandler() == DateUnixTimestampTypeHandler.class) {
- this.configuration.register(entity.getTable().getName().getText(), column.getName().getText(),
- new DateAsLongType());
- }
- if (column.getTypeHandler() == UnixTimestampDateTypeHandler.class) {
- this.configuration.register(entity.getTable().getName().getText(), column.getName().getText(),
- new LongAsDateType());
- }
- });
+ Model model = mappingContext.getRequiredModel(entityInformation.getJavaType());
+ List columns = model.findColumnByTypeHandler(DateUnixTimestampTypeHandler.class);
+ if (!CollectionUtils.isEmpty(columns)) {
+ DateAsLongType dateAsLongType = new DateAsLongType();
+ columns.stream().forEach(c -> this.configuration.register(model.getTable().getName().getText(),
+ c.getName().getText(), dateAsLongType));
+ }
+ columns = model.findColumnByTypeHandler(UnixTimestampDateTypeHandler.class);
+ if (!CollectionUtils.isEmpty(columns)) {
+ LongAsDateType longAsDateType = new LongAsDateType();
+ columns.stream().forEach(c -> this.configuration.register(model.getTable().getName().getText(),
+ c.getName().getText(), longAsDateType));
+ }
+
}
public AbstractSQLQuery> createQuery() {
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/QuerydslMybatisPredicateExecutor.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/QuerydslMybatisPredicateExecutor.java
index d89b57f9eff6e9a337f69c92111b2330593fa132..93ea3390d0c749acf19354e4a2a508e7d646ea87 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/QuerydslMybatisPredicateExecutor.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/QuerydslMybatisPredicateExecutor.java
@@ -24,13 +24,11 @@ import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.sql.AbstractSQLQuery;
-import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
-import org.springframework.data.mybatis.dialect.Dialect;
import org.springframework.data.mybatis.mapping.MybatisMappingContext;
import org.springframework.data.mybatis.querydsl.MybatisRelationalPathBase;
import org.springframework.data.mybatis.querydsl.MybatisSQLQuery;
@@ -57,10 +55,10 @@ public class QuerydslMybatisPredicateExecutor implements QuerydslPredicate
private FactoryExpression bean;
public QuerydslMybatisPredicateExecutor(MybatisEntityInformation entityInformation,
- EntityPathResolver resolver, MybatisMappingContext mappingContext, SqlSessionTemplate sqlSessionTemplate,
- Dialect dialect) {
+ EntityPathResolver resolver, MybatisMappingContext mappingContext) {
this.path = (MybatisRelationalPathBase) resolver.createPath(entityInformation.getJavaType());
- this.querydsl = new Querydsl<>(sqlSessionTemplate, mappingContext, dialect, entityInformation,
+ this.querydsl = new Querydsl<>(mappingContext.getSqlSessionTemplate(), mappingContext,
+ mappingContext.getDialect(), entityInformation,
new PathBuilder<>(this.path.getType(), this.path.getMetadata()));
this.bean = this.path.projections();
}
diff --git a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/ResidentStatementName.java b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/ResidentStatementName.java
index 0c49364a529fba05a25ffc1202bdc39b0360aac2..8840c405876f90269b613f63145ba97a8267f18c 100644
--- a/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/ResidentStatementName.java
+++ b/spring-data-mybatis/src/main/java/org/springframework/data/mybatis/repository/support/ResidentStatementName.java
@@ -36,10 +36,30 @@ public final class ResidentStatementName {
*/
public static final String RESULT_MAP = PREFIX + "result_map";
+ /**
+ * For __basic_result_map.
+ */
+ public static final String BASIC_RESULT_MAP = PREFIX + "basic_result_map";
+
/**
* For __result_map_.
*/
- public static final String RESULT_MAP_PREFIX = PREFIX + "__result_map_";
+ public static final String RESULT_MAP_PREFIX = PREFIX + "result_map_";
+
+ /**
+ * For __basic_column_list.
+ */
+ public static final String BASIC_COLUMN_LIST = PREFIX + "basic_column_list";
+
+ /**
+ * For __from.
+ */
+ public static final String FROM = PREFIX + "from";
+
+ /**
+ * For __select.
+ */
+ public static final String SELECT = PREFIX + "select";
/**
* For __get_by_id.
@@ -56,6 +76,11 @@ public final class ResidentStatementName {
*/
public static final String COUNT_ALL = PREFIX + "count_all";
+ /**
+ * For __delete.
+ */
+ public static final Object DELETE = PREFIX + "delete";
+
/**
* For __delete_by_id.
*/
@@ -191,6 +216,16 @@ public final class ResidentStatementName {
*/
public static final String BASE_COLUMN_LIST = PREFIX + "base_column_list";
+ /**
+ * For __all_column_list.
+ */
+ public static final String ALL_COLUMN_LIST = PREFIX + "all_column_list";
+
+ /**
+ * For __column_list.
+ */
+ public static final String COLUMN_LIST = PREFIX + "column_list";
+
public static String statementName(String namespace, String statement) {
return namespace + '.' + statement;
}
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/config/spring-mybatis-2.0.xsd b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/config/spring-mybatis-2.0.xsd
index 7191835bd0f22803350bc5b0811257edf38f3cc6..c65359095175a0ad9944585457544f577eb331c7 100644
--- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/config/spring-mybatis-2.0.xsd
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/config/spring-mybatis-2.0.xsd
@@ -11,6 +11,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -36,9 +69,7 @@
-
+ type="org.springframework.data.mybatis.auditing.MybatisAuditingHandler"/>
@@ -58,6 +89,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{#domain}}
+ {{#primaryKey}}{{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}}{{/primaryKey}}
+ {{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}}
+ {{#embeddedDomains}}
+ {{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}}
+ {{/embeddedDomains}}
+ {{#oneToOneAssociations}}
+ {{#leftJoin}}
+ {{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}}
+ {{/leftJoin}}
+ {{/oneToOneAssociations}}
+ {{#manyToOneAssociations}}
+ {{#leftJoin}}
+ {{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}}
+ {{/leftJoin}}
+ {{/manyToOneAssociations}}
+ {{/domain}}
+
+
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeDelete.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeDelete.mustache
new file mode 100644
index 0000000000000000000000000000000000000000..62c74f142587371709802db656f0c193caa6871e
--- /dev/null
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeDelete.mustache
@@ -0,0 +1,14 @@
+
+ {{#ass}}
+ {{#joinTable}}DELETE {{table}}
+
+ {{#joinColumns}}
+ AND {{local.name}} = #{ {{local.name}} }
+ {{/joinColumns}}
+ {{#inverseJoinColumns}}
+ AND {{local.name}} = #{ {{local.name}} }
+ {{/inverseJoinColumns}}
+
+ {{/joinTable}}
+ {{/ass}}
+
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeInsert.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeInsert.mustache
new file mode 100644
index 0000000000000000000000000000000000000000..45cda9ca28f84f6a2d2ab9c9f699fd868c6df932
--- /dev/null
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeInsert.mustache
@@ -0,0 +1,11 @@
+
+ {{#ass}}
+ {{#joinTable}}INSERT INTO {{table}} (
+ {{#joinColumns}}{{^-first}}, {{/-first}}{{local.name}}{{/joinColumns}}
+ {{#inverseJoinColumns}}, {{local.name}}{{/inverseJoinColumns}}
+ ) VALUES (
+ {{#joinColumns}}{{^-first}}, {{/-first}}#{ {{local.name}} }{{/joinColumns}}
+ {{#inverseJoinColumns}}, #{ {{local.name}} }{{/inverseJoinColumns}}
+ ){{/joinTable}}
+ {{/ass}}
+
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeUpdate.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeUpdate.mustache
new file mode 100644
index 0000000000000000000000000000000000000000..f4760aa12780e9b82df6540f2b6a23a58b15d3de
--- /dev/null
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/AssociativeUpdate.mustache
@@ -0,0 +1,17 @@
+
+ {{#ass}}
+ {{#joinTable}}UPDATE {{table}}
+ SET
+ {{#joinColumns}}{{^-first}}, {{/-first}}{{local.name}} = #{ {{local.name}} }{{/joinColumns}}
+ {{#inverseJoinColumns}}{{local.name}} = #{ {{local.name}} }{{/inverseJoinColumns}}
+
+ {{#joinColumns}}
+ AND {{local.name}} = #{ {{local.name}} }
+ {{/joinColumns}}
+ {{#inverseJoinColumns}}
+ AND {{local.name}} = #{ {{local.name}} }
+ {{/inverseJoinColumns}}
+
+ {{/joinTable}}
+ {{/ass}}
+
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/BasicColumnList.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/BasicColumnList.mustache
new file mode 100644
index 0000000000000000000000000000000000000000..50c38d11d1e21e821eb8a0157af3124619864930
--- /dev/null
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/BasicColumnList.mustache
@@ -0,0 +1,14 @@
+
+
+ {{#domain}}
+ {{#primaryKey}}{{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}}{{/primaryKey}}
+ {{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}}
+ {{#embeddedDomains}}
+ {{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}}
+ {{/embeddedDomains}}
+ {{#manyToOneAssociations}}
+ {{#columns}}{{#quote}}{{alias}}{{/quote}}.{{name}},{{/columns}}
+ {{/manyToOneAssociations}}
+ {{/domain}}
+
+
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/BasicResultMap.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/BasicResultMap.mustache
new file mode 100644
index 0000000000000000000000000000000000000000..283af95cddbd90a135a088def4a57b7ca0e824a8
--- /dev/null
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/BasicResultMap.mustache
@@ -0,0 +1,32 @@
+{{#domain}}
+
+{{#primaryKey}}{{#columns}}
+
+{{/columns}}{{/primaryKey}}
+{{#columns}}
+
+{{/columns}}
+{{#embeddedDomains}}
+
+ {{#primaryKey}}
+
+ {{/primaryKey}}
+ {{#columns}}
+
+ {{/columns}}
+
+{{/embeddedDomains}}
+{{#manyToOneAssociations}}
+
+
+{{/manyToOneAssociations}}
+{{#oneToOneAssociations}}
+
+
+{{/oneToOneAssociations}}
+{{#oneToManyAssociations}}
+
+
+{{/oneToManyAssociations}}
+
+{{/domain}}
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ColumnList.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ColumnList.mustache
new file mode 100644
index 0000000000000000000000000000000000000000..eb692e6fc71ca17257f01d59cc49f9a10e795c8e
--- /dev/null
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/ColumnList.mustache
@@ -0,0 +1,26 @@
+
+
+ {{#domain}}
+ {{#primaryKey}}{{#columns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/columns}}{{/primaryKey}}
+ {{#normalColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/normalColumns}}
+ {{#versionColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/versionColumns}}
+ {{#embeddings}}
+ {{#primaryKey}}{{#columns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/columns}}{{/primaryKey}}
+ {{#normalColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/normalColumns}}
+ {{#versionColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/versionColumns}}
+ {{/embeddings}}
+ {{#manyToOneAssociations}}
+ {{#leftJoin}}
+ {{#normalColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/normalColumns}}
+ {{#versionColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/versionColumns}}
+ {{#embeddings}}
+ {{#primaryKey}}{{#columns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/columns}}{{/primaryKey}}
+ {{#normalColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/normalColumns}}
+ {{#versionColumns}}{{#quote}}{{tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{columnAlias}}{{/quote}}, {{/versionColumns}}
+ {{/embeddings}}
+ {{/leftJoin}}
+ {{^leftJoin}}{{#foreignKey}}{{#columns}}{{#local}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{name}} AS {{#quote}}{{name}}{{/quote}}, {{/local}}{{/columns}}{{/foreignKey}}{{/leftJoin}}
+ {{/manyToOneAssociations}}
+ {{/domain}}
+
+
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Count.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Count.mustache
index 9f49736b079e620477c086fcddaff509ac2e9f09..3c32a507a7a9c742260ac16d7d6da94ea90ff157 100644
--- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Count.mustache
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Count.mustache
@@ -1,4 +1,3 @@
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountAll.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountAll.mustache
index ab3acdf402695271c3599ee4f728dc82d149bbe5..d79dd422cd7fe503604eaaadecbd36368f8fa1b0 100644
--- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountAll.mustache
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountAll.mustache
@@ -1 +1,5 @@
-
+
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountQueryByExample.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountQueryByExample.mustache
index 35b3f87b5c3425315ee2c27725c0eeaef3d52cb1..f037bef992e3bf5377818f3d4cdf7ec1b7099977 100644
--- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountQueryByExample.mustache
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/CountQueryByExample.mustache
@@ -1,4 +1,4 @@
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteAll.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteAll.mustache
index 4b880b7bd90eee51b97c4734155d8d7f3cc6f412..5e59032fc7d8d3b5d51049f8408f94416683e504 100644
--- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteAll.mustache
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteAll.mustache
@@ -1,3 +1,5 @@
-
- DELETE FROM {{table}}
-
+{{#domain}}
+
+ DELETE FROM {{table}}
+
+{{/domain}}
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteById.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteById.mustache
index 0be7c37d92fc266f132670c966bdff0629476bba..98e761b3d814c292868e36459f863c3f7f81544d 100644
--- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteById.mustache
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteById.mustache
@@ -1,6 +1,12 @@
-
- DELETE FROM {{table}}
-
-
-
-
+{{#domain}}{{#primaryKey}}
+
+ DELETE FROM {{table}}
+
+ {{#columns}}
+ AND {{name}} = {{#composited}}#{ {{property.name}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} }{{/composited}}
+ {{^composited}}#{_parameter}{{/composited}}
+ {{/columns}}
+
+
+{{/primaryKey}}
+{{/domain}}
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteByIds.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteByIds.mustache
index 857a065c9c9ba310499a4631ef45b2fb0fde4ebd..a9a1bc7431f6d9e9525eb6113d58479614c4ae97 100644
--- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteByIds.mustache
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/DeleteByIds.mustache
@@ -1,6 +1,33 @@
-
- DELETE FROM {{table}}
-
-
-
-
+{{#domain}}
+
+ DELETE FROM {{table}}
+
+
+
+ {{#primaryKey}}
+ {{^composited}}
+ {{#columns}}
+ {{name}} IN
+
+ #{item}
+
+ {{/columns}}
+ {{/composited}}
+ {{#composited}}
+
+ {{#columns}}
+ {{^-first}} AND {{/-first}}
+ {{name}} = #{ item.{{property.name}} }
+ {{/columns}}
+
+ {{/composited}}
+ {{/primaryKey}}
+
+
+
+
+{{/domain}}
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Find.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Find.mustache
index 013901b89c927f7b7ae7e31ee1597f43f5b0edce..47d7346e83cebb9157cfee3f25f21f0332ee2d86 100644
--- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Find.mustache
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Find.mustache
@@ -1,57 +1,8 @@
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Find2.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Find2.mustache
new file mode 100644
index 0000000000000000000000000000000000000000..013901b89c927f7b7ae7e31ee1597f43f5b0edce
--- /dev/null
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Find2.mustache
@@ -0,0 +1,57 @@
+
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/FindByPage.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/FindByPage.mustache
new file mode 100644
index 0000000000000000000000000000000000000000..56f7589f6a752e0ea55e552dd5f71d7fc281869f
--- /dev/null
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/FindByPage.mustache
@@ -0,0 +1,48 @@
+
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/From.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/From.mustache
new file mode 100644
index 0000000000000000000000000000000000000000..36866137c4dcea631c27fbf6f2f58a04901c5afb
--- /dev/null
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/From.mustache
@@ -0,0 +1,21 @@
+
+{{#domain}}
+ {{table}} {{#quote}}{{tableAlias}}{{/quote}}
+ {{#oneToOneAssociations}}
+ {{#leftJoin}}
+ LEFT JOIN {{table}} {{#quote}}{{tableAlias}}{{/quote}} ON
+ {{#foreignKey}}
+ {{#columns}}{{#local}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{name}}{{/local}} = {{#foreign}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{name}}{{/foreign}}{{/columns}}
+ {{/foreignKey}}
+ {{/leftJoin}}
+ {{/oneToOneAssociations}}
+ {{#manyToOneAssociations}}
+ {{#leftJoin}}
+ LEFT JOIN {{table}} {{#quote}}{{tableAlias}}{{/quote}} ON
+ {{#foreignKey}}
+ {{#columns}}{{#local}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{name}}{{/local}} = {{#foreign}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{name}}{{/foreign}}{{/columns}}
+ {{/foreignKey}}
+ {{/leftJoin}}
+ {{/manyToOneAssociations}}
+{{/domain}}
+
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/GetById.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/GetById.mustache
index 49b03ee99a969c7748a00059fa8dbb5c8edc27d8..6e59a5c73ecd3bcf17a14b4111f641ceb1a2192a 100644
--- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/GetById.mustache
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/GetById.mustache
@@ -1,7 +1,10 @@
-
+{{/domain}}
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Insert.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Insert.mustache
index b386abd4b8fa51caec8d352ca8b13f87eaf4e63b..da176d6e7c70c9036e3dce5a395db248090c3309 100644
--- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Insert.mustache
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Insert.mustache
@@ -1,42 +1,74 @@
-
- {{#useGeneratedKeys}}
- {{keySql}}
- {{/useGeneratedKeys}}
- INSERT INTO {{table}}
-
- {{#properties}}
- {{#selective}}
-
- {{/selective}}
- {{^excludeId}}
- {{value.name}},
- {{/excludeId}}
- {{#excludeId}}
- {{^value.primaryKey}}{{value.name}},{{/value.primaryKey}}
- {{/excludeId}}
- {{#selective}}{{/selective}}
- {{/properties}}
-
-
- {{#properties}}
- {{#selective}}
-
- {{/selective}}
- {{^excludeId}}
- #{ {{key}}{{#value.jdbcType}}
- ,jdbcType={{value.jdbcType}}{{/value.jdbcType}}{{#value.typeHandler}}
- ,typeHandler={{value.typeHandler.name}}{{/value.typeHandler}} },
- {{/excludeId}}
- {{#excludeId}}
- {{^value.primaryKey}}#{ {{key}}{{#value.jdbcType}}
- ,jdbcType={{value.jdbcType}}{{/value.jdbcType}}{{#value.typeHandler}}
- ,typeHandler={{value.typeHandler.name}}{{/value.typeHandler}}
- },{{/value.primaryKey}}
- {{/excludeId}}
- {{#selective}}{{/selective}}
- {{/properties}}
-
-
+{{#domain}}
+
+ {{#primaryKey}}
+ {{#generatedKeys}}
+ {{#columns}}
+ {{keySql}}
+ {{/columns}}
+ {{/generatedKeys}}
+ {{/primaryKey}}
+ INSERT INTO {{table}}
+
+ {{#primaryKey}}
+ {{^excludeInsertId}}
+ {{#columns}}{{name}},{{/columns}}
+ {{/excludeInsertId}}
+ {{/primaryKey}}
+ {{#normalColumns}}{{name}},{{/normalColumns}}
+ {{#versionColumns}}{{name}},{{/versionColumns}}
+ {{#embeddings}}
+
+ {{#primaryKey}}{{#columns}}{{name}},{{/columns}}{{/primaryKey}}
+ {{#normalColumns}}{{name}},{{/normalColumns}}
+ {{#verionColumns}}{{name}},{{/verionColumns}}
+
+ {{/embeddings}}
+ {{#oneToOneAssociations}}
+
+ {{#foreignKey}}
+ {{#columns}}{{#local}}{{name}},{{/local}}{{/columns}}
+ {{/foreignKey}}
+
+ {{/oneToOneAssociations}}
+ {{#manyToOneAssociations}}
+
+ {{#foreignKey}}
+ {{#columns}}{{#local}}{{name}},{{/local}}{{/columns}}
+ {{/foreignKey}}
+
+ {{/manyToOneAssociations}}
+
+
+ {{#primaryKey}}
+ {{^excludeInsertId}}
+ {{#columns}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/columns}}
+ {{/excludeInsertId}}
+ {{/primaryKey}}
+ {{#normalColumns}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/normalColumns}}
+ {{#versionColumns}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/versionColumns}}
+ {{#embeddings}}
+
+ {{#primaryKey}}{{#columns}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/columns}}{{/primaryKey}}
+ {{#normalColumns}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/normalColumns}}
+ {{#versionColumns}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/versionColumns}}
+
+ {{/embeddings}}
+ {{#oneToOneAssociations}}
+
+ {{#foreignKey}}
+ {{#columns}}{{#foreign}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/foreign}}{{/columns}}
+ {{/foreignKey}}
+
+ {{/oneToOneAssociations}}
+ {{#manyToOneAssociations}}
+
+ {{#foreignKey}}
+ {{#columns}}{{#foreign}}#{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },{{/foreign}}{{/columns}}
+ {{/foreignKey}}
+
+ {{/manyToOneAssociations}}
+
+
+{{/domain}}
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/InsertSelective.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/InsertSelective.mustache
new file mode 100644
index 0000000000000000000000000000000000000000..c642fc53761391769596340f5973a100cd765887
--- /dev/null
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/InsertSelective.mustache
@@ -0,0 +1,136 @@
+{{#domain}}
+
+ {{#primaryKey}}
+ {{#generatedKeys}}
+ {{#columns}}
+ {{keySql}}
+ {{/columns}}
+ {{/generatedKeys}}
+ {{/primaryKey}}
+ INSERT INTO {{table}}
+
+ {{#primaryKey}}
+ {{^excludeInsertId}}
+ {{#columns}}
+
+ {{name}},
+ {{/columns}}
+ {{/excludeInsertId}}
+ {{/primaryKey}}
+ {{#normalColumns}}
+ {{name}},
+ {{/normalColumns}}
+ {{#versionColumns}}
+ {{name}},
+ {{/versionColumns}}
+ {{#embeddings}}
+ {{#primaryKey}}
+ {{#columns}}
+
+ {{name}},
+
+ {{/columns}}
+ {{/primaryKey}}
+ {{#normalColumns}}
+
+ {{name}},
+
+ {{/normalColumns}}
+ {{#versionColumns}}
+
+ {{name}},
+
+ {{/versionColumns}}
+ {{/embeddings}}
+ {{#oneToOneAssociations}}
+ {{#foreignKey}}
+ {{#columns}}{{#local}}{{name}},{{/local}}{{/columns}}
+ {{/foreignKey}}
+ {{/oneToOneAssociations}}
+ {{#manyToOneAssociations}}
+ {{#foreignKey}}
+ {{#columns}}{{#local}}{{name}},{{/local}}{{/columns}}
+ {{/foreignKey}}
+ {{/manyToOneAssociations}}
+
+
+ {{#primaryKey}}
+ {{^excludeInsertId}}
+ {{#columns}}
+
+ #{ {{propertyName}}{{#javaType}}
+ ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}}
+ ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}}
+ ,typeHandler={{typeHandler.name}}{{/typeHandler}} },
+
+ {{/columns}}
+ {{/excludeInsertId}}
+ {{/primaryKey}}
+ {{#normalColumns}}
+
+ #{ {{propertyName}}{{#javaType}}
+ ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}}
+ ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}}
+ ,typeHandler={{typeHandler.name}}{{/typeHandler}} },
+
+ {{/normalColumns}}
+ {{#versionColumns}}
+
+ #{ {{propertyName}}{{#javaType}}
+ ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}}
+ ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}}
+ ,typeHandler={{typeHandler.name}}{{/typeHandler}} },
+
+ {{/versionColumns}}
+ {{#embeddings}}
+ {{#primaryKey}}
+ {{#columns}}
+
+ #{ {{propertyName}}{{#javaType}}
+ ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}}
+ ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}}
+ ,typeHandler={{typeHandler.name}}{{/typeHandler}}
+ },
+
+ {{/columns}}
+ {{/primaryKey}}
+ {{#normalColumns}}
+
+ #{ {{propertyName}}{{#javaType}}
+ ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}}
+ ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}}
+ ,typeHandler={{typeHandler.name}}{{/typeHandler}} },
+
+ {{/normalColumns}}
+ {{#versionColumns}}
+
+ #{ {{propertyName}}{{#javaType}}
+ ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}}
+ ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}}
+ ,typeHandler={{typeHandler.name}}{{/typeHandler}} },
+
+ {{/versionColumns}}
+ {{/embeddings}}
+ {{#oneToOneAssociations}}
+ {{#foreignKey}}
+ {{#columns}}{{#foreign}}
+
+ #{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },
+
+ {{/foreign}}{{/columns}}
+ {{/foreignKey}}
+ {{/oneToOneAssociations}}
+ {{#manyToOneAssociations}}
+ {{#foreignKey}}
+ {{#columns}}{{#foreign}}
+
+ #{ {{propertyName}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}} },
+
+ {{/foreign}}{{/columns}}
+ {{/foreignKey}}
+ {{/manyToOneAssociations}}
+
+
+{{/domain}}
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Mapper.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Mapper.mustache
new file mode 100644
index 0000000000000000000000000000000000000000..6a3d0f4c4c1d8992e4c2a31349844e601c74ddbe
--- /dev/null
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/Mapper.mustache
@@ -0,0 +1,6 @@
+
+
+
+
+ {{#statements}}{{.}}{{/statements}}
+
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeCondition.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeCondition.mustache
index a67def57083c2dbf84870099dda84dbe0fd29258..dd6c9909d5271b79c4df6a0c5711953dcf945277 100644
--- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeCondition.mustache
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeCondition.mustache
@@ -1,12 +1,12 @@
{{#tree}}
{{^-first}} OR {{/-first}}
(
- {{#parts}}
+ {{#this}}
{{^-first}} AND {{/-first}}
{{^opIn}}
{{^opNotIn}}
- {{#ignoreCase}}{{lowercaseFunction}}({{column.name}}){{/ignoreCase}}
- {{^ignoreCase}}{{column.name}}{{/ignoreCase}}
+ {{#ignoreCase}}{{lowercaseFunction}}({{#column}}{{#includeAlias}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{/includeAlias}}{{name}}{{/column}}){{/ignoreCase}}
+ {{^ignoreCase}}{{#column}}{{#includeAlias}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{/includeAlias}}{{name}}{{/column}}{{/ignoreCase}}
{{/opNotIn}}
{{/opIn}}
{{#opBetween}}
@@ -48,18 +48,17 @@
{{#opIn}}
- {{#ignoreCase}}{{lowercaseFunction}}({{column.name}}){{/ignoreCase}}
- {{^ignoreCase}}{{column.name}}{{/ignoreCase}}
+ {{#ignoreCase}}{{lowercaseFunction}}({{#column}}{{#includeAlias}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{/includeAlias}}{{name}}{{/column}}){{/ignoreCase}}
+ {{^ignoreCase}}{{#column}}{{#includeAlias}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{/includeAlias}}{{name}}{{/column}}{{/ignoreCase}}
IN
#{__item
- {{#column.hasJavaType}}
- ,javaType={{column.javaTypeString}}
- {{/column.hasJavaType}}
- {{#column.hasTypeHandler}}
- ,typeHandler={{column.typeHandlerString}}
- {{/column.hasTypeHandler}} }
+ {{#column}}{{#javaType}}
+ ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}}
+ ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}}
+ ,typeHandler={{typeHandler.name}}{{/typeHandler}}{{/column}}
+ }
0=1
@@ -68,18 +67,17 @@
{{#opNotIn}}
- {{#ignoreCase}}{{lowercaseFunction}}({{column.name}}){{/ignoreCase}}
- {{^ignoreCase}}{{column.name}}{{/ignoreCase}}
+ {{#ignoreCase}}{{lowercaseFunction}}({{#column}}{{#includeAlias}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{/includeAlias}}{{name}}{{/column}}){{/ignoreCase}}
+ {{^ignoreCase}}{{#column}}{{#includeAlias}}{{#quote}}{{model.tableAlias}}{{/quote}}.{{/includeAlias}}{{name}}{{/column}}{{/ignoreCase}}
NOT IN
#{__item
- {{#column.hasJavaType}}
- ,javaType={{column.javaTypeString}}
- {{/column.hasJavaType}}
- {{#column.hasTypeHandler}}
- ,typeHandler={{column.typeHandlerString}}
- {{/column.hasTypeHandler}} }
+ {{#column}}{{#javaType}}
+ ,javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}}
+ ,jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}}
+ ,typeHandler={{typeHandler.name}}{{/typeHandler}}{{/column}}
+ }
0=1
@@ -102,14 +100,10 @@
{{/ignoreCase}}
{{^ignoreCase}}
#{ {{#arguments}}{{.}}{{/arguments}}
- {{#column.hasJavaType}}
- ,javaType={{column.javaTypeString}}
- {{/column.hasJavaType}}
- {{#column.hasTypeHandler}}
- ,typeHandler={{column.typeHandlerString}}
- {{/column.hasTypeHandler}} }
+ {{#column}}{{#javaType}},javaType={{javaTypeString}}{{/javaType}}{{#jdbcType}},jdbcType={{jdbcType.name}}{{/jdbcType}}{{#typeHandler}},typeHandler={{typeHandler.name}}{{/typeHandler}}{{/column}}
+ }
{{/ignoreCase}}
{{/opDefault}}
- {{/parts}}
+ {{/this}}
)
{{/tree}}
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeDelete.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeDelete.mustache
index 4f378cdc482d7df6e932eb7d1c91f1127dcb5607..fe734c9c5b19b02f0612835c2ab5cd5e0662a7bf 100644
--- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeDelete.mustache
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeDelete.mustache
@@ -1,5 +1,5 @@
- DELETE FROM {{table}}
+ DELETE FROM {{domain.table}}
{{>PartTreeCondition}}
diff --git a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeCount.mustache b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeInnerCount.mustache
similarity index 80%
rename from spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeCount.mustache
rename to spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeInnerCount.mustache
index 54c970dfde6fa67c82537b2793f0891ca0420b39..cc9631f9f073c9ec4cb1dc9d107a067b4058963a 100644
--- a/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeCount.mustache
+++ b/spring-data-mybatis/src/main/resources/org/springframework/data/mybatis/repository/query/template/PartTreeInnerCount.mustache
@@ -1,4 +1,4 @@
-