diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/gridfs/GridFsTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/gridfs/GridFsTemplate.java index b9a6089c3..f32540935 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/gridfs/GridFsTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/gridfs/GridFsTemplate.java @@ -58,10 +58,14 @@ import com.mongodb.client.gridfs.model.GridFSUploadOptions; */ public class GridFsTemplate extends GridFsOperationsSupport implements GridFsOperations, ResourcePatternResolver { - private Supplier bucketSupplier; + private final Supplier bucketSupplier; /** * Creates a new {@link GridFsTemplate} using the given {@link MongoDatabaseFactory} and {@link MongoConverter}. + *

+ * Note that the {@link GridFSBucket} is obtained only once from {@link MongoDatabaseFactory#getMongoDatabase() + * MongoDatabase}. Use {@link #GridFsTemplate(MongoConverter, Supplier)} if you want to use different buckets from the + * same Template instance. * * @param dbFactory must not be {@literal null}. * @param converter must not be {@literal null}. @@ -72,6 +76,10 @@ public class GridFsTemplate extends GridFsOperationsSupport implements GridFsOpe /** * Creates a new {@link GridFsTemplate} using the given {@link MongoDatabaseFactory} and {@link MongoConverter}. + *

+ * Note that the {@link GridFSBucket} is obtained only once from {@link MongoDatabaseFactory#getMongoDatabase() + * MongoDatabase}. Use {@link #GridFsTemplate(MongoConverter, Supplier)} if you want to use different buckets from the + * same Template instance. * * @param dbFactory must not be {@literal null}. * @param converter must not be {@literal null}. @@ -93,14 +101,19 @@ public class GridFsTemplate extends GridFsOperationsSupport implements GridFsOpe super(converter); + Assert.notNull(gridFSBucket, "GridFSBucket supplier must not be null"); + this.bucketSupplier = gridFSBucket; } + @Override public ObjectId store(InputStream content, @Nullable String filename, @Nullable String contentType, @Nullable Object metadata) { return store(content, filename, contentType, toDocument(metadata)); } + @Override + @SuppressWarnings("unchecked") public T store(GridFsObject upload) { GridFSUploadOptions uploadOptions = computeUploadOptionsFor(upload.getOptions().getContentType(), @@ -119,6 +132,7 @@ public class GridFsTemplate extends GridFsOperationsSupport implements GridFsOpe return upload.getFileId(); } + @Override public GridFSFindIterable find(Query query) { Assert.notNull(query, "Query must not be null"); @@ -139,10 +153,12 @@ public class GridFsTemplate extends GridFsOperationsSupport implements GridFsOpe return iterable; } + @Override public GridFSFile findOne(Query query) { return find(query).first(); } + @Override public void delete(Query query) { for (GridFSFile gridFSFile : find(query)) { @@ -150,10 +166,12 @@ public class GridFsTemplate extends GridFsOperationsSupport implements GridFsOpe } } + @Override public ClassLoader getClassLoader() { - return this.getClassLoader(); + return null; } + @Override public GridFsResource getResource(String location) { return Optional.ofNullable(findOne(query(whereFilename().is(location)))) // @@ -161,6 +179,7 @@ public class GridFsTemplate extends GridFsOperationsSupport implements GridFsOpe .orElseGet(() -> GridFsResource.absent(location)); } + @Override public GridFsResource getResource(GridFSFile file) { Assert.notNull(file, "GridFSFile must not be null"); @@ -168,6 +187,7 @@ public class GridFsTemplate extends GridFsOperationsSupport implements GridFsOpe return new GridFsResource(file, getGridFs().openDownloadStream(file.getId())); } + @Override public GridFsResource[] getResources(String locationPattern) { if (!StringUtils.hasText(locationPattern)) { @@ -191,12 +211,14 @@ public class GridFsTemplate extends GridFsOperationsSupport implements GridFsOpe return new GridFsResource[] { getResource(locationPattern) }; } - GridFSBucket getGridFs() { + private GridFSBucket getGridFs() { return this.bucketSupplier.get(); } private static GridFSBucket getGridFs(MongoDatabaseFactory dbFactory, @Nullable String bucket) { + Assert.notNull(dbFactory, "MongoDatabaseFactory must not be null"); + MongoDatabase db = dbFactory.getMongoDatabase(); return bucket == null ? GridFSBuckets.create(db) : GridFSBuckets.create(db, bucket); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/gridfs/ReactiveGridFsTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/gridfs/ReactiveGridFsTemplate.java index 0c385d1b6..b0beb8ac1 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/gridfs/ReactiveGridFsTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/gridfs/ReactiveGridFsTemplate.java @@ -62,11 +62,16 @@ import com.mongodb.reactivestreams.client.gridfs.GridFSUploadPublisher; public class ReactiveGridFsTemplate extends GridFsOperationsSupport implements ReactiveGridFsOperations { private final DataBufferFactory dataBufferFactory; - private Mono bucketSupplier; + private final Mono bucketSupplier; /** * Creates a new {@link ReactiveGridFsTemplate} using the given {@link ReactiveMongoDatabaseFactory} and * {@link MongoConverter}. + *

+ * Note that the {@link GridFSBucket} is obtained only once from + * {@link ReactiveMongoDatabaseFactory#getMongoDatabase() MongoDatabase}. Use + * {@link #ReactiveGridFsTemplate(MongoConverter, Mono, DataBufferFactory)} if you want to use different buckets from + * the same Template instance. * * @param dbFactory must not be {@literal null}. * @param converter must not be {@literal null}. @@ -78,10 +83,15 @@ public class ReactiveGridFsTemplate extends GridFsOperationsSupport implements R /** * Creates a new {@link ReactiveGridFsTemplate} using the given {@link ReactiveMongoDatabaseFactory} and * {@link MongoConverter}. + *

+ * Note that the {@link GridFSBucket} is obtained only once from + * {@link ReactiveMongoDatabaseFactory#getMongoDatabase() MongoDatabase}. Use + * {@link #ReactiveGridFsTemplate(MongoConverter, Mono, DataBufferFactory)} if you want to use different buckets from + * the same Template instance. * * @param dbFactory must not be {@literal null}. * @param converter must not be {@literal null}. - * @param bucket + * @param bucket can be {@literal null}. */ public ReactiveGridFsTemplate(ReactiveMongoDatabaseFactory dbFactory, MongoConverter converter, @Nullable String bucket) { @@ -91,11 +101,16 @@ public class ReactiveGridFsTemplate extends GridFsOperationsSupport implements R /** * Creates a new {@link ReactiveGridFsTemplate} using the given {@link DataBufferFactory}, * {@link ReactiveMongoDatabaseFactory} and {@link MongoConverter}. + *

+ * Note that the {@link GridFSBucket} is obtained only once from + * {@link ReactiveMongoDatabaseFactory#getMongoDatabase() MongoDatabase}. Use + * {@link #ReactiveGridFsTemplate(MongoConverter, Mono, DataBufferFactory)} if you want to use different buckets from + * the same Template instance. * * @param dataBufferFactory must not be {@literal null}. * @param dbFactory must not be {@literal null}. * @param converter must not be {@literal null}. - * @param bucket + * @param bucket can be {@literal null}. */ public ReactiveGridFsTemplate(DataBufferFactory dataBufferFactory, ReactiveMongoDatabaseFactory dbFactory, MongoConverter converter, @Nullable String bucket) { @@ -105,7 +120,7 @@ public class ReactiveGridFsTemplate extends GridFsOperationsSupport implements R /** * Creates a new {@link ReactiveGridFsTemplate} using the given {@link MongoConverter}, {@link Mono} emitting a * {@link ReactiveMongoDatabaseFactory} and {@link DataBufferFactory}. - * + * * @param converter must not be {@literal null}. * @param gridFSBucket must not be {@literal null}. * @param dataBufferFactory must not be {@literal null}. @@ -116,6 +131,7 @@ public class ReactiveGridFsTemplate extends GridFsOperationsSupport implements R super(converter); + Assert.notNull(gridFSBucket, "GridFSBucket Mono must not be null"); Assert.notNull(dataBufferFactory, "DataBufferFactory must not be null"); this.bucketSupplier = gridFSBucket; @@ -128,6 +144,8 @@ public class ReactiveGridFsTemplate extends GridFsOperationsSupport implements R return store(content, filename, contentType, toDocument(metadata)); } + @Override + @SuppressWarnings("unchecked") public Mono store(GridFsObject> upload) { GridFSUploadOptions uploadOptions = computeUploadOptionsFor(upload.getOptions().getContentType(), @@ -258,15 +276,18 @@ public class ReactiveGridFsTemplate extends GridFsOperationsSupport implements R return doGetBucket().flatMapMany(callback::doInBucket); } - static Mono doGetBucket(ReactiveMongoDatabaseFactory dbFactory, @Nullable String bucket) { - return dbFactory.getMongoDatabase() - .map(db -> bucket == null ? GridFSBuckets.create(db) : GridFSBuckets.create(db, bucket)); - } - protected Mono doGetBucket() { return bucketSupplier; } + private static Mono doGetBucket(ReactiveMongoDatabaseFactory dbFactory, @Nullable String bucket) { + + Assert.notNull(dbFactory, "ReactiveMongoDatabaseFactory must not be null"); + + return dbFactory.getMongoDatabase() + .map(db -> bucket == null ? GridFSBuckets.create(db) : GridFSBuckets.create(db, bucket)); + } + /** * @param * @author Mathieu Ouellet @@ -289,6 +310,7 @@ public class ReactiveGridFsTemplate extends GridFsOperationsSupport implements R this.sortObject = sortObject; } + @Override public GridFSFindPublisher doInBucket(GridFSBucket bucket) { GridFSFindPublisher findPublisher = bucket.find(queryObject).sort(sortObject); @@ -326,21 +348,8 @@ public class ReactiveGridFsTemplate extends GridFsOperationsSupport implements R } } - private static class UploadCallback implements ReactiveBucketCallback { - - private final BsonValue fileId; - private final String filename; - private final Publisher source; - private final GridFSUploadOptions uploadOptions; - - public UploadCallback(BsonValue fileId, String filename, Publisher source, - GridFSUploadOptions uploadOptions) { - - this.fileId = fileId; - this.filename = filename; - this.source = source; - this.uploadOptions = uploadOptions; - } + private record UploadCallback(BsonValue fileId, String filename, Publisher source, + GridFSUploadOptions uploadOptions) implements ReactiveBucketCallback { @Override public GridFSUploadPublisher doInBucket(GridFSBucket bucket) { @@ -348,19 +357,8 @@ public class ReactiveGridFsTemplate extends GridFsOperationsSupport implements R } } - private static class AutoIdCreatingUploadCallback implements ReactiveBucketCallback { - - private final String filename; - private final Publisher source; - private final GridFSUploadOptions uploadOptions; - - public AutoIdCreatingUploadCallback(String filename, Publisher source, - GridFSUploadOptions uploadOptions) { - - this.filename = filename; - this.source = source; - this.uploadOptions = uploadOptions; - } + private record AutoIdCreatingUploadCallback(String filename, Publisher source, + GridFSUploadOptions uploadOptions) implements ReactiveBucketCallback { @Override public GridFSUploadPublisher doInBucket(GridFSBucket bucket) { @@ -368,13 +366,7 @@ public class ReactiveGridFsTemplate extends GridFsOperationsSupport implements R } } - private static class DeleteCallback implements ReactiveBucketCallback { - - private final BsonValue id; - - public DeleteCallback(BsonValue id) { - this.id = id; - } + private record DeleteCallback(BsonValue id) implements ReactiveBucketCallback { @Override public Publisher doInBucket(GridFSBucket bucket) { diff --git a/src/main/asciidoc/reference/gridfs.adoc b/src/main/asciidoc/reference/gridfs.adoc index 6f55877cc..0362b9b49 100644 --- a/src/main/asciidoc/reference/gridfs.adoc +++ b/src/main/asciidoc/reference/gridfs.adoc @@ -3,7 +3,6 @@ MongoDB supports storing binary files inside its filesystem, GridFS. Spring Data MongoDB provides a `GridFsOperations` interface as well as the corresponding implementation, `GridFsTemplate`, to let you interact with the filesystem. You can set up a `GridFsTemplate` instance by handing it a `MongoDatabaseFactory` as well as a `MongoConverter`, as the following example shows: - ==== .Java [source,java,role="primary"] @@ -82,7 +81,7 @@ class GridFsClient { @Test public void findFilesInGridFs() { - GridFSFindIterable result = operations.find(query(whereFilename().is("filename.txt"))) + GridFSFindIterable result = operations.find(query(whereFilename().is("filename.txt"))); } } ---- @@ -110,3 +109,7 @@ class GridFsClient { ==== `GridFsOperations` extends `ResourcePatternResolver` and lets the `GridFsTemplate` (for example) to be plugged into an `ApplicationContext` to read Spring Config files from MongoDB database. + +NOTE: By default, `GridFsTemplate` obtains `GridFSBucket` once upon the first GridFS interaction. +After that, the Template instance reuses the cached bucket. +To use different buckets, from the same Template instance use the constructor accepting `Supplier`.