Skip to content

Commit

Permalink
Add SQL provider class that help detecting a template file automatically
Browse files Browse the repository at this point in the history
  • Loading branch information
kazuki43zoo committed Apr 14, 2019
1 parent 18cd409 commit cf8bccc
Show file tree
Hide file tree
Showing 21 changed files with 779 additions and 3 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ jdk:
- oraclejdk8

script:
# build using mybatis latest version
# build using mybatis latest released version
- ./mvnw clean verify
# build using mybatis 3.4.x line
- ./mvnw clean verify -Dmybatis.version=3.4.6
# test using mybatis 3.4.x line
- ./mvnw test -Dmybatis.version=3.4.6
# build using mybatis 3.5.x snapshot
- ./mvnw clean verify -Dmybatis.version=3.5.2-SNAPSHOT

Expand Down
12 changes: 12 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@
</dependencies>

<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<mybatis.version>${mybatis.version}</mybatis.version>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.asciidoctor</groupId>
Expand Down
65 changes: 65 additions & 0 deletions src/main/asciidoc/user-guide.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -963,6 +963,71 @@ using <<Configuration properties, Configuration properties>>.
AND firstName LIKE #{patternFirstName} ESCAPE '\'
----

== Support classes

We provides useful classes for supporting development.

=== TemplateFilePathProvider

The `TemplateFilePathProvider` is SQL provider class that return the SQL template file path(Available since 1.0.1).
This class use with SQL provider annotation(`@InsertProvider`, `@UpdateProvider`, `@DeleteProvider` and `@SelectProvider`}) as follow:

[NOTE]
====
**This class required to use on MyBatis 3.5.1+.**
====

.Usage:

[source, java]
----
package com.example.mapper;
public interface BaseMapper<T> {
@Options(useGeneratedKeys = true, keyProperty = "id")
@InsertProvider(type = TemplateFilePathProvider.class)
void insert(T entity);
@UpdateProvider(type = TemplateFilePathProvider.class)
void update(T entity);
@DeleteProvider(type = TemplateFilePathProvider.class)
void delete(T entity);
@SelectProvider(type = TemplateFilePathProvider.class)
T findById(Integer id);
}
----

[source, java]
----
package com.example.mapper;
public interface NameMapper extends BaseMapper {
@SelectProvider(type = TemplateFilePathProvider.class)
List<Name> findByCondition(NameCondition condition);
}
----

By default implementation, a template file path resolve following format and priority order.
If does not match all, it throw an exception that indicate not found a template file.

* `com/example/mapper/NameMapper-{methodName}-{databaseId}.sql`
* `com/example/mapper/NameMapper-{methodName}.sql` +
(fallback using default database)
* `com/example/mapper/BaseMapper-{methodName}-{databaseId}.sql` +
(fallback using declaring class of mapper method)
* `com/example/mapper/BaseMapper-{methodName}.sql` +
(fallback using declaring class of mapper method and default database)

If you want to customize the template file path format(e.g. `com/example/mapper/NameMapper/{methodName}-{databaseId}.sql`),
please specify a custom implementation of the `TemplateFilePathGenerator`
using `TemplateFilePathProvider#setCustomTemplateFilePathGenerator` method **before initialize the MyBatis module**.


