Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ private void settingsElement(Properties props) {
configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
configuration.setShrinkWhitespacesInSql(booleanValueOf(props.getProperty("shrinkWhitespacesInSql"), false));
configuration.setDefaultSqlProviderType(resolveClass(props.getProperty("defaultSqlProviderType")));
configuration.setNullableOnForEach(booleanValueOf(props.getProperty("nullableOnForEach"), false));
}

private void environmentsElement(XNode context) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--

Copyright 2009-2018 the original author or authors.
Copyright 2009-2021 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.
Expand Down Expand Up @@ -271,6 +271,7 @@ suffixOverrides CDATA #IMPLIED
<!ELEMENT foreach (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
<!ATTLIST foreach
collection CDATA #REQUIRED
nullable (true|false) #IMPLIED
item CDATA #IMPLIED
index CDATA #IMPLIED
open CDATA #IMPLIED
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright 2009-2018 the original author or authors.
Copyright 2009-2021 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.
Expand Down Expand Up @@ -599,6 +599,7 @@
<xs:element ref="bind"/>
</xs:choice>
<xs:attribute name="collection" use="required"/>
<xs:attribute name="nullable" type="xs:boolean"/>
<xs:attribute name="item"/>
<xs:attribute name="index"/>
<xs:attribute name="open"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,25 @@ public boolean evaluateBoolean(String expression, Object parameterObject) {
return value != null;
}

/**
* @deprecated Since 3.5.9, use the {@link #evaluateIterable(String, Object, boolean)}.
*/
@Deprecated
public Iterable<?> evaluateIterable(String expression, Object parameterObject) {
return evaluateIterable(expression, parameterObject, false);
}

/**
* @since 3.5.9
*/
public Iterable<?> evaluateIterable(String expression, Object parameterObject, boolean nullable) {
Object value = OgnlCache.getValue(expression, parameterObject);
if (value == null) {
throw new BuilderException("The expression '" + expression + "' evaluated to a null value.");
if (nullable) {
return null;
} else {
throw new BuilderException("The expression '" + expression + "' evaluated to a null value.");
}
}
if (value instanceof Iterable) {
return (Iterable<?>) value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.apache.ibatis.scripting.xmltags;

import java.util.Map;
import java.util.Optional;

import org.apache.ibatis.parsing.GenericTokenParser;
import org.apache.ibatis.session.Configuration;
Expand All @@ -28,6 +29,7 @@ public class ForEachSqlNode implements SqlNode {

private final ExpressionEvaluator evaluator;
private final String collectionExpression;
private final Boolean nullable;
private final SqlNode contents;
private final String open;
private final String close;
Expand All @@ -36,9 +38,21 @@ public class ForEachSqlNode implements SqlNode {
private final String index;
private final Configuration configuration;

/**
* @deprecated Since 3.5.9, use the {@link #ForEachSqlNode(Configuration, SqlNode, String, Boolean, String, String, String, String, String)}.
*/
@Deprecated
public ForEachSqlNode(Configuration configuration, SqlNode contents, String collectionExpression, String index, String item, String open, String close, String separator) {
this(configuration, contents, collectionExpression, null, index, item, open, close, separator);
}

/**
* @since 3.5.9
*/
public ForEachSqlNode(Configuration configuration, SqlNode contents, String collectionExpression, Boolean nullable, String index, String item, String open, String close, String separator) {
this.evaluator = new ExpressionEvaluator();
this.collectionExpression = collectionExpression;
this.nullable = nullable;
this.contents = contents;
this.open = open;
this.close = close;
Expand All @@ -51,8 +65,9 @@ public ForEachSqlNode(Configuration configuration, SqlNode contents, String coll
@Override
public boolean apply(DynamicContext context) {
Map<String, Object> bindings = context.getBindings();
final Iterable<?> iterable = evaluator.evaluateIterable(collectionExpression, bindings);
if (!iterable.iterator().hasNext()) {
final Iterable<?> iterable = evaluator.evaluateIterable(collectionExpression, bindings,
Optional.ofNullable(nullable).orElseGet(configuration::isNullableOnForEach));
if (iterable == null || !iterable.iterator().hasNext()) {
return true;
}
boolean first = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,13 @@ public ForEachHandler() {
public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
String collection = nodeToHandle.getStringAttribute("collection");
Boolean nullable = nodeToHandle.getBooleanAttribute("nullable");
String item = nodeToHandle.getStringAttribute("item");
String index = nodeToHandle.getStringAttribute("index");
String open = nodeToHandle.getStringAttribute("open");
String close = nodeToHandle.getStringAttribute("close");
String separator = nodeToHandle.getStringAttribute("separator");
ForEachSqlNode forEachSqlNode = new ForEachSqlNode(configuration, mixedSqlNode, collection, index, item, open, close, separator);
ForEachSqlNode forEachSqlNode = new ForEachSqlNode(configuration, mixedSqlNode, collection, nullable, index, item, open, close, separator);
targetContents.add(forEachSqlNode);
}
}
Expand Down
23 changes: 23 additions & 0 deletions src/main/java/org/apache/ibatis/session/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ public class Configuration {
protected boolean useActualParamName = true;
protected boolean returnInstanceForEmptyRow;
protected boolean shrinkWhitespacesInSql;
protected boolean nullableOnForEach;

protected String logPrefix;
protected Class<? extends Log> logImpl;
Expand Down Expand Up @@ -297,6 +298,28 @@ public void setShrinkWhitespacesInSql(boolean shrinkWhitespacesInSql) {
this.shrinkWhitespacesInSql = shrinkWhitespacesInSql;
}

/**
* Sets the default value of 'nullable' attribute on 'foreach' tag.
*
* @param nullableOnForEach If nullable, set to {@code true}
* @since 3.5.9
*/
public void setNullableOnForEach(boolean nullableOnForEach) {
this.nullableOnForEach = nullableOnForEach;
}

/**
* Returns the default value of 'nullable' attribute on 'foreach' tag.
*
* <p>Default is {@code false}.
*
* @return If nullable, set to {@code true}
* @since 3.5.9
*/
public boolean isNullableOnForEach() {
return nullableOnForEach;
}

public String getDatabaseId() {
return databaseId;
}
Expand Down
14 changes: 14 additions & 0 deletions src/site/es/xdoc/configuration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,20 @@ SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environ
Not set
</td>
</tr>
<tr>
<td>
nullableOnForEach
</td>
<td>
Specifies the default value of 'nullable' attribute on 'foreach' tag. (Since 3.5.9)
</td>
<td>
true | false
</td>
<td>
false
</td>
</tr>
</tbody>
</table>
<p>
Expand Down
13 changes: 7 additions & 6 deletions src/site/es/xdoc/dynamic-sql.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright 2009-2019 the original author or authors.
Copyright 2009-2021 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.
Expand Down Expand Up @@ -147,11 +147,12 @@ AND title like ‘someTitle’]]></source>
<source><![CDATA[<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
<where>
<foreach item="item" index="index" collection="list"
open="ID in (" separator="," close=")" nullable="true">
#{item}
</foreach>
</where>
</select>]]></source>
<p>El elemento foreach es muy potente, permite especificar una colección y declarar variables elemento e índice que pueden usarse dentro del cuerpo del elemento. Permite también abrir y cerrar strings y añadir un separador entre las iteraciones. Este elemento es inteligente en tanto en cuanto no añade separadores extra accidentalmente.</p>
<p><span class="label important">NOTA</span> You can pass any Iterable object (for example List, Set, etc.), as well as any Map or Array object to foreach as collection parameter. When using an Iterable or Array, index will be the number of current iteration and value item will be the element retrieved in this iteration. When using a Map (or Collection of Map.Entry objects), index will be the key object and item will be the value object.</p>
Expand Down
14 changes: 14 additions & 0 deletions src/site/ja/xdoc/configuration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,20 @@ SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environ
未指定
</td>
</tr>
<tr>
<td>
nullableOnForEach
</td>
<td>
'foreach' タグの 'nullable' 属性のデフォルト値. (導入されたバージョン: 3.5.9)
</td>
<td>
true | false
</td>
<td>
false
</td>
</tr>
</tbody>
</table>
<p>
Expand Down
13 changes: 7 additions & 6 deletions src/site/ja/xdoc/dynamic-sql.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright 2009-2019 the original author or authors.
Copyright 2009-2021 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.
Expand Down Expand Up @@ -153,11 +153,12 @@ AND title like ‘someTitle’]]></source>
<source><![CDATA[<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
<where>
<foreach item="item" index="index" collection="list"
open="ID in (" separator="," close=")" nullable="true">
#{item}
</foreach>
</where>
</select>]]></source>
<p><em>foreach</em> 要素は非常に強力で、イテレーション処理の対象となるコレクションを指定する collection と、ループ内で要素を格納する変数 item、ループ回数を格納する index 変数を宣言することができます。また、開始・終了の文字列とイテレーションの合間に出力する区切り文字を指定することもできます。foreach タグは賢いので、余分な区切り文字を出力することはありません。</p>
<p><span class="label important">NOTE</span> collection には Iterable を実装したオブジェクト(List や Set など)の他に Map や Array を指定することもできます。collection に Iterable または Array を指定した場合、 index で指定した変数にはインデックスの数値、 item で指定した変数にはコレクション、配列の要素が格納されます。Map あるいは Map.Entry のコレクションを指定した場合は index にマップのキー、item にマップの値が格納されます。</p>
Expand Down
14 changes: 14 additions & 0 deletions src/site/ko/xdoc/configuration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,20 @@ SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environ
설정하지 않음
</td>
</tr>
<tr>
<td>
nullableOnForEach
</td>
<td>
Specifies the default value of 'nullable' attribute on 'foreach' tag. (Since 3.5.9)
</td>
<td>
true | false
</td>
<td>
false
</td>
</tr>
</tbody>
</table>
<p>위 설정을 모두 사용한 setting 엘리먼트의 예제이다:</p>
Expand Down
13 changes: 7 additions & 6 deletions src/site/ko/xdoc/dynamic-sql.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright 2009-2020 the original author or authors.
Copyright 2009-2021 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.
Expand Down Expand Up @@ -176,11 +176,12 @@ AND title like ‘someTitle’]]></source>
<source><![CDATA[<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
<where>
<foreach item="item" index="index" collection="list"
open="ID in (" separator="," close=")" nullable="true">
#{item}
</foreach>
</where>
</select>]]></source>
<p>foreach엘리먼트는 매우 강력하고 collection 을 명시하는 것을 허용한다.
엘리먼트 내부에서 사용할 수 있는 item, index두가지 변수를 선언한다.
Expand Down
14 changes: 14 additions & 0 deletions src/site/xdoc/configuration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,20 @@ SqlSessionFactory factory =
Not set
</td>
</tr>
<tr>
<td>
nullableOnForEach
</td>
<td>
Specifies the default value of 'nullable' attribute on 'foreach' tag. (Since 3.5.9)
</td>
<td>
true | false
</td>
<td>
false
</td>
</tr>
</tbody>
</table>
<p>
Expand Down
13 changes: 7 additions & 6 deletions src/site/xdoc/dynamic-sql.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright 2009-2019 the original author or authors.
Copyright 2009-2021 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.
Expand Down Expand Up @@ -146,11 +146,12 @@ AND title like ‘someTitle’]]></source>
<source><![CDATA[<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
<where>
<foreach item="item" index="index" collection="list"
open="ID in (" separator="," close=")" nullable="true">
#{item}
</foreach>
</where>
</select>]]></source>
<p>The <em>foreach</em> element is very powerful, and allows you to specify a collection, declare item and index variables that can be used inside the body of the element. It also allows you to specify opening and closing strings, and add a separator to place in between iterations. The element is smart in that it won’t accidentally append extra separators. </p>
<p><span class="label important">NOTE</span> You can pass any Iterable object (for example List, Set, etc.), as well as any Map or Array object to foreach as collection parameter. When using an Iterable or Array, index will be the number of current iteration and value item will be the element retrieved in this iteration. When using a Map (or Collection of Map.Entry objects), index will be the key object and item will be the value object.</p>
Expand Down
14 changes: 14 additions & 0 deletions src/site/zh/xdoc/configuration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,20 @@ SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environ
Not set
</td>
</tr>
<tr>
<td>
nullableOnForEach
</td>
<td>
Specifies the default value of 'nullable' attribute on 'foreach' tag. (Since 3.5.9)
</td>
<td>
true | false
</td>
<td>
false
</td>
</tr>
</tbody>
</table>
<p>
Expand Down
Loading