Skip to content

Commit 66508f0

Browse files
committed
Exclude the columns used in constructor-automapping when applying property-automapping
This logic is applied only to the new arg-name-based constructor auto-mapping. Although it is possible (and it may also be the expected behavior) to apply the same logic to the old column-order-based constructor auto-mapping, it will break many existing solutions, probably.
1 parent 7a76f77 commit 66508f0

File tree

3 files changed

+20
-11
lines changed

3 files changed

+20
-11
lines changed

src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ public class DefaultResultSetHandler implements ResultSetHandler {
100100

101101
// Cached Automappings
102102
private final Map<String, List<UnMappedColumnAutoMapping>> autoMappingsCache = new HashMap<>();
103+
private final Map<String, List<String>> constructorAutoMappingColumns = new HashMap<>();
103104

104105
// temporary marking flag that indicate using constructor mapping (use field to reduce memory usage)
105106
private boolean useConstructorMappings;
@@ -524,6 +525,10 @@ private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper
524525
if (autoMapping == null) {
525526
autoMapping = new ArrayList<>();
526527
final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
528+
List<String> mappedInConstructorAutoMapping = constructorAutoMappingColumns.remove(mapKey);
529+
if (mappedInConstructorAutoMapping != null) {
530+
unmappedColumnNames.removeAll(mappedInConstructorAutoMapping);
531+
}
527532
for (String columnName : unmappedColumnNames) {
528533
String propertyName = columnName;
529534
if (columnPrefix != null && !columnPrefix.isEmpty()) {
@@ -660,7 +665,7 @@ private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, Lis
660665
} else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
661666
return objectFactory.create(resultType);
662667
} else if (shouldApplyAutomaticMappings(resultMap, false)) {
663-
return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);
668+
return createByConstructorSignature(rsw, resultMap, columnPrefix, resultType, constructorArgTypes, constructorArgs);
664669
}
665670
throw new ExecutorException("Do not know how to create an instance of " + resultType);
666671
}
@@ -692,9 +697,9 @@ Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType
692697
return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
693698
}
694699

695-
private Object createByConstructorSignature(ResultSetWrapper rsw, Class<?> resultType,
700+
private Object createByConstructorSignature(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix, Class<?> resultType,
696701
List<Class<?>> constructorArgTypes, List<Object> constructorArgs) throws SQLException {
697-
return applyConstructorAutomapping(rsw, resultType, constructorArgTypes, constructorArgs,
702+
return applyConstructorAutomapping(rsw, resultMap, columnPrefix, resultType, constructorArgTypes, constructorArgs,
698703
findConstructorForAutomapping(resultType, rsw).orElseThrow(() -> new ExecutorException(
699704
"No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames())));
700705
}
@@ -733,10 +738,10 @@ private boolean findUsableConstructorByArgTypes(final Constructor<?> constructor
733738
return true;
734739
}
735740

736-
private Object applyConstructorAutomapping(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor) throws SQLException {
741+
private Object applyConstructorAutomapping(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor) throws SQLException {
737742
boolean foundValues = false;
738743
if (configuration.isArgNameBasedConstructorAutoMapping()) {
739-
foundValues = applyArgNameBasedConstructorAutoMapping(rsw, resultType, constructorArgTypes, constructorArgs,
744+
foundValues = applyArgNameBasedConstructorAutoMapping(rsw, resultMap, columnPrefix, resultType, constructorArgTypes, constructorArgs,
740745
constructor, foundValues);
741746
} else {
742747
foundValues = applyColumnOrderBasedConstructorAutomapping(rsw, constructorArgTypes, constructorArgs, constructor,
@@ -759,7 +764,7 @@ private boolean applyColumnOrderBasedConstructorAutomapping(ResultSetWrapper rsw
759764
return foundValues;
760765
}
761766

762-
private boolean applyArgNameBasedConstructorAutoMapping(ResultSetWrapper rsw, Class<?> resultType,
767+
private boolean applyArgNameBasedConstructorAutoMapping(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix, Class<?> resultType,
763768
List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor, boolean foundValues)
764769
throws SQLException {
765770
List<String> missingArgs = null;
@@ -776,6 +781,10 @@ private boolean applyArgNameBasedConstructorAutoMapping(ResultSetWrapper rsw, Cl
776781
Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
777782
constructorArgTypes.add(paramType);
778783
constructorArgs.add(value);
784+
final String mapKey = resultMap.getId() + ":" + columnPrefix;
785+
if (!autoMappingsCache.containsKey(mapKey)) {
786+
constructorAutoMappingColumns.computeIfAbsent(mapKey, k -> new ArrayList<>()).add(columnName);
787+
}
779788
columnNotFound = false;
780789
foundValues = value != null || foundValues;
781790
}

src/test/java/org/apache/ibatis/submitted/arg_name_baesd_constructor_automapping/ArgNameBasedConstructorAutoMappingTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ void shouldFindResultsInDifferentOrder() {
5353
Mapper mapper = sqlSession.getMapper(Mapper.class);
5454
User user = mapper.selectNameAndId(1);
5555
assertEquals(Integer.valueOf(1), user.getId());
56-
assertEquals("User1", user.getName());
56+
assertEquals("User1!", user.getName());
5757
}
5858
}
5959

@@ -65,7 +65,7 @@ void shouldRespectUseColumnLabelSetting() {
6565
Mapper mapper = sqlSession.getMapper(Mapper.class);
6666
User user = mapper.selectNameAndIdWithBogusLabel(1);
6767
assertEquals(Integer.valueOf(1), user.getId());
68-
assertEquals("User1", user.getName());
68+
assertEquals("User1!", user.getName());
6969
} finally {
7070
sqlSessionFactory.getConfiguration().setUseColumnLabel(true);
7171
}
@@ -76,7 +76,7 @@ void shouldErrorMessageBeHelpful() {
7676
// This test requires -parameters compiler option
7777
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
7878
Mapper mapper = sqlSession.getMapper(Mapper.class);
79-
User user = mapper.selectNameAndIdWithBogusLabel(1);
79+
mapper.selectNameAndIdWithBogusLabel(1);
8080
fail("Exception should be thrown");
8181
} catch (PersistenceException e) {
8282
ExecutorException ex = (ExecutorException) e.getCause();
@@ -96,7 +96,7 @@ void shouldWorkWithExtraColumns() {
9696
Mapper mapper = sqlSession.getMapper(Mapper.class);
9797
User user = mapper.selectNameTeamAndId(1);
9898
assertEquals(Integer.valueOf(1), user.getId());
99-
assertEquals("User1", user.getName());
99+
assertEquals("User1!", user.getName());
100100
assertEquals(99, user.getTeam());
101101
}
102102
}

src/test/java/org/apache/ibatis/submitted/arg_name_baesd_constructor_automapping/User.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class User {
2424
public User(Integer id, String name) {
2525
super();
2626
this.id = id;
27-
this.name = name;
27+
this.name = name + "!";
2828
}
2929

3030
public Integer getId() {

0 commit comments

Comments
 (0)