Skip to content

Commit 9ade243

Browse files
committed
Remove constructor verification process
ObjectFactory will throw an appropriate error.
1 parent ccc2071 commit 9ade243

File tree

3 files changed

+10
-112
lines changed

3 files changed

+10
-112
lines changed

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

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -380,8 +380,7 @@ private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap r
380380
throw new ExecutorException("Expected result object to be a pending constructor creation!");
381381
}
382382

383-
createAndStorePendingCreation(resultHandler, resultSet, resultContext, (PendingConstructorCreation) rowValue,
384-
lastHandledCreation == null);
383+
createAndStorePendingCreation(resultHandler, resultSet, resultContext, (PendingConstructorCreation) rowValue);
385384
lastHandledCreation = (PendingConstructorCreation) rowValue;
386385
}
387386
}
@@ -1069,7 +1068,6 @@ private String prependPrefix(String columnName, String prefix) {
10691068
private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap,
10701069
ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
10711070
final boolean useCollectionConstructorInjection = resultMap.hasResultMapsUsingConstructorCollection();
1072-
boolean verifyPendingCreationResult = true;
10731071
PendingConstructorCreation lastHandledCreation = null;
10741072
if (useCollectionConstructorInjection) {
10751073
verifyPendingCreationPreconditions(parentMapping);
@@ -1090,12 +1088,8 @@ private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap r
10901088
// issue #577, #542 && #101
10911089
if (useCollectionConstructorInjection) {
10921090
if (foundNewUniqueRow && lastHandledCreation != null) {
1093-
createAndStorePendingCreation(resultHandler, resultSet, resultContext, lastHandledCreation,
1094-
verifyPendingCreationResult);
1091+
createAndStorePendingCreation(resultHandler, resultSet, resultContext, lastHandledCreation);
10951092
lastHandledCreation = null;
1096-
// we only need to verify the first the result for a given result set
1097-
// as we can assume the next result will look exactly the same w.r.t its mapping
1098-
verifyPendingCreationResult = false;
10991093
}
11001094

11011095
rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
@@ -1117,8 +1111,7 @@ private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap r
11171111
}
11181112

11191113
if (useCollectionConstructorInjection && lastHandledCreation != null) {
1120-
createAndStorePendingCreation(resultHandler, resultSet, resultContext, lastHandledCreation,
1121-
verifyPendingCreationResult);
1114+
createAndStorePendingCreation(resultHandler, resultSet, resultContext, lastHandledCreation);
11221115
} else if (rowValue != null && mappedStatement.isResultOrdered()
11231116
&& shouldProcessMoreRows(resultContext, rowBounds)) {
11241117
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
@@ -1298,7 +1291,7 @@ private void createPendingConstructorCreations(Object rowValue) {
12981291
for (Object pendingCreation : pendingCreations) {
12991292
if (pendingCreation instanceof PendingConstructorCreation) {
13001293
final PendingConstructorCreation pendingConstructorCreation = (PendingConstructorCreation) pendingCreation;
1301-
targetMetaObject.add(pendingConstructorCreation.create(objectFactory, false));
1294+
targetMetaObject.add(pendingConstructorCreation.create(objectFactory));
13021295
}
13031296
}
13041297
}
@@ -1317,9 +1310,8 @@ private void verifyPendingCreationPreconditions(ResultMapping parentMapping) {
13171310
}
13181311

13191312
private void createAndStorePendingCreation(ResultHandler<?> resultHandler, ResultSet resultSet,
1320-
DefaultResultContext<Object> resultContext, PendingConstructorCreation pendingCreation, boolean shouldVerify)
1321-
throws SQLException {
1322-
final Object result = pendingCreation.create(objectFactory, shouldVerify);
1313+
DefaultResultContext<Object> resultContext, PendingConstructorCreation pendingCreation) throws SQLException {
1314+
final Object result = pendingCreation.create(objectFactory);
13231315
storeObject(resultHandler, resultContext, result, null, resultSet);
13241316
nestedResultObjects.clear();
13251317
}

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

Lines changed: 2 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,16 @@
1515
*/
1616
package org.apache.ibatis.executor.resultset;
1717

18-
import java.lang.reflect.Constructor;
19-
import java.lang.reflect.ParameterizedType;
20-
import java.lang.reflect.Type;
2118
import java.util.ArrayList;
2219
import java.util.Collection;
23-
import java.util.Collections;
2420
import java.util.HashMap;
2521
import java.util.List;
2622
import java.util.Map;
27-
import java.util.Optional;
28-
import java.util.stream.Collectors;
2923

3024
import org.apache.ibatis.executor.ExecutorException;
3125
import org.apache.ibatis.mapping.ResultMap;
3226
import org.apache.ibatis.mapping.ResultMapping;
3327
import org.apache.ibatis.reflection.ReflectionException;
34-
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
3528
import org.apache.ibatis.reflection.factory.ObjectFactory;
3629

3730
/**
@@ -108,87 +101,6 @@ void linkCollectionValue(ResultMapping constructorMapping, Object value) {
108101
linkedCollectionsByKey.get(creationKey).add(value);
109102
}
110103

111-
/**
112-
* Verifies preconditions before we can actually create the result object, this is more of a sanity check to ensure
113-
* all the mappings are as we expect them to be.
114-
* <p>
115-
* And if anything went wrong, provide the user with more information as to what went wrong
116-
*
117-
* @param objectFactory
118-
* the object factory
119-
*/
120-
private void verifyCanCreate(ObjectFactory objectFactory) {
121-
// if a custom object factory was supplied, we cannot reasionably verify that creation will work
122-
// thus, we disable verification and leave it up to the end user.
123-
if (!DefaultObjectFactory.class.equals(objectFactory.getClass())) {
124-
return;
125-
}
126-
127-
// before we create, we need to get the constructor to be used and verify our types match
128-
// since we added to the collection completely unchecked
129-
final Constructor<?> resolvedConstructor = resolveConstructor(resultType, constructorArgTypes);
130-
final Type[] genericParameterTypes = resolvedConstructor.getGenericParameterTypes();
131-
for (int i = 0; i < genericParameterTypes.length; i++) {
132-
if (!linkedCollectionMetaInfo.containsKey(i)) {
133-
continue;
134-
}
135-
136-
final PendingCreationMetaInfo creationMetaInfo = linkedCollectionMetaInfo.get(i);
137-
final Class<?> resolvedItemType = checkResolvedItemType(creationMetaInfo, genericParameterTypes[i]);
138-
139-
// ensure we have an empty collection if there are linked creations for this arg
140-
final PendingCreationKey pendingCreationKey = creationMetaInfo.getPendingCreationKey();
141-
if (linkedCreationsByKey.containsKey(pendingCreationKey)) {
142-
final Object emptyCollection = constructorArgs.get(i);
143-
if (emptyCollection == null || !objectFactory.isCollection(emptyCollection.getClass())) {
144-
throw new ExecutorException(
145-
"Expected empty collection for '" + resolvedItemType + "', MyBatis internal error!");
146-
}
147-
} else {
148-
final Object linkedCollection = constructorArgs.get(i);
149-
if (!linkedCollectionsByKey.containsKey(pendingCreationKey)) {
150-
throw new ExecutorException(
151-
"Expected linked collection for key '" + pendingCreationKey + "', not found! MyBatis internal error!");
152-
}
153-
154-
// comparing memory locations here (we rely on that fact)
155-
if (linkedCollection != linkedCollectionsByKey.get(pendingCreationKey)) {
156-
throw new ExecutorException("Expected linked collection in creation to be the same as arg for resultMap '"
157-
+ pendingCreationKey + "', not equal! MyBatis internal error!");
158-
}
159-
}
160-
}
161-
}
162-
163-
private static <T> Constructor<T> resolveConstructor(Class<T> type, List<Class<?>> constructorArgTypes) {
164-
try {
165-
if (constructorArgTypes == null) {
166-
return type.getDeclaredConstructor();
167-
}
168-
169-
return type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[0]));
170-
} catch (Exception e) {
171-
String argTypes = Optional.ofNullable(constructorArgTypes).orElseGet(Collections::emptyList).stream()
172-
.map(Class::getSimpleName).collect(Collectors.joining(","));
173-
throw new ReflectionException(
174-
"Error resolving constructor for " + type + " with invalid types (" + argTypes + ") . Cause: " + e, e);
175-
}
176-
}
177-
178-
private static Class<?> checkResolvedItemType(PendingCreationMetaInfo creationMetaInfo, Type genericParameterTypes) {
179-
final ParameterizedType genericParameterType = (ParameterizedType) genericParameterTypes;
180-
final Class<?> expectedType = (Class<?>) genericParameterType.getActualTypeArguments()[0];
181-
final Class<?> resolvedItemType = creationMetaInfo.getArgumentType();
182-
183-
if (!expectedType.isAssignableFrom(resolvedItemType)) {
184-
throw new ReflectionException(
185-
"Expected type '" + resolvedItemType + "', while the actual type of the collection was '" + expectedType
186-
+ "', ensure your resultMap matches the type of the collection you are trying to inject");
187-
}
188-
189-
return resolvedItemType;
190-
}
191-
192104
@Override
193105
public String toString() {
194106
return "PendingConstructorCreation(" + this.hashCode() + "){" + "resultType=" + resultType + '}';
@@ -199,16 +111,10 @@ public String toString() {
199111
*
200112
* @param objectFactory
201113
* the object factory
202-
* @param verifyCreate
203-
* should we verify this object can be created, should only be needed once
204114
*
205115
* @return the new immutable result
206116
*/
207-
Object create(ObjectFactory objectFactory, boolean verifyCreate) {
208-
if (verifyCreate) {
209-
verifyCanCreate(objectFactory);
210-
}
211-
117+
Object create(ObjectFactory objectFactory) {
212118
final List<Object> newArguments = new ArrayList<>(constructorArgs.size());
213119
for (int i = 0; i < constructorArgs.size(); i++) {
214120
final PendingCreationMetaInfo creationMetaInfo = linkedCollectionMetaInfo.get(i);
@@ -228,7 +134,7 @@ Object create(ObjectFactory objectFactory, boolean verifyCreate) {
228134
final List<PendingConstructorCreation> linkedCreations = linkedCreationsByKey.get(pendingCreationKey);
229135

230136
for (PendingConstructorCreation linkedCreation : linkedCreations) {
231-
emptyCollection.add(linkedCreation.create(objectFactory, verifyCreate));
137+
emptyCollection.add(linkedCreation.create(objectFactory));
232138
}
233139

234140
newArguments.add(emptyCollection);

src/test/java/org/apache/ibatis/immutable/ImmutableConstructorTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ void shouldSelectBlogWithPostsButNoCommentsOrTags() {
143143
void shouldFailToSelectBlogWithMissingConstructorForPostComments() {
144144
try (SqlSession session = sqlSessionFactory.openSession()) {
145145
ImmutableBlogMapper mapper = session.getMapper(ImmutableBlogMapper.class);
146-
assertThatThrownBy(() -> mapper.retrieveAllBlogsWithMissingConstructor()).isInstanceOf(PersistenceException.class)
146+
assertThatThrownBy(mapper::retrieveAllBlogsWithMissingConstructor).isInstanceOf(PersistenceException.class)
147147
.hasCauseInstanceOf(ReflectionException.class).hasMessageContaining(
148-
"Error resolving constructor for class org.apache.ibatis.domain.blog.immutable.ImmutablePost with invalid types");
148+
"Error instantiating class org.apache.ibatis.domain.blog.immutable.ImmutablePost with invalid types");
149149
}
150150
}
151151
}

0 commit comments

Comments
 (0)