Skip to content

Commit aa67be6

Browse files
committed
Support Stream as mapper method return type
Signed-off-by: Yanming Zhou <[email protected]>
1 parent ed55127 commit aa67be6

File tree

8 files changed

+236
-2
lines changed

8 files changed

+236
-2
lines changed

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

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2024 the original author or authors.
2+
* Copyright 2009-2025 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.
@@ -23,6 +23,10 @@
2323
import java.util.List;
2424
import java.util.Map;
2525
import java.util.Optional;
26+
import java.util.Spliterator;
27+
import java.util.Spliterators;
28+
import java.util.stream.Stream;
29+
import java.util.stream.StreamSupport;
2630

2731
import org.apache.ibatis.annotations.Flush;
2832
import org.apache.ibatis.annotations.MapKey;
@@ -43,6 +47,7 @@
4347
* @author Eduardo Macarron
4448
* @author Lasse Voss
4549
* @author Kazuki Shimizu
50+
* @author Yanming Zhou
4651
*/
4752
public class MapperMethod {
4853

@@ -82,6 +87,9 @@ public Object execute(SqlSession sqlSession, Object[] args) {
8287
result = executeForMap(sqlSession, args);
8388
} else if (method.returnsCursor()) {
8489
result = executeForCursor(sqlSession, args);
90+
} else if (method.returnsStream()) {
91+
Cursor<?> cursor = executeForCursor(sqlSession, args);
92+
result = StreamSupport.stream(Spliterators.spliteratorUnknownSize(cursor.iterator(), Spliterator.ORDERED), false);
8593
} else {
8694
Object param = method.convertArgsToSqlCommandParam(args);
8795
result = sqlSession.selectOne(command.getName(), param);
@@ -274,6 +282,7 @@ public static class MethodSignature {
274282
private final boolean returnsMap;
275283
private final boolean returnsVoid;
276284
private final boolean returnsCursor;
285+
private final boolean returnsStream;
277286
private final boolean returnsOptional;
278287
private final Class<?> returnType;
279288
private final String mapKey;
@@ -293,6 +302,7 @@ public MethodSignature(Configuration configuration, Class<?> mapperInterface, Me
293302
this.returnsVoid = void.class.equals(this.returnType);
294303
this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
295304
this.returnsCursor = Cursor.class.equals(this.returnType);
305+
this.returnsStream = Stream.class.equals(this.returnType);
296306
this.returnsOptional = Optional.class.equals(this.returnType);
297307
this.mapKey = getMapKey(method);
298308
this.returnsMap = this.mapKey != null;
@@ -341,6 +351,10 @@ public boolean returnsCursor() {
341351
return returnsCursor;
342352
}
343353

354+
public boolean returnsStream() {
355+
return returnsStream;
356+
}
357+
344358
/**
345359
* return whether return type is {@code java.util.Optional}.
346360
*

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
/**
9494
* @author Clinton Begin
9595
* @author Kazuki Shimizu
96+
* @author Yanming Zhou
9697
*/
9798
public class MapperAnnotationBuilder {
9899

@@ -401,7 +402,7 @@ private static Class<?> getReturnType(Method method, Class<?> type) {
401402
} else if (resolvedReturnType instanceof ParameterizedType) {
402403
ParameterizedType parameterizedType = (ParameterizedType) resolvedReturnType;
403404
Class<?> rawType = (Class<?>) parameterizedType.getRawType();
404-
if (Collection.class.isAssignableFrom(rawType) || Cursor.class.isAssignableFrom(rawType)) {
405+
if (Collection.class.isAssignableFrom(rawType) || Cursor.class.isAssignableFrom(rawType) || Stream.class.isAssignableFrom(rawType)) {
405406
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
406407
if (actualTypeArguments != null && actualTypeArguments.length == 1) {
407408
Type returnTypeParameter = actualTypeArguments[0];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2009-2022 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+
* https://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.stream_on_mapper_method;
17+
18+
import org.apache.ibatis.annotations.Select;
19+
20+
import java.util.stream.Stream;
21+
22+
public interface Mapper {
23+
24+
@Select("select * from users order by id")
25+
Stream<User> findAll();
26+
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2009-2025 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+
* https://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.stream_on_mapper_method;
17+
18+
import org.apache.ibatis.BaseDataTest;
19+
import org.apache.ibatis.io.Resources;
20+
import org.apache.ibatis.session.SqlSession;
21+
import org.apache.ibatis.session.SqlSessionFactory;
22+
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
23+
import org.junit.jupiter.api.BeforeAll;
24+
import org.junit.jupiter.api.Test;
25+
26+
import java.io.Reader;
27+
import java.util.stream.Stream;
28+
29+
import static org.junit.jupiter.api.Assertions.assertEquals;
30+
31+
/**
32+
* Tests for support the {@code java.util.stream.Stream} as return type of mapper method.
33+
*
34+
* @author Yanming Zhou
35+
*/
36+
class StreamOnMapperMethodTest {
37+
38+
private static SqlSessionFactory sqlSessionFactory;
39+
40+
@BeforeAll
41+
static void setUp() throws Exception {
42+
// create an SqlSessionFactory
43+
try (Reader reader = Resources
44+
.getResourceAsReader("org/apache/ibatis/submitted/stream_on_mapper_method/mybatis-config.xml")) {
45+
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
46+
}
47+
48+
// populate in-memory database
49+
BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(),
50+
"org/apache/ibatis/submitted/stream_on_mapper_method/CreateDB.sql");
51+
}
52+
53+
@Test
54+
void returnStream() {
55+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
56+
Mapper mapper = sqlSession.getMapper(Mapper.class);
57+
Stream<User> stream = mapper.findAll();
58+
assertEquals(2, stream.count());
59+
}
60+
}
61+
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2009-2022 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+
* https://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.stream_on_mapper_method;
17+
18+
public class User {
19+
20+
private Integer id;
21+
private String name;
22+
23+
public Integer getId() {
24+
return id;
25+
}
26+
27+
public void setId(Integer id) {
28+
this.id = id;
29+
}
30+
31+
public String getName() {
32+
return name;
33+
}
34+
35+
public void setName(String name) {
36+
this.name = name;
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--
2+
-- Copyright 2009-2022 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+
-- https://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');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
Copyright 2009-2022 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+
https://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+
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
22+
23+
<mapper namespace="org.apache.ibatis.submitted.stream_on_mapper_method.Mapper">
24+
25+
</mapper>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<!--
3+
4+
Copyright 2009-2022 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+
https://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 configuration
20+
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
21+
"https://mybatis.org/dtd/mybatis-3-config.dtd">
22+
23+
<configuration>
24+
25+
<environments default="development">
26+
<environment id="development">
27+
<transactionManager type="JDBC">
28+
<property name="" value="" />
29+
</transactionManager>
30+
<dataSource type="UNPOOLED">
31+
<property name="driver" value="org.hsqldb.jdbcDriver" />
32+
<property name="url" value="jdbc:hsqldb:mem:useactualparamname" />
33+
<property name="username" value="sa" />
34+
</dataSource>
35+
</environment>
36+
</environments>
37+
38+
<mappers>
39+
<mapper class="org.apache.ibatis.submitted.stream_on_mapper_method.Mapper" />
40+
</mappers>
41+
42+
</configuration>

0 commit comments

Comments
 (0)