Skip to content

Commit

Permalink
Merge pull request #2767 from FlyInWind1/no-result-type
Browse files Browse the repository at this point in the history
Resolve resultType by namespace and id when not provide resultType and resultMap
  • Loading branch information
harawata committed Jan 6, 2023
2 parents 8e4cf55 + d51f3a7 commit 2d50c4b
Show file tree
Hide file tree
Showing 10 changed files with 316 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2009-2022 the original author or authors.
* Copyright 2009-2023 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 @@ -138,7 +138,7 @@ public void parse() {
parsePendingMethods();
}

private boolean canHaveStatement(Method method) {
private static boolean canHaveStatement(Method method) {
// issue #237
return !method.isBridge() && !method.isDefault();
}
Expand Down Expand Up @@ -224,7 +224,7 @@ private void parseCacheRef() {
}

private String parseResultMap(Method method) {
Class<?> returnType = getReturnType(method);
Class<?> returnType = getReturnType(method, type);
Arg[] args = method.getAnnotationsByType(Arg.class);
Result[] results = method.getAnnotationsByType(Result.class);
TypeDiscriminator typeDiscriminator = method.getAnnotation(TypeDiscriminator.class);
Expand Down Expand Up @@ -366,7 +366,7 @@ void parseStatement(Method method) {
null,
parameterTypeClass,
resultMapId,
getReturnType(method),
getReturnType(method, type),
resultSetType,
flushCache,
useCache,
Expand Down Expand Up @@ -408,7 +408,7 @@ private Class<?> getParameterType(Method method) {
return parameterType;
}

private Class<?> getReturnType(Method method) {
private static Class<?> getReturnType(Method method, Class<?> type) {
Class<?> returnType = method.getReturnType();
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, type);
if (resolvedReturnType instanceof Class) {
Expand Down Expand Up @@ -669,6 +669,23 @@ private Optional<AnnotationWrapper> getAnnotationWrapper(Method method, boolean
return Optional.ofNullable(annotationWrapper);
}

public static Class<?> getMethodReturnType(String mapperFqn, String localStatementId) {
if (mapperFqn == null || localStatementId == null) {
return null;
}
try {
Class<?> mapperClass = Resources.classForName(mapperFqn);
for (Method method : mapperClass.getMethods()) {
if (method.getName().equals(localStatementId) && canHaveStatement(method)) {
return getReturnType(method, mapperClass);
}
}
} catch (ClassNotFoundException e) {
// No corresponding mapper interface which is OK
}
return null;
}

private class AnnotationWrapper {
private final Annotation annotation;
private final String databaseId;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2009-2022 the original author or authors.
* Copyright 2009-2023 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 All @@ -20,6 +20,7 @@

import org.apache.ibatis.builder.BaseBuilder;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.builder.annotation.MapperAnnotationBuilder;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
Expand Down Expand Up @@ -101,6 +102,9 @@ public void parseStatementNode() {
String resultType = context.getStringAttribute("resultType");
Class<?> resultTypeClass = resolveClass(resultType);
String resultMap = context.getStringAttribute("resultMap");
if (resultTypeClass == null && resultMap == null) {
resultTypeClass = MapperAnnotationBuilder.getMethodReturnType(builderAssistant.getCurrentNamespace(), id);
}
String resultSetType = context.getStringAttribute("resultSetType");
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
if (resultSetTypeEnum == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2009-2022 the original author or authors.
* Copyright 2009-2023 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 @@ -294,7 +294,7 @@ private void cleanUpAfterHandlingResultSet() {
private void validateResultMapsCount(ResultSetWrapper rsw, int resultMapCount) {
if (rsw != null && resultMapCount < 1) {
throw new ExecutorException("A query was run and no Result Maps were found for the Mapped Statement '" + mappedStatement.getId()
+ "'. It's likely that neither a Result Type nor a Result Map was specified.");
+ "'. 'resultType' or 'resultMap' must be specified when there is no corresponding method.");
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2009-2023 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.submitted.no_result_type_map;

import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface Mapper extends ParentMapper<User>{

User getUser(@Param("id") Integer id);

List<User> getAllUsers();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright 2009-2023 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.submitted.no_result_type_map;

import static org.junit.jupiter.api.Assertions.*;

import java.io.Reader;
import java.util.List;

import org.apache.ibatis.BaseDataTest;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

class NoResultTypeMapTest {

private static SqlSessionFactory sqlSessionFactory;

@BeforeAll
static void setUp() throws Exception {
// create a SqlSessionFactory
try (Reader reader = Resources
.getResourceAsReader("org/apache/ibatis/submitted/no_result_type_map/mybatis-config.xml")) {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
sqlSessionFactory.getConfiguration().addMapper(Mapper.class);
}

// populate in-memory database
BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(),
"org/apache/ibatis/submitted/no_result_type_map/CreateDB.sql");
}

@Test
void shouldGetAUser() {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
Mapper mapper = sqlSession.getMapper(Mapper.class);
User user = mapper.getUser(1);
Assertions.assertEquals("User1", user.getName());
}
}

@Test
void shouldGetAllUsers() {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
Mapper mapper = sqlSession.getMapper(Mapper.class);
List<User> users = mapper.getAllUsers();
Assertions.assertEquals(3, users.size());
}
}

@Test
void shouldResolveInheritedReturnType() {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
Mapper mapper = sqlSession.getMapper(Mapper.class);
List<User> users = mapper.getAllUsersInParent();
Assertions.assertEquals(3, users.size());
}
}

@Test
void shouldFailIfNoMatchingMethod() {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
PersistenceException ex = assertThrows(PersistenceException.class,
() -> sqlSession.selectList("org.apache.ibatis.submitted.no_result_type_map.Mapper.noMatchingMethod"));
ExecutorException cause = (ExecutorException) ex.getCause();
assertEquals("A query was run and no Result Maps were found for the Mapped Statement "
+ "'org.apache.ibatis.submitted.no_result_type_map.Mapper.noMatchingMethod'. "
+ "'resultType' or 'resultMap' must be specified when there is no corresponding method.",
cause.getMessage());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2009-2023 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.submitted.no_result_type_map;

import java.util.List;

public interface ParentMapper<T> {

List<T> getAllUsersInParent();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2009-2023 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.submitted.no_result_type_map;

public class User {

private Integer id;
private String name;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--
-- Copyright 2009-2023 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.
-- You may obtain a copy of the License at
--
-- https://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--

drop table users if exists;

create table users (
id int,
name varchar(20)
);

insert into users (id, name) values(1, 'User1');
insert into users (id, name) values(2, 'User2');
insert into users (id, name) values(3, 'User3');
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2009-2023 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.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="org.apache.ibatis.submitted.no_result_type_map.Mapper">

<select id="getUser">
select * from users where id = #{id}
</select>

<select id="getAllUsers">
select * from users
</select>

<select id="getAllUsersInParent">
select * from users
</select>

<select id="noMatchingMethod">
select * from users
</select>

</mapper>
Loading

0 comments on commit 2d50c4b

Please sign in to comment.