Skip to content

Commit c92b65a

Browse files
authored
Merge pull request #799 from kazuki43zoo/support-optional-mapper-method
Support java.util.Optional as return type of mapper method
2 parents fafd159 + 0914973 commit c92b65a

File tree

10 files changed

+381
-9
lines changed

10 files changed

+381
-9
lines changed

src/main/java/org/apache/ibatis/binding/MapperMethod.java

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2017 the original author or authors.
2+
* Copyright 2009-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,7 +21,9 @@
2121
import org.apache.ibatis.mapping.MappedStatement;
2222
import org.apache.ibatis.mapping.SqlCommandType;
2323
import org.apache.ibatis.mapping.StatementType;
24+
import org.apache.ibatis.reflection.Jdk;
2425
import org.apache.ibatis.reflection.MetaObject;
26+
import org.apache.ibatis.reflection.OptionalUtil;
2527
import org.apache.ibatis.reflection.ParamNameResolver;
2628
import org.apache.ibatis.reflection.TypeParameterResolver;
2729
import org.apache.ibatis.session.Configuration;
@@ -39,6 +41,7 @@
3941
* @author Clinton Begin
4042
* @author Eduardo Macarron
4143
* @author Lasse Voss
44+
* @author Kazuki Shimizu
4245
*/
4346
public class MapperMethod {
4447

@@ -54,7 +57,7 @@ public Object execute(SqlSession sqlSession, Object[] args) {
5457
Object result;
5558
switch (command.getType()) {
5659
case INSERT: {
57-
Object param = method.convertArgsToSqlCommandParam(args);
60+
Object param = method.convertArgsToSqlCommandParam(args);
5861
result = rowCountResult(sqlSession.insert(command.getName(), param));
5962
break;
6063
}
@@ -81,6 +84,10 @@ public Object execute(SqlSession sqlSession, Object[] args) {
8184
} else {
8285
Object param = method.convertArgsToSqlCommandParam(args);
8386
result = sqlSession.selectOne(command.getName(), param);
87+
if (method.returnsOptional() &&
88+
(result == null || !method.getReturnType().equals(result.getClass()))) {
89+
result = OptionalUtil.ofNullable(result);
90+
}
8491
}
8592
break;
8693
case FLUSH:
@@ -116,8 +123,8 @@ private void executeWithResultHandler(SqlSession sqlSession, Object[] args) {
116123
MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName());
117124
if (!StatementType.CALLABLE.equals(ms.getStatementType())
118125
&& void.class.equals(ms.getResultMaps().get(0).getType())) {
119-
throw new BindingException("method " + command.getName()
120-
+ " needs either a @ResultMap annotation, a @ResultType annotation,"
126+
throw new BindingException("method " + command.getName()
127+
+ " needs either a @ResultMap annotation, a @ResultType annotation,"
121128
+ " or a resultType attribute in XML so a ResultHandler can be used as a parameter.");
122129
}
123130
Object param = method.convertArgsToSqlCommandParam(args);
@@ -176,7 +183,7 @@ private <E> Object convertToArray(List<E> list) {
176183
for (int i = 0; i < list.size(); i++) {
177184
Array.set(array, i, list.get(i));
178185
}
179-
return array;
186+
return array;
180187
} else {
181188
return list.toArray((E[])array);
182189
}
@@ -219,7 +226,7 @@ public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method
219226
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
220227
configuration);
221228
if (ms == null) {
222-
if (method.getAnnotation(Flush.class) != null) {
229+
if(method.getAnnotation(Flush.class) != null){
223230
name = null;
224231
type = SqlCommandType.FLUSH;
225232
} else {
@@ -270,6 +277,7 @@ public static class MethodSignature {
270277
private final boolean returnsMap;
271278
private final boolean returnsVoid;
272279
private final boolean returnsCursor;
280+
private final boolean returnsOptional;
273281
private final Class<?> returnType;
274282
private final String mapKey;
275283
private final Integer resultHandlerIndex;
@@ -288,6 +296,7 @@ public MethodSignature(Configuration configuration, Class<?> mapperInterface, Me
288296
this.returnsVoid = void.class.equals(this.returnType);
289297
this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
290298
this.returnsCursor = Cursor.class.equals(this.returnType);
299+
this.returnsOptional = Jdk.optionalExists && Optional.class.equals(this.returnType);
291300
this.mapKey = getMapKey(method);
292301
this.returnsMap = this.mapKey != null;
293302
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
@@ -339,6 +348,15 @@ public boolean returnsCursor() {
339348
return returnsCursor;
340349
}
341350

351+
/**
352+
* return whether return type is {@code java.util.Optional}
353+
* @return return {@code true}, if return type is {@code java.util.Optional}
354+
* @since 3.4.2
355+
*/
356+
public boolean returnsOptional() {
357+
return returnsOptional;
358+
}
359+
342360
private Integer getUniqueParamIndex(Method method, Class<?> paramType) {
343361
Integer index = null;
344362
final Class<?>[] argTypes = method.getParameterTypes();

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2017 the original author or authors.
2+
* Copyright 2009-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
3131
import java.util.List;
3232
import java.util.Locale;
3333
import java.util.Map;
34+
import java.util.Optional;
3435
import java.util.Properties;
3536
import java.util.Set;
3637

@@ -80,6 +81,7 @@
8081
import org.apache.ibatis.mapping.SqlSource;
8182
import org.apache.ibatis.mapping.StatementType;
8283
import org.apache.ibatis.parsing.PropertyParser;
84+
import org.apache.ibatis.reflection.Jdk;
8385
import org.apache.ibatis.reflection.TypeParameterResolver;
8486
import org.apache.ibatis.scripting.LanguageDriver;
8587
import org.apache.ibatis.session.Configuration;
@@ -91,6 +93,7 @@
9193

9294
/**
9395
* @author Clinton Begin
96+
* @author Kazuki Shimizu
9497
*/
9598
public class MapperAnnotationBuilder {
9699

@@ -446,6 +449,12 @@ private Class<?> getReturnType(Method method) {
446449
returnType = (Class<?>) ((ParameterizedType) returnTypeParameter).getRawType();
447450
}
448451
}
452+
} else if (Jdk.optionalExists && Optional.class.equals(rawType)) {
453+
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
454+
Type returnTypeParameter = actualTypeArguments[0];
455+
if (returnTypeParameter instanceof Class<?>) {
456+
returnType = (Class<?>) returnTypeParameter;
457+
}
449458
}
450459
}
451460

src/main/java/org/apache/ibatis/reflection/Jdk.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2017 the original author or authors.
2+
* Copyright 2009-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
1716
package org.apache.ibatis.reflection;
1817

1918
import org.apache.ibatis.io.Resources;
@@ -52,6 +51,19 @@ public class Jdk {
5251
dateAndTimeApiExists = available;
5352
}
5453

54+
public static final boolean optionalExists;
55+
56+
static {
57+
boolean available = false;
58+
try {
59+
Resources.classForName("java.util.Optional");
60+
available = true;
61+
} catch (ClassNotFoundException e) {
62+
// ignore
63+
}
64+
optionalExists = available;
65+
}
66+
5567
private Jdk() {
5668
super();
5769
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Copyright 2009-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.apache.ibatis.reflection;
18+
19+
import java.util.Optional;
20+
21+
import org.apache.ibatis.lang.UsesJava8;
22+
23+
public abstract class OptionalUtil {
24+
25+
@UsesJava8
26+
public static Object ofNullable(Object value) {
27+
return Optional.ofNullable(value);
28+
}
29+
30+
private OptionalUtil() {
31+
super();
32+
}
33+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--
2+
-- Copyright 2009-2016 the original author or authors.
3+
--
4+
-- Licensed under the Apache License, Version 2.0 (the "License");
5+
-- you may not use this file except in compliance with the License.
6+
-- You may obtain a copy of the License at
7+
--
8+
-- http://www.apache.org/licenses/LICENSE-2.0
9+
--
10+
-- Unless required by applicable law or agreed to in writing, software
11+
-- distributed under the License is distributed on an "AS IS" BASIS,
12+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
-- See the License for the specific language governing permissions and
14+
-- limitations under the License.
15+
--
16+
17+
drop table users if exists;
18+
19+
create table users (
20+
id int,
21+
name varchar(20)
22+
);
23+
24+
insert into users (id, name) values
25+
(1, 'User1'), (2, 'User2');
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Copyright 2009-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.ibatis.submitted.usesjava8.optional_on_mapper_method;
17+
18+
import org.apache.ibatis.annotations.Select;
19+
20+
import java.util.List;
21+
import java.util.Optional;
22+
23+
public interface Mapper {
24+
25+
@Select("select * from users where id = #{id}")
26+
Optional<User> getUserUsingAnnotation(Integer id);
27+
28+
Optional<User> getUserUsingXml(Integer id);
29+
30+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
Copyright 2009-2016 the original author or authors.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
18+
-->
19+
<!DOCTYPE mapper
20+
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
21+
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
22+
23+
<mapper namespace="org.apache.ibatis.submitted.usesjava8.optional_on_mapper_method.Mapper">
24+
25+
<select id="getUserUsingXml" resultType="org.apache.ibatis.submitted.usesjava8.optional_on_mapper_method.User">
26+
select * from users where id = #{id}
27+
</select>
28+
29+
</mapper>

0 commit comments

Comments
 (0)