== Cautions for usage

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/**
* Copyright 2018-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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mybatis.scripting.thymeleaf.support;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Optional;

import org.apache.ibatis.builder.annotation.ProviderContext;
import org.apache.ibatis.io.Resources;

/**
* The SQL provider class that return the SQL template file path. <br>
* <b>IMPORTANT: This class required to use with mybatis 3.5.1+</b> and need to use with SQL provider annotation (such
* as {@link org.apache.ibatis.annotations.SelectProvider} as follow: <br>
* <br>
*
* <pre>
* package com.example.mapper;
*
* public interface BaseMapper&lt;T&gt; {
*
* &#64;Options(useGeneratedKeys = true, keyProperty = "id")
* &#64;InsertProvider(type = TemplateFilePathProvider.class)
* void insert(T entity);
*
* &#64;UpdateProvider(type = TemplateFilePathProvider.class)
* void update(T entity);
*
* &#64;DeleteProvider(type = TemplateFilePathProvider.class)
* void delete(T entity);
*
* &#64;SelectProvider(type = TemplateFilePathProvider.class)
* T findById(Integer id);
*
* }
* </pre>
*
* <pre>
* package com.example.mapper;
*
* public interface NameMapper extends BaseMapper {
*
* &#64;SelectProvider(type = TemplateFilePathProvider.class)
* List&lt;Name&gt; findByConditions(NameConditions conditions);
*
* }
* </pre>
*
* @author Kazuki Shimizu
* @version 1.0.1
*/
public class TemplateFilePathProvider {

private static TemplateFilePathGenerator generator = TemplateFilePathProvider::generatePath;

/**
* Set custom implementation for {@link TemplateFilePathGenerator}.
*
* @param customGenerator
* a instance for generating a template file path
*/
public static void setCustomTemplateFilePathGenerator(TemplateFilePathGenerator customGenerator) {
generator = Optional.ofNullable(customGenerator).orElse(TemplateFilePathProvider::generatePath);
}

/**
* Provide an SQL scripting string(template file path).
*
* <br>
* By default implementation, a template file path resolve following format and priority order. If does not match all,
* it throw an exception that indicate not found a template file.
* <ul>
* <li>com/example/mapper/NameMapper-{methodName}-{databaseId}.sql</li>
* <li>com/example/mapper/NameMapper-{methodName}.sql (fallback using default database)</li>
* <li>com/example/mapper/BaseMapper-{methodName}-{databaseId}.sql (fallback using declaring class of method)</li>
* <li>com/example/mapper/BaseMapper-{methodName}.sql (fallback using declaring class of method and default
* database)</li>
* </ul>
* <br>
* If you want to customize path format, please call the
* {@link #setCustomTemplateFilePathGenerator(TemplateFilePathGenerator)} on application initialize phase.
*
* @param context
* a context of SQL provider
* @return an SQL scripting string(template file path)
*/
public static String provideSql(ProviderContext context) {
return providePath(context.getMapperType(), context.getMapperMethod(), context.getDatabaseId());
}

static String providePath(Class<?> mapperType, Method mapperMethod, String databaseId) {
boolean fallbackDeclaringClass = mapperType != mapperMethod.getDeclaringClass();
boolean fallbackDatabase = databaseId != null;
String path = generator.generatePath(mapperType, mapperMethod, databaseId);
if (exists(path)) {
return path;
}
if (fallbackDatabase) {
path = generator.generatePath(mapperType, mapperMethod, null);
if (exists(path)) {
return path;
}
}
if (fallbackDeclaringClass) {
path = generator.generatePath(mapperMethod.getDeclaringClass(), mapperMethod, databaseId);
if (exists(path)) {
return path;
}
}
if (fallbackDatabase) {
path = generator.generatePath(mapperMethod.getDeclaringClass(), mapperMethod, null);
if (exists(path)) {
return path;
}
}
throw new IllegalStateException("The SQL template file not found. mapperType:[" + mapperType + "] mapperMethod:["
+ mapperMethod + "] databaseId:[" + databaseId + "]");
}

private static String generatePath(Class<?> type, Method method, String databaseId) {
StringBuilder path = new StringBuilder();
path.append(type.getName().replace('.', '/'));
path.append("-").append(method.getName());
if (databaseId != null) {
path.append("-").append(databaseId);
}
path.append(".sql");
return path.toString();
}

private static boolean exists(String path) {
try {
return Resources.getResourceAsFile(path).exists();
} catch (IOException e) {
return false;
}
}

/**
* The interface that implements a function for generating template file path.
*/
@FunctionalInterface
public interface TemplateFilePathGenerator {

/**
* Generate a template file path.
*
* @param type
* mapper interface type that specified provider (or declaring interface type of mapper method)
* @param method
* a mapper method that specified provider
* @param databaseId
* a database id that provided from {@link org.apache.ibatis.mapping.DatabaseIdProvider}
* @return a template file path
*/
String generatePath(Class<?> type, Method method, String databaseId);

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright 2018-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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* The package that holds classes for supports development.
*/
package org.mybatis.scripting.thymeleaf.support;
Loading

0 comments on commit cf8bccc

Please sign in to comment.