From ac538c6d29a9162b4ea3af467fa0f2e62b3f1e1e Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 23 May 2022 14:07:54 +0200 Subject: [PATCH] Improve exception message when deriving collection name from type. We now provide a better worded exception message when trying to derive the collection name for a type that is not considered a user types (such as org.bson.Document). Update the Javadoc to hint to the error. Closes #4061 Original pull request: #4062. --- .../data/mongodb/core/EntityOperations.java | 6 ++- .../data/mongodb/core/MongoOperations.java | 39 +++++++++++++++-- .../mongodb/core/ReactiveMongoOperations.java | 43 ++++++++++++++++++- 3 files changed, 83 insertions(+), 5 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/EntityOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/EntityOperations.java index 6908d331f..e46d98305 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/EntityOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/EntityOperations.java @@ -174,7 +174,11 @@ class EntityOperations { "No class parameter provided, entity collection can't be determined!"); } - return context.getRequiredPersistentEntity(entityClass).getCollection(); + MongoPersistentEntity persistentEntity = context.getPersistentEntity(entityClass); + if(persistentEntity == null) { + throw new MappingException(String.format("Collection name cannot be derived for type %s. Is it a store native type?", entityClass)); + } + return persistentEntity.getCollection(); } public Query getByIdInQuery(Collection entities) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java index f889e95c7..04aa51069 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java @@ -79,6 +79,7 @@ public interface MongoOperations extends FluentMongoOperations { * * @param entityClass must not be {@literal null}. * @return never {@literal null}. + * @throws org.springframework.data.mapping.MappingException if the collection name cannot be derived from the type. */ String getCollectionName(Class entityClass); @@ -947,6 +948,8 @@ public interface MongoOperations extends FluentMongoOperations { * fields specification. Must not be {@literal null}. * @param replacement the replacement document. Must not be {@literal null}. * @return the converted object that was updated or {@literal null}, if not found. + * @throws org.springframework.data.mapping.MappingException if the collection name cannot be + * {@link #getCollectionName(Class) derived} from the given replacement value. * @since 2.1 */ @Nullable @@ -988,6 +991,8 @@ public interface MongoOperations extends FluentMongoOperations { * @return the converted object that was updated or {@literal null}, if not found. Depending on the value of * {@link FindAndReplaceOptions#isReturnNew()} this will either be the object as it was before the update or * as it is after the update. + * @throws org.springframework.data.mapping.MappingException if the collection name cannot be + * {@link #getCollectionName(Class) derived} from the given replacement value. * @since 2.1 */ @Nullable @@ -1061,6 +1066,8 @@ public interface MongoOperations extends FluentMongoOperations { * @return the converted object that was updated or {@literal null}, if not found. Depending on the value of * {@link FindAndReplaceOptions#isReturnNew()} this will either be the object as it was before the update or * as it is after the update. + * @throws org.springframework.data.mapping.MappingException if the collection name cannot be + * {@link #getCollectionName(Class) derived} from the given replacement value. * @since 2.1 */ @Nullable @@ -1144,6 +1151,8 @@ public interface MongoOperations extends FluentMongoOperations { * {@literal null}. * @param entityClass class that determines the collection to use. Must not be {@literal null}. * @return the count of matching documents. + * @throws org.springframework.data.mapping.MappingException if the collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. * @see #exactCount(Query, Class) * @see #estimatedCount(Class) */ @@ -1199,6 +1208,8 @@ public interface MongoOperations extends FluentMongoOperations { * * @param entityClass must not be {@literal null}. * @return the estimated number of documents. + * @throws org.springframework.data.mapping.MappingException if the collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. * @since 3.1 */ default long estimatedCount(Class entityClass) { @@ -1235,6 +1246,8 @@ public interface MongoOperations extends FluentMongoOperations { * {@literal null}. * @param entityClass class that determines the collection to use. Must not be {@literal null}. * @return the count of matching documents. + * @throws org.springframework.data.mapping.MappingException if the collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. * @since 3.4 */ default long exactCount(Query query, Class entityClass) { @@ -1302,6 +1315,8 @@ public interface MongoOperations extends FluentMongoOperations { * @param objectToSave the object to store in the collection. Must not be {@literal null}. * @return the inserted object. * @throws IllegalArgumentException in case the {@code objectToSave} is collection-like. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given object type. */ T insert(T objectToSave); @@ -1326,6 +1341,8 @@ public interface MongoOperations extends FluentMongoOperations { * @param batchToSave the batch of objects to save. Must not be {@literal null}. * @param entityClass class that determines the collection to use. Must not be {@literal null}. * @return the inserted objects that. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. */ Collection insert(Collection batchToSave, Class entityClass); @@ -1344,6 +1361,8 @@ public interface MongoOperations extends FluentMongoOperations { * * @param objectsToSave the list of objects to save. Must not be {@literal null}. * @return the inserted objects. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} for the given objects. */ Collection insertAll(Collection objectsToSave); @@ -1362,6 +1381,8 @@ public interface MongoOperations extends FluentMongoOperations { * @param objectToSave the object to store in the collection. Must not be {@literal null}. * @return the saved object. * @throws IllegalArgumentException in case the {@code objectToSave} is collection-like. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given object type. */ T save(T objectToSave); @@ -1396,9 +1417,11 @@ public interface MongoOperations extends FluentMongoOperations { * the existing object. Must not be {@literal null}. * @param entityClass class that determines the collection to use. Must not be {@literal null}. * @return the {@link UpdateResult} which lets you access the results of the previous write. - * @since 3.0 * @see Update * @see AggregationUpdate + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. + * @since 3.0 */ UpdateResult upsert(Query query, UpdateDefinition update, Class entityClass); @@ -1450,9 +1473,11 @@ public interface MongoOperations extends FluentMongoOperations { * the existing. Must not be {@literal null}. * @param entityClass class that determines the collection to use. * @return the {@link UpdateResult} which lets you access the results of the previous write. - * @since 3.0 * @see Update * @see AggregationUpdate + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. + * @since 3.0 */ UpdateResult updateFirst(Query query, UpdateDefinition update, Class entityClass); @@ -1504,9 +1529,11 @@ public interface MongoOperations extends FluentMongoOperations { * the existing. Must not be {@literal null}. * @param entityClass class of the pojo to be operated on. Must not be {@literal null}. * @return the {@link UpdateResult} which lets you access the results of the previous write. - * @since 3.0 + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. * @see Update * @see AggregationUpdate + * @since 3.0 */ UpdateResult updateMulti(Query query, UpdateDefinition update, Class entityClass); @@ -1554,6 +1581,8 @@ public interface MongoOperations extends FluentMongoOperations { * * @param object must not be {@literal null}. * @return the {@link DeleteResult} which lets you access the results of the previous delete. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given object type. */ DeleteResult remove(Object object); @@ -1577,6 +1606,8 @@ public interface MongoOperations extends FluentMongoOperations { * @param entityClass class that determines the collection to use. * @return the {@link DeleteResult} which lets you access the results of the previous delete. * @throws IllegalArgumentException when {@literal query} or {@literal entityClass} is {@literal null}. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. */ DeleteResult remove(Query query, Class entityClass); @@ -1624,6 +1655,8 @@ public interface MongoOperations extends FluentMongoOperations { * @param query the query document that specifies the criteria used to find and remove documents. * @param entityClass class of the pojo to be operated on. * @return the {@link List} converted objects deleted by this operation. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. * @since 1.5 */ List findAllAndRemove(Query query, Class entityClass); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java index 1bde11633..f031a9fa5 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java @@ -756,6 +756,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * fields specification. Must not be {@literal null}. * @param replacement the replacement document. Must not be {@literal null}. * @return the converted object that was updated or {@link Mono#empty()}, if not found. + * @throws org.springframework.data.mapping.MappingException if the collection name cannot be + * {@link #getCollectionName(Class) derived} from the given replacement value. * @since 2.1 */ default Mono findAndReplace(Query query, T replacement) { @@ -795,6 +797,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * @return the converted object that was updated or {@link Mono#empty()}, if not found. Depending on the value of * {@link FindAndReplaceOptions#isReturnNew()} this will either be the object as it was before the update or * as it is after the update. + * @throws org.springframework.data.mapping.MappingException if the collection name cannot be + * {@link #getCollectionName(Class) derived} from the given replacement value. * @since 2.1 */ default Mono findAndReplace(Query query, T replacement, FindAndReplaceOptions options) { @@ -865,6 +869,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * @return the converted object that was updated or {@link Mono#empty()}, if not found. Depending on the value of * {@link FindAndReplaceOptions#isReturnNew()} this will either be the object as it was before the update or * as it is after the update. + * @throws org.springframework.data.mapping.MappingException if the collection name cannot be + * {@link #getCollectionName(Class) derived} from the given replacement value. * @since 2.1 */ default Mono findAndReplace(Query query, S replacement, FindAndReplaceOptions options, Class entityType, @@ -948,6 +954,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * {@literal null}. * @param entityClass class that determines the collection to use. Must not be {@literal null}. * @return the count of matching documents. + * @throws org.springframework.data.mapping.MappingException if the collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. * @see #exactCount(Query, Class) * @see #estimatedCount(Class) */ @@ -1004,6 +1012,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * * @param entityClass must not be {@literal null}. * @return a {@link Mono} emitting the estimated number of documents. + * @throws org.springframework.data.mapping.MappingException if the collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. * @since 3.1 */ default Mono estimatedCount(Class entityClass) { @@ -1041,6 +1051,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * {@literal null}. * @param entityClass class that determines the collection to use. Must not be {@literal null}. * @return the count of matching documents. + * @throws org.springframework.data.mapping.MappingException if the collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. * @since 3.4 */ default Mono exactCount(Query query, Class entityClass) { @@ -1111,6 +1123,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * @param objectToSave the object to store in the collection. Must not be {@literal null}. * @return the inserted object. * @throws IllegalArgumentException in case the {@code objectToSave} is collection-like. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given object type. */ Mono insert(T objectToSave); @@ -1136,7 +1150,9 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * * @param batchToSave the batch of objects to save. Must not be {@literal null}. * @param entityClass class that determines the collection to use. Must not be {@literal null}. - * @return the inserted objects . + * @return the inserted objects. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. */ Flux insert(Collection batchToSave, Class entityClass); @@ -1155,6 +1171,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * * @param objectsToSave the list of objects to save. Must not be {@literal null}. * @return the saved objects. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} for the given objects. */ Flux insertAll(Collection objectsToSave); @@ -1182,6 +1200,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * @param batchToSave the publisher which provides objects to save. Must not be {@literal null}. * @param entityClass class that determines the collection to use. Must not be {@literal null}. * @return the inserted objects. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} for the type. */ Flux insertAll(Mono> batchToSave, Class entityClass); @@ -1221,6 +1241,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * @param objectToSave the object to store in the collection. Must not be {@literal null}. * @return the saved object. * @throws IllegalArgumentException in case the {@code objectToSave} is collection-like. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given object type. */ Mono save(T objectToSave); @@ -1257,6 +1279,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * * @param objectToSave the object to store in the collection. Must not be {@literal null}. * @return the saved object. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given object type. */ Mono save(Mono objectToSave); @@ -1290,6 +1314,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * the existing object. Must not be {@literal null}. * @param entityClass class that determines the collection to use. Must not be {@literal null}. * @return the {@link UpdateResult} which lets you access the results of the previous write. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. * @since 3.0 * @see Update * @see AggregationUpdate @@ -1344,6 +1370,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * the existing. Must not be {@literal null}. * @param entityClass class that determines the collection to use. * @return the {@link UpdateResult} which lets you access the results of the previous write. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. * @since 3.0 * @see Update * @see AggregationUpdate @@ -1399,6 +1427,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * @param entityClass class of the pojo to be operated on. Must not be {@literal null}. * @return the {@link UpdateResult} which lets you access the results of the previous write. * @since 3.0 + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. * @see Update * @see AggregationUpdate */ @@ -1445,6 +1475,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * * @param object must not be {@literal null}. * @return the {@link DeleteResult} which lets you access the results of the previous delete. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given object type. */ Mono remove(Object object); @@ -1462,6 +1494,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * * @param objectToRemove must not be {@literal null}. * @return the {@link DeleteResult} which lets you access the results of the previous delete. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given object type. */ Mono remove(Mono objectToRemove); @@ -1481,6 +1515,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * @param query the query document that specifies the criteria used to remove a record. * @param entityClass class that determines the collection to use. * @return the {@link DeleteResult} which lets you access the results of the previous delete. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. */ Mono remove(Query query, Class entityClass); @@ -1524,6 +1560,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * @param query the query document that specifies the criteria used to find and remove documents. * @param entityClass class of the pojo to be operated on. * @return the {@link Flux} converted objects deleted by this operation. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. */ Flux findAllAndRemove(Query query, Class entityClass); @@ -1555,6 +1593,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * specification. * @param entityClass the parametrized type of the returned {@link Flux}. * @return the {@link Flux} of converted objects. + * @throws org.springframework.data.mapping.MappingException if the target collection name cannot be + * {@link #getCollectionName(Class) derived} from the given type. */ Flux tail(Query query, Class entityClass); @@ -1703,6 +1743,7 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * * @param entityClass must not be {@literal null}. * @return never {@literal null}. + * @throws org.springframework.data.mapping.MappingException if the collection name cannot be derived from the type. * @since 2.1 */ String getCollectionName(Class entityClass);