diff --git a/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java b/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java index 0973b36a6da..7503c94b248 100644 --- a/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java +++ b/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java @@ -710,12 +710,14 @@ private Optional> findConstructorForAutomapping(final Class re if (constructors.length == 1) { return Optional.of(constructors[0]); } - for (final Constructor constructor : constructors) { - if (constructor.isAnnotationPresent(AutomapConstructor.class)) { - return Optional.of(constructor); - } - } - if (configuration.isArgNameBasedConstructorAutoMapping()) { + Optional> annotated = Arrays.stream(constructors) + .filter(x -> x.isAnnotationPresent(AutomapConstructor.class)) + .reduce((x, y) -> { + throw new ExecutorException("@AutomapConstructor should be used in only one constructor."); + }); + if (annotated.isPresent()) { + return annotated; + } else if (configuration.isArgNameBasedConstructorAutoMapping()) { // Finding-best-match type implementation is possible, // but using @AutomapConstructor seems sufficient. throw new ExecutorException(MessageFormat.format( diff --git a/src/test/java/org/apache/ibatis/autoconstructor/AutoConstructorMapper.java b/src/test/java/org/apache/ibatis/autoconstructor/AutoConstructorMapper.java index f4fde3da77b..11f3623d6ec 100644 --- a/src/test/java/org/apache/ibatis/autoconstructor/AutoConstructorMapper.java +++ b/src/test/java/org/apache/ibatis/autoconstructor/AutoConstructorMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2021 the original author or authors. + * Copyright 2009-2022 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. @@ -29,6 +29,9 @@ public interface AutoConstructorMapper { @Select("SELECT * FROM subject") List getAnnotatedSubjects(); + @Select("SELECT * FROM subject") + List getBadAnnotatedSubjects(); + @Select("SELECT * FROM subject") List getBadSubjects(); diff --git a/src/test/java/org/apache/ibatis/autoconstructor/AutoConstructorTest.java b/src/test/java/org/apache/ibatis/autoconstructor/AutoConstructorTest.java index 83da262c18f..accc1fe6a8e 100644 --- a/src/test/java/org/apache/ibatis/autoconstructor/AutoConstructorTest.java +++ b/src/test/java/org/apache/ibatis/autoconstructor/AutoConstructorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2021 the original author or authors. + * Copyright 2009-2022 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. @@ -15,6 +15,7 @@ */ package org.apache.ibatis.autoconstructor; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -23,6 +24,7 @@ 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; @@ -71,6 +73,16 @@ void annotatedSubject() { } } + @Test + void badMultipleAnnotatedSubject() { + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + final AutoConstructorMapper mapper = sqlSession.getMapper(AutoConstructorMapper.class); + final PersistenceException ex = assertThrows(PersistenceException.class, mapper::getBadAnnotatedSubjects); + final ExecutorException cause = (ExecutorException) ex.getCause(); + assertEquals("@AutomapConstructor should be used in only one constructor.", cause.getMessage()); + } + } + @Test void badSubject() { try (SqlSession sqlSession = sqlSessionFactory.openSession()) { diff --git a/src/test/java/org/apache/ibatis/autoconstructor/BadAnnotatedSubject.java b/src/test/java/org/apache/ibatis/autoconstructor/BadAnnotatedSubject.java new file mode 100644 index 00000000000..7c4a46b25f9 --- /dev/null +++ b/src/test/java/org/apache/ibatis/autoconstructor/BadAnnotatedSubject.java @@ -0,0 +1,44 @@ +/* + * Copyright 2009-2022 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 + * + * http://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.autoconstructor; + +import org.apache.ibatis.annotations.AutomapConstructor; + +public class BadAnnotatedSubject { + private final int id; + private final String name; + private final int age; + private final int height; + private final int weight; + + @AutomapConstructor + public BadAnnotatedSubject(final int id, final String name, final int age, final int height, final int weight) { + this.id = id; + this.name = name; + this.age = age; + this.height = height; + this.weight = weight; + } + + @AutomapConstructor + public BadAnnotatedSubject(final int id, final String name, final int age) { + this.id = id; + this.name = name; + this.age = age; + this.height = 0; + this.weight = 0; + } +}