Skip to content

Commit 2b3f932

Browse files
committed
Add the @options#timeoutString
Support a new attribute that specify the query timeout using configuration's variables such as ${timeout.query1}
1 parent 39f2527 commit 2b3f932

File tree

4 files changed

+85
-3
lines changed

4 files changed

+85
-3
lines changed

src/main/java/org/apache/ibatis/annotations/Options.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,26 @@ enum FlushCachePolicy {
9696
* Returns the statement timeout.
9797
*
9898
* @return the statement timeout
99+
*
100+
* @see #timeoutString()
99101
*/
100102
int timeout() default -1;
101103

104+
/**
105+
* Returns the statement timeout string.
106+
* <p>
107+
* Can specify configuration's variables such as {@code ${timeout.select}}. If not resolve variable value, fallback
108+
* the {@link #timeout()} value.
109+
* </p>
110+
*
111+
* @return the statement timeout string
112+
*
113+
* @see #timeout()
114+
*
115+
* @since 3.5.14
116+
*/
117+
String timeoutString() default "";
118+
102119
/**
103120
* Returns whether use the generated keys feature supported by JDBC 3.0
104121
*

src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.Optional;
3434
import java.util.Properties;
3535
import java.util.Set;
36+
import java.util.function.Function;
3637
import java.util.stream.Collectors;
3738
import java.util.stream.Stream;
3839

@@ -80,6 +81,7 @@
8081
import org.apache.ibatis.mapping.SqlCommandType;
8182
import org.apache.ibatis.mapping.SqlSource;
8283
import org.apache.ibatis.mapping.StatementType;
84+
import org.apache.ibatis.parsing.GenericTokenParser;
8385
import org.apache.ibatis.parsing.PropertyParser;
8486
import org.apache.ibatis.reflection.TypeParameterResolver;
8587
import org.apache.ibatis.scripting.LanguageDriver;
@@ -101,6 +103,8 @@ public class MapperAnnotationBuilder {
101103
InsertProvider.class, DeleteProvider.class)
102104
.collect(Collectors.toSet());
103105

106+
private static final GenericTokenParser TOKEN_PARSER = new GenericTokenParser("${", "}", t -> t);
107+
104108
private final Configuration configuration;
105109
private final MapperBuilderAssistant assistant;
106110
private final Class<?> type;
@@ -345,7 +349,8 @@ void parseStatement(Method method) {
345349
useCache = options.useCache();
346350
// issue #348
347351
fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null;
348-
timeout = options.timeout() > -1 ? options.timeout() : null;
352+
Integer fallbackTimeout = options.timeout() > -1 ? options.timeout() : null;
353+
timeout = parseStringValue(options.timeoutString(), fallbackTimeout, Integer::parseInt);
349354
statementType = options.statementType();
350355
if (options.resultSetType() != ResultSetType.DEFAULT) {
351356
resultSetType = options.resultSetType();
@@ -372,6 +377,20 @@ null, parameterTypeClass, resultMapId, getReturnType(method, type), resultSetTyp
372377
});
373378
}
374379

380+
private <T> T parseStringValue(String valueString, T fallbackValue, Function<String, T> valueTypeConverter) {
381+
if (valueString.isEmpty()) {
382+
return fallbackValue;
383+
} else {
384+
Properties defaults = new Properties();
385+
Optional.ofNullable(fallbackValue).map(String::valueOf)
386+
.ifPresent(x -> defaults.setProperty(TOKEN_PARSER.parse(valueString), x));
387+
Properties variables = new Properties(defaults);
388+
variables.putAll(configuration.getVariables());
389+
return Optional.ofNullable(PropertyParser.parse(valueString, variables)).map(valueTypeConverter)
390+
.orElse(fallbackValue);
391+
}
392+
}
393+
375394
private LanguageDriver getLanguageDriver(Method method) {
376395
Lang lang = method.getAnnotation(Lang.class);
377396
Class<? extends LanguageDriver> langClass = null;

src/main/java/org/apache/ibatis/parsing/PropertyParser.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ public String handleToken(String content) {
8888
return variables.getProperty(key, defaultValue);
8989
}
9090
}
91-
if (variables.containsKey(key)) {
92-
return variables.getProperty(key);
91+
String value = variables.getProperty(key);
92+
if (value != null) {
93+
return value;
9394
}
9495
}
9596
return "${" + content + "}";

src/test/java/org/apache/ibatis/builder/AnnotationMapperBuilderTest.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import static org.assertj.core.api.Assertions.assertThat;
1919

20+
import java.util.Properties;
21+
2022
import org.apache.ibatis.annotations.Insert;
2123
import org.apache.ibatis.annotations.Options;
2224
import org.apache.ibatis.annotations.Select;
@@ -25,6 +27,7 @@
2527
import org.apache.ibatis.mapping.MappedStatement;
2628
import org.apache.ibatis.mapping.ResultSetType;
2729
import org.apache.ibatis.mapping.StatementType;
30+
import org.apache.ibatis.parsing.PropertyParser;
2831
import org.apache.ibatis.session.Configuration;
2932
import org.junit.jupiter.api.Test;
3033

@@ -93,6 +96,26 @@ void withoutOptionsWhenNotSpecifyDefaultValue() {
9396
assertThat(mappedStatement.getResultSetType()).isEqualTo(ResultSetType.DEFAULT);
9497
}
9598

99+
@Test
100+
void timeout() {
101+
Configuration configuration = new Configuration();
102+
Properties variables = new Properties();
103+
variables.setProperty(PropertyParser.KEY_ENABLE_DEFAULT_VALUE, "true");
104+
variables.setProperty("timeout.select1", "200");
105+
configuration.setVariables(variables);
106+
MapperAnnotationBuilder builder = new MapperAnnotationBuilder(configuration, TimeoutMapper.class);
107+
builder.parse();
108+
109+
assertThat(configuration.getMappedStatement("selectWithTimeoutStringByNumber").getTimeout()).isEqualTo(10);
110+
assertThat(configuration.getMappedStatement("selectWithTimeoutStringByVariable").getTimeout()).isEqualTo(200);
111+
assertThat(configuration.getMappedStatement("selectWithTimeoutStringByVariableDefaultValue").getTimeout())
112+
.isEqualTo(30);
113+
assertThat(configuration.getMappedStatement("selectWithTimeoutAndTimeoutStringVariableFound").getTimeout())
114+
.isEqualTo(200);
115+
assertThat(configuration.getMappedStatement("selectWithTimeoutAndTimeoutStringVariableNotFound").getTimeout())
116+
.isEqualTo(40);
117+
}
118+
96119
interface Mapper {
97120

98121
@Insert("insert into test (name) values(#{name})")
@@ -112,4 +135,26 @@ interface Mapper {
112135

113136
}
114137

138+
interface TimeoutMapper {
139+
@Select("select * from test")
140+
@Options(timeoutString = "10")
141+
String selectWithTimeoutStringByNumber(Integer id);
142+
143+
@Select("select * from test")
144+
@Options(timeoutString = "${timeout.select1}")
145+
String selectWithTimeoutStringByVariable(Integer id);
146+
147+
@Select("select * from test")
148+
@Options(timeoutString = "${timeout.select2:30}")
149+
String selectWithTimeoutStringByVariableDefaultValue(Integer id);
150+
151+
@Select("select * from test")
152+
@Options(timeout = 20, timeoutString = "${timeout.select1}")
153+
String selectWithTimeoutAndTimeoutStringVariableFound(Integer id);
154+
155+
@Select("select * from test")
156+
@Options(timeout = 40, timeoutString = "${timeout.select3}")
157+
String selectWithTimeoutAndTimeoutStringVariableNotFound(Integer id);
158+
}
159+
115160
}

0 commit comments

Comments
 (0)