Skip to content

Commit

Permalink
Merge pull request #1951 from kazuki43zoo/support-defaultSqlProviderType
Browse files Browse the repository at this point in the history
Support global configuration for applying sql provider type when omit on annotation
Fixes gh-1951
  • Loading branch information
kazuki43zoo committed Jun 7, 2020
2 parents 4917d53 + 9df34f5 commit 28b3f89
Show file tree
Hide file tree
Showing 16 changed files with 313 additions and 7 deletions.
Expand Up @@ -100,7 +100,7 @@ public ProviderSqlSource(Configuration configuration, Annotation provider, Class
this.mapperMethod = mapperMethod;
Lang lang = mapperMethod == null ? null : mapperMethod.getAnnotation(Lang.class);
this.languageDriver = configuration.getLanguageDriver(lang == null ? null : lang.value());
this.providerType = getProviderType(provider, mapperMethod);
this.providerType = getProviderType(configuration, provider, mapperMethod);
candidateProviderMethodName = (String) provider.annotationType().getMethod("method").invoke(provider);

if (candidateProviderMethodName.length() == 0 && ProviderMethodResolver.class.isAssignableFrom(this.providerType)) {
Expand Down Expand Up @@ -235,11 +235,14 @@ private String invokeProviderMethod(Object... args) throws Exception {
return sql != null ? sql.toString() : null;
}

private Class<?> getProviderType(Annotation providerAnnotation, Method mapperMethod)
private Class<?> getProviderType(Configuration configuration, Annotation providerAnnotation, Method mapperMethod)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> type = (Class<?>) providerAnnotation.annotationType().getMethod("type").invoke(providerAnnotation);
Class<?> value = (Class<?>) providerAnnotation.annotationType().getMethod("value").invoke(providerAnnotation);
if (value == void.class && type == void.class) {
if (configuration.getDefaultSqlProviderType() != null) {
return configuration.getDefaultSqlProviderType();
}
throw new BuilderException("Please specify either 'value' or 'type' attribute of @"
+ providerAnnotation.annotationType().getSimpleName()
+ " at the '" + mapperMethod.toString() + "'.");
Expand Down
Expand Up @@ -269,6 +269,7 @@ private void settingsElement(Properties props) {
configuration.setLogPrefix(props.getProperty("logPrefix"));
configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
configuration.setShrinkWhitespacesInSql(booleanValueOf(props.getProperty("shrinkWhitespacesInSql"), false));
configuration.setDefaultSqlProviderType(resolveClass(props.getProperty("defaultSqlProviderType")));
}

private void environmentsElement(XNode context) throws Exception {
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/org/apache/ibatis/session/Configuration.java
Expand Up @@ -118,6 +118,7 @@ public class Configuration {
protected String logPrefix;
protected Class<? extends Log> logImpl;
protected Class<? extends VFS> vfsImpl;
protected Class<?> defaultSqlProviderType;
protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
protected Set<String> lazyLoadTriggerMethods = new HashSet<>(Arrays.asList("equals", "clone", "hashCode", "toString"));
Expand Down Expand Up @@ -243,6 +244,27 @@ public void setVfsImpl(Class<? extends VFS> vfsImpl) {
}
}

/**
* Gets an applying type when omit a type on sql provider annotation(e.g. {@link org.apache.ibatis.annotations.SelectProvider}).
*
* @return the default type for sql provider annotation
* @since 3.5.6
*/
public Class<?> getDefaultSqlProviderType() {
return defaultSqlProviderType;
}

/**
* Sets an applying type when omit a type on sql provider annotation(e.g. {@link org.apache.ibatis.annotations.SelectProvider}).
*
* @param defaultSqlProviderType
* the default type for sql provider annotation
* @since 3.5.6
*/
public void setDefaultSqlProviderType(Class<?> defaultSqlProviderType) {
this.defaultSqlProviderType = defaultSqlProviderType;
}

public boolean isCallSettersOnNulls() {
return callSettersOnNulls;
}
Expand Down
16 changes: 16 additions & 0 deletions src/site/es/xdoc/configuration.xml
Expand Up @@ -561,6 +561,22 @@ SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environ
false
</td>
</tr>
<tr>
<td>
defaultSqlProviderType
</td>
<td>
Specifies an sql provider class that holds provider method (Since 3.5.6).
This class apply to the <code>type</code>(or <code>value</code>) attribute on sql provider annotation(e.g. <code>@SelectProvider</code>),
when these attribute was omitted.
</td>
<td>
A type alias or fully qualified class name
</td>
<td>
Not set
</td>
</tr>
</tbody>
</table>
<p>
Expand Down
26 changes: 25 additions & 1 deletion src/site/es/xdoc/java-api.xml
Expand Up @@ -480,7 +480,8 @@ void rollback(boolean force)</source>
via the <code>ProviderContext</code>(available since MyBatis 3.4.5 or later) as method argument.(In MyBatis 3.4 or later, it's allow multiple parameters)
Atributos: value, type y method.
El atributo value y type es el nombre completamente cualificado de una clase
(The <code>type</code> attribute is alias for <code>value</code>, you must be specify either one).
(The <code>type</code> attribute is alias for <code>value</code>, you must be specify either one.
But both attributes can be omit when specify the <code>defaultSqlProviderType</code> as global configuration).
El method es el nombre un método de dicha clase
(Since 3.5.1, you can omit <code>method</code> attribute, the MyBatis will resolve a target method via the
<code>ProviderMethodResolver</code> interface.
Expand Down Expand Up @@ -635,6 +636,29 @@ class UserSqlProvider implements ProviderMethodResolver {
}
}]]></source>

<p>This example shows usage that share an sql provider class to all mapper methods using global configuration(Available since 3.5.6):</p>
<source><![CDATA[
Configuration configuration = new Configuration();
configuration.setDefaultSqlProviderType(TemplateFilePathProvider.class); // Specify an sql provider class for sharing on all mapper methods
// ...]]></source>
<source><![CDATA[
// Can omit the type/value attribute on sql provider annotation
// If omit it, the MyBatis apply the class that specified on defaultSqlProviderType.
public interface UserMapper {
@SelectProvider // Same with @SelectProvider(TemplateFilePathProvider.class)
User findUser(int id);
@InsertProvider // Same with @InsertProvider(TemplateFilePathProvider.class)
void createUser(User user);
@UpdateProvider // Same with @UpdateProvider(TemplateFilePathProvider.class)
void updateUser(User user);
@DeleteProvider // Same with @DeleteProvider(TemplateFilePathProvider.class)
void deleteUser(int id);
}]]></source>

<p>This example shows usage the default implementation of <code>ProviderMethodResolver</code>(available since MyBatis 3.5.1 or later):</p>
<source><![CDATA[@SelectProvider(UserSqlProvider.class)
List<User> getUsersByName(String name);
Expand Down
15 changes: 15 additions & 0 deletions src/site/ja/xdoc/configuration.xml
Expand Up @@ -586,6 +586,21 @@ SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environ
false
</td>
</tr>
<tr>
<td>
defaultSqlProviderType
</td>
<td>
SQLを提供するメソッドを保持するSQLプロバイダクラスを指定します(導入されたバージョン: 3.5.6)。
ここで指定したクラスは、SQLプロバイダアノテーション(例: <code>@SelectProvider</code>)の<code>type</code>(または <code>value</code>) 属性を省略した際に適用されます。
</td>
<td>
タイプエイリアスまたは完全修飾クラス名
</td>
<td>
未指定
</td>
</tr>
</tbody>
</table>
<p>
Expand Down
26 changes: 25 additions & 1 deletion src/site/ja/xdoc/java-api.xml
Expand Up @@ -491,7 +491,8 @@ void rollback(boolean force)</source>
なお、メソッド引数にはMapperメソッドの引数に渡したオブジェクトに加え、<code>ProviderContext</code>(MyBatis 3.4.5以降で利用可能)を介して「Mapperインタフェースの型」「Mapperメソッド」「データベースID」を渡すことができます。(MyBatis 3.4以降では、複数の引数を渡すことができます)
キー: <code>value</code>, <code>type</code>, <code>method</code>.
<code>value</code> と <code>type</code> にはクラスオブジェクトを指定します
(<code>type</code> は <code>value</code> の別名で、どちらか一方を指定する必要があります)。
(<code>type</code> は <code>value</code> の別名で、どちらか一方を指定する必要があります。
ただし、グローバル設定として<code>defaultSqlProviderType</code>を指定している場合は両方とも省略することができます)。
<code>method</code> にはメソッド名を指定します
(MyBatis 3.5.1以降では、<code>method</code> 属性を省略することができます。その際MyBatisは、<code>ProviderMethodResolver</code> インタフェースを介して対象メソッドの解決を試み、
対象メソッドが解決できない場合は、<code>provideSql</code>という名前のメソッドを代替メソッドとして利用します)。
Expand Down Expand Up @@ -619,6 +620,29 @@ class UserSqlBuilder {
}
}]]></source>

<p>次のコードは、グローバル設定を利用して全てのマッパーメソッドで同じSQLプロバイダクラスを利用する例です。(3.5.6以降で利用可能)</p>
<source><![CDATA[
Configuration configuration = new Configuration();
configuration.setDefaultSqlProviderType(TemplateFilePathProvider.class); // 全てのマッパーメソッドで利用するSQLプロバイダクラスを指定する
// ...]]></source>
<source><![CDATA[
// 各メソッドのSQLプロバイダアノテーションの type または value 属性は省略することができ、
// 省略した場合はMyBaitsはグローバル設定の defaultSqlProviderType に指定されているクラスを適用する
public interface UserMapper {
@SelectProvider // @SelectProvider(TemplateFilePathProvider.class) と同義
User findUser(int id);
@InsertProvider // @InsertProvider(TemplateFilePathProvider.class) と同義
void createUser(User user);
@UpdateProvider // @UpdateProvider(TemplateFilePathProvider.class) と同義
void updateUser(User user);
@DeleteProvider // @DeleteProvider(TemplateFilePathProvider.class) と同義
void deleteUser(int id);
}]]></source>

<p>次のコードは、<code>ProviderMethodResolver</code>(MyBatis 3.5.1以降で利用可能)のデフォルト実装の利用例です。</p>
<source><![CDATA[@SelectProvider(UserSqlProvider.class)
List<User> getUsersByName(String name);
Expand Down
16 changes: 16 additions & 0 deletions src/site/ko/xdoc/configuration.xml
Expand Up @@ -569,6 +569,22 @@ SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environ
false
</td>
</tr>
<tr>
<td>
defaultSqlProviderType
</td>
<td>
Specifies an sql provider class that holds provider method (Since 3.5.6).
This class apply to the <code>type</code>(or <code>value</code>) attribute on sql provider annotation(e.g. <code>@SelectProvider</code>),
when these attribute was omitted.
</td>
<td>
A type alias or fully qualified class name
</td>
<td>
Not set
</td>
</tr>
</tbody>
</table>
<p>위 설정을 모두 사용한 setting 엘리먼트의 예제이다:</p>
Expand Down
26 changes: 25 additions & 1 deletion src/site/ko/xdoc/java-api.xml
Expand Up @@ -605,7 +605,8 @@ void rollback(boolean force)</source>
매핑된 구문을 실행할 때 마이바티스는 클래스의 인스턴스를 만들고 메소드를 실행한다.
Mapper 메서드의 인수인 "Mapper interface type" and "Database ID" 과 <code>ProviderContext</code>(Mybatis 3.4.5 부터) 를 이용한 "Mapper method" 로 전달 된 객체를 메서드 매개변수로 전달할 수 있다.(마이바티스 3.4이상에서는 복수 파라미터를 허용한다.)
사용가능한 속성들 : value, type, method.
value and type 속성은 클래스 (The <code>type</code> attribute is alias for <code>value</code>, you must be specify either one).
value and type 속성은 클래스 (The <code>type</code> attribute is alias for <code>value</code>, you must be specify either one.
But both attributes can be omit when specify the <code>defaultSqlProviderType</code> as global configuration).
method 속성은 메소드명이다
(Since 3.5.1, you can omit <code>method</code> attribute, the MyBatis will resolve a target method via the
<code>ProviderMethodResolver</code> interface.
Expand Down Expand Up @@ -749,6 +750,29 @@ class UserSqlBuilder {
}
}]]></source>

<p>This example shows usage that share an sql provider class to all mapper methods using global configuration(Available since 3.5.6):</p>
<source><![CDATA[
Configuration configuration = new Configuration();
configuration.setDefaultSqlProviderType(TemplateFilePathProvider.class); // Specify an sql provider class for sharing on all mapper methods
// ...]]></source>
<source><![CDATA[
// Can omit the type/value attribute on sql provider annotation
// If omit it, the MyBatis apply the class that specified on defaultSqlProviderType.
public interface UserMapper {
@SelectProvider // Same with @SelectProvider(TemplateFilePathProvider.class)
User findUser(int id);
@InsertProvider // Same with @InsertProvider(TemplateFilePathProvider.class)
void createUser(User user);
@UpdateProvider // Same with @UpdateProvider(TemplateFilePathProvider.class)
void updateUser(User user);
@DeleteProvider // Same with @DeleteProvider(TemplateFilePathProvider.class)
void deleteUser(int id);
}]]></source>

<p>This example shows usage the default implementation of <code>ProviderMethodResolver</code>(available since MyBatis 3.5.1 or later):</p>
<source><![CDATA[@SelectProvider(UserSqlProvider.class)
List<User> getUsersByName(String name);
Expand Down
16 changes: 16 additions & 0 deletions src/site/xdoc/configuration.xml
Expand Up @@ -648,6 +648,22 @@ SqlSessionFactory factory =
false
</td>
</tr>
<tr>
<td>
defaultSqlProviderType
</td>
<td>
Specifies an sql provider class that holds provider method (Since 3.5.6).
This class apply to the <code>type</code>(or <code>value</code>) attribute on sql provider annotation(e.g. <code>@SelectProvider</code>),
when these attribute was omitted.
</td>
<td>
A type alias or fully qualified class name
</td>
<td>
Not set
</td>
</tr>
</tbody>
</table>
<p>
Expand Down
27 changes: 26 additions & 1 deletion src/site/xdoc/java-api.xml
Expand Up @@ -525,7 +525,8 @@ void rollback(boolean force)</source>
(In MyBatis 3.4 or later, it's allow multiple parameters)
Attributes: <code>value</code>, <code>type</code>, <code>method</code> and <code>databaseId</code>.
The <code>value</code> and <code>type</code> attribute is a class
(The <code>type</code> attribute is alias for <code>value</code>, you must be specify either one).
(The <code>type</code> attribute is alias for <code>value</code>, you must be specify either one.
But both attributes can be omit when specify the <code>defaultSqlProviderType</code> as global configuration).
The <code>method</code> is the name of the method on that class
(Since 3.5.1, you can omit <code>method</code> attribute, the MyBatis will resolve a target method via the
<code>ProviderMethodResolver</code> interface.
Expand Down Expand Up @@ -672,6 +673,29 @@ class UserSqlBuilder {
}
}]]></source>

<p>This example shows usage that share an sql provider class to all mapper methods using global configuration(Available since 3.5.6):</p>
<source><![CDATA[
Configuration configuration = new Configuration();
configuration.setDefaultSqlProviderType(TemplateFilePathProvider.class); // Specify an sql provider class for sharing on all mapper methods
// ...]]></source>
<source><![CDATA[
// Can omit the type/value attribute on sql provider annotation
// If omit it, the MyBatis apply the class that specified on defaultSqlProviderType.
public interface UserMapper {
@SelectProvider // Same with @SelectProvider(TemplateFilePathProvider.class)
User findUser(int id);
@InsertProvider // Same with @InsertProvider(TemplateFilePathProvider.class)
void createUser(User user);
@UpdateProvider // Same with @UpdateProvider(TemplateFilePathProvider.class)
void updateUser(User user);
@DeleteProvider // Same with @DeleteProvider(TemplateFilePathProvider.class)
void deleteUser(int id);
}]]></source>

<p>This example shows usage the default implementation of <code>ProviderMethodResolver</code>(available since MyBatis 3.5.1 or later):</p>
<source><![CDATA[@SelectProvider(UserSqlProvider.class)
List<User> getUsersByName(String name);
Expand All @@ -691,6 +715,7 @@ class UserSqlProvider implements ProviderMethodResolver {
}
}]]></source>


<p>This example shows usage the <code>databaseId</code> attribute on the statement annotation(Available since 3.5.5):</p>
<source><![CDATA[
@Select(value = "SELECT SYS_GUID() FROM dual", databaseId = "oracle") // Use this statement if DatabaseIdProvider provide "oracle"
Expand Down
16 changes: 16 additions & 0 deletions src/site/zh/xdoc/configuration.xml
Expand Up @@ -579,6 +579,22 @@ SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environ
false
</td>
</tr>
<tr>
<td>
defaultSqlProviderType
</td>
<td>
Specifies an sql provider class that holds provider method (Since 3.5.6).
This class apply to the <code>type</code>(or <code>value</code>) attribute on sql provider annotation(e.g. <code>@SelectProvider</code>),
when these attribute was omitted.
</td>
<td>
A type alias or fully qualified class name
</td>
<td>
Not set
</td>
</tr>
</tbody>
</table>
<p>
Expand Down

0 comments on commit 28b3f89

Please sign in to comment.