Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support global configuration for applying sql provider type when omit on annotation #1951

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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