Skip to content

Commit 2ef9844

Browse files
Move collection like check for reactive-/template insert methods to EntityOperations.
Reintroduce the protected ensureNotIterable method in MongoTemplate to keep the API stable. Delegate to the newly introduced method and move the collection like check to EntityOperations. Original Pull Request: spring-projects#590
1 parent 6f13837 commit 2ef9844

File tree

5 files changed

+90
-28
lines changed

5 files changed

+90
-28
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/EntityOperations.java

+16
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.springframework.data.mongodb.core;
1717

1818
import java.util.Collection;
19+
import java.util.Iterator;
1920
import java.util.Map;
2021
import java.util.Optional;
2122

@@ -40,6 +41,7 @@
4041
import org.springframework.util.ClassUtils;
4142
import org.springframework.util.LinkedMultiValueMap;
4243
import org.springframework.util.MultiValueMap;
44+
import org.springframework.util.ObjectUtils;
4345

4446
/**
4547
* Common operations performed on an entity in the context of it's mapping metadata.
@@ -107,6 +109,20 @@ <T> AdaptibleEntity<T> forEntity(T entity, ConversionService conversionService)
107109
return AdaptibleMappedEntity.of(entity, context, conversionService);
108110
}
109111

112+
/**
113+
* @param source can be {@literal null}.
114+
* @return {@literal true} if the given value is an {@literal array}, {@link Collection} or {@link Iterator}.
115+
* @since 3.2
116+
*/
117+
static boolean isCollectionLike(@Nullable Object source) {
118+
119+
if (source == null) {
120+
return false;
121+
}
122+
123+
return ObjectUtils.isArray(source) || source instanceof Collection || source instanceof Iterator;
124+
}
125+
110126
/**
111127
* @param entityClass should not be null.
112128
* @return the {@link MongoPersistentEntity#getCollection() collection name}.

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java

+24-8
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,6 @@ public void dropCollection(String collectionName) {
705705
});
706706
}
707707

708-
709708
@Override
710709
public IndexOperations indexOps(String collectionName) {
711710
return indexOps(collectionName, null);
@@ -1154,7 +1153,7 @@ public <T> T insert(T objectToSave) {
11541153

11551154
Assert.notNull(objectToSave, "ObjectToSave must not be null!");
11561155

1157-
ensureNotAnArrayOrCollection(objectToSave);
1156+
ensureNotIterable(objectToSave);
11581157
return insert(objectToSave, getCollectionName(ClassUtils.getUserClass(objectToSave)));
11591158
}
11601159

@@ -1169,15 +1168,32 @@ public <T> T insert(T objectToSave, String collectionName) {
11691168
Assert.notNull(objectToSave, "ObjectToSave must not be null!");
11701169
Assert.notNull(collectionName, "CollectionName must not be null!");
11711170

1172-
ensureNotAnArrayOrCollection(objectToSave);
1171+
ensureNotIterable(objectToSave);
11731172
return (T) doInsert(collectionName, objectToSave, this.mongoConverter);
11741173
}
11751174

1176-
protected void ensureNotAnArrayOrCollection(@Nullable Object o) {
1177-
if (null != o) {
1178-
if (o.getClass().isArray() || (o instanceof Collection) || (o instanceof Iterator)) {
1179-
throw new IllegalArgumentException("Cannot use a collection here.");
1180-
}
1175+
/**
1176+
* Ensure the given {@literal source} is not an {@link java.lang.reflect.Array}, {@link Collection} or
1177+
* {@link Iterator}.
1178+
*
1179+
* @param source can be {@literal null}.
1180+
* @deprecated since 3.2. Call {@link #ensureNotCollectionLike(Object)} instead.
1181+
*/
1182+
protected void ensureNotIterable(@Nullable Object source) {
1183+
ensureNotCollectionLike(source);
1184+
}
1185+
1186+
/**
1187+
* Ensure the given {@literal source} is not an {@link java.lang.reflect.Array}, {@link Collection} or
1188+
* {@link Iterator}.
1189+
*
1190+
* @param source can be {@literal null}.
1191+
* @since 3.2.
1192+
*/
1193+
protected void ensureNotCollectionLike(@Nullable Object source) {
1194+
1195+
if (EntityOperations.isCollectionLike(source)) {
1196+
throw new IllegalArgumentException("Cannot use a collection here.");
11811197
}
11821198
}
11831199

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java

+21-20
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717

1818
import static org.springframework.data.mongodb.core.query.SerializationUtils.*;
1919

20-
import org.springframework.data.mongodb.core.QueryOperations.AggregationDefinition;
21-
import org.springframework.data.mongodb.core.aggregation.RelaxedTypeBasedAggregationOperationContext;
2220
import reactor.core.publisher.Flux;
2321
import reactor.core.publisher.Mono;
2422
import reactor.util.function.Tuple2;
@@ -38,7 +36,6 @@
3836
import org.reactivestreams.Subscriber;
3937
import org.slf4j.Logger;
4038
import org.slf4j.LoggerFactory;
41-
4239
import org.springframework.beans.BeansException;
4340
import org.springframework.context.ApplicationContext;
4441
import org.springframework.context.ApplicationContextAware;
@@ -63,6 +60,7 @@
6360
import org.springframework.data.mongodb.ReactiveMongoDatabaseUtils;
6461
import org.springframework.data.mongodb.SessionSynchronization;
6562
import org.springframework.data.mongodb.core.EntityOperations.AdaptibleEntity;
63+
import org.springframework.data.mongodb.core.QueryOperations.AggregationDefinition;
6664
import org.springframework.data.mongodb.core.QueryOperations.CountContext;
6765
import org.springframework.data.mongodb.core.QueryOperations.DeleteContext;
6866
import org.springframework.data.mongodb.core.QueryOperations.DistinctQueryContext;
@@ -72,6 +70,7 @@
7270
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
7371
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
7472
import org.springframework.data.mongodb.core.aggregation.PrefixingDelegatingAggregationOperationContext;
73+
import org.springframework.data.mongodb.core.aggregation.RelaxedTypeBasedAggregationOperationContext;
7574
import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext;
7675
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
7776
import org.springframework.data.mongodb.core.convert.DbRefResolver;
@@ -157,18 +156,6 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
157156

158157
private static final Logger LOGGER = LoggerFactory.getLogger(ReactiveMongoTemplate.class);
159158
private static final WriteResultChecking DEFAULT_WRITE_RESULT_CHECKING = WriteResultChecking.NONE;
160-
private static final Collection<Class<?>> ITERABLE_CLASSES;
161-
162-
static {
163-
164-
Set<Class<?>> iterableClasses = new HashSet<>();
165-
iterableClasses.add(List.class);
166-
iterableClasses.add(Collection.class);
167-
iterableClasses.add(Iterator.class);
168-
iterableClasses.add(Publisher.class);
169-
170-
ITERABLE_CLASSES = Collections.unmodifiableCollection(iterableClasses);
171-
}
172159

173160
private final MongoConverter mongoConverter;
174161
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
@@ -2668,13 +2655,27 @@ private MongoCollection<Document> getAndPrepareCollection(MongoDatabase db, Stri
26682655
}
26692656
}
26702657

2671-
protected void ensureNotIterable(Object o) {
2658+
/**
2659+
* Ensure the given {@literal source} is not an {@link java.lang.reflect.Array}, {@link Collection} or
2660+
* {@link Iterator}.
2661+
*
2662+
* @param source can be {@literal null}.
2663+
* @deprecated since 3.2. Call {@link #ensureNotCollectionLike(Object)} instead.
2664+
*/
2665+
protected void ensureNotIterable(@Nullable Object source) {
2666+
ensureNotCollectionLike(source);
2667+
}
26722668

2673-
boolean isIterable = o.getClass().isArray()
2674-
|| ITERABLE_CLASSES.stream().anyMatch(iterableClass -> iterableClass.isAssignableFrom(o.getClass())
2675-
|| o.getClass().getName().equals(iterableClass.getName()));
2669+
/**
2670+
* Ensure the given {@literal source} is not an {@link java.lang.reflect.Array}, {@link Collection} or
2671+
* {@link Iterator}.
2672+
*
2673+
* @param source can be {@literal null}.
2674+
* @since 3.2.
2675+
*/
2676+
protected void ensureNotCollectionLike(@Nullable Object source) {
26762677

2677-
if (isIterable) {
2678+
if (EntityOperations.isCollectionLike(source) || source instanceof Publisher) {
26782679
throw new IllegalArgumentException("Cannot use a collection here.");
26792680
}
26802681
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java

+20
Original file line numberDiff line numberDiff line change
@@ -2206,6 +2206,13 @@ void esitmatedCountShouldBeDelegatedCorrectly() {
22062206
verify(collection).estimatedDocumentCount(any());
22072207
}
22082208

2209+
@Test // GH-2911
2210+
void insertErrorsOnCustomIteratorImplementation() {
2211+
2212+
assertThatExceptionOfType(IllegalArgumentException.class)
2213+
.isThrownBy(() -> template.insert(new TypeImplementingIterator()));
2214+
}
2215+
22092216
class AutogenerateableId {
22102217

22112218
@Id BigInteger id;
@@ -2299,6 +2306,19 @@ static class Sith {
22992306
@Field("firstname") String name;
23002307
}
23012308

2309+
static class TypeImplementingIterator implements Iterator {
2310+
2311+
@Override
2312+
public boolean hasNext() {
2313+
return false;
2314+
}
2315+
2316+
@Override
2317+
public Object next() {
2318+
return null;
2319+
}
2320+
}
2321+
23022322
/**
23032323
* Mocks out the {@link MongoTemplate#getDb()} method to return the {@link DB} mock instead of executing the actual
23042324
* behaviour.

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java

+9
Original file line numberDiff line numberDiff line change
@@ -1400,6 +1400,15 @@ void esitmatedCountShouldBeDelegatedCorrectly() {
14001400
verify(collection).estimatedDocumentCount(any());
14011401
}
14021402

1403+
@Test // GH-2911
1404+
void insertErrorsOnPublisher() {
1405+
1406+
Publisher<String> publisher = Mono.just("data");
1407+
1408+
assertThatExceptionOfType(IllegalArgumentException.class)
1409+
.isThrownBy(() -> template.insert(publisher));
1410+
}
1411+
14031412
private void stubFindSubscribe(Document document) {
14041413

14051414
Publisher<Document> realPublisher = Flux.just(document);

0 commit comments

Comments
 (0)