Skip to content

Commit

Permalink
Polishing.
Browse files Browse the repository at this point in the history
Add assertions and missing Override annotations. Avoid recursive self-call on getClassLoader. Extend documentation.

See #1627
Original pull request: #4389
  • Loading branch information
mp911de committed May 26, 2023
1 parent 4b78ef6 commit 370b414
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 49 deletions.
Expand Up @@ -58,10 +58,14 @@
*/
public class GridFsTemplate extends GridFsOperationsSupport implements GridFsOperations, ResourcePatternResolver {

private Supplier<GridFSBucket> bucketSupplier;
private final Supplier<GridFSBucket> bucketSupplier;

/**
* Creates a new {@link GridFsTemplate} using the given {@link MongoDatabaseFactory} and {@link MongoConverter}.
* <p>
* 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}.
Expand All @@ -72,6 +76,10 @@ public GridFsTemplate(MongoDatabaseFactory dbFactory, MongoConverter converter)

/**
* Creates a new {@link GridFsTemplate} using the given {@link MongoDatabaseFactory} and {@link MongoConverter}.
* <p>
* 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}.
Expand All @@ -93,14 +101,19 @@ public GridFsTemplate(MongoConverter converter, Supplier<GridFSBucket> gridFSBuc

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> T store(GridFsObject<T, InputStream> upload) {

GridFSUploadOptions uploadOptions = computeUploadOptionsFor(upload.getOptions().getContentType(),
Expand All @@ -119,6 +132,7 @@ public <T> T store(GridFsObject<T, InputStream> upload) {
return upload.getFileId();
}

@Override
public GridFSFindIterable find(Query query) {

Assert.notNull(query, "Query must not be null");
Expand All @@ -139,35 +153,41 @@ public GridFSFindIterable find(Query query) {
return iterable;
}

@Override
public GridFSFile findOne(Query query) {
return find(query).first();
}

@Override
public void delete(Query query) {

for (GridFSFile gridFSFile : find(query)) {
getGridFs().delete(gridFSFile.getId());
}
}

@Override
public ClassLoader getClassLoader() {
return this.getClassLoader();
return null;
}

@Override
public GridFsResource getResource(String location) {

return Optional.ofNullable(findOne(query(whereFilename().is(location)))) //
.map(this::getResource) //
.orElseGet(() -> GridFsResource.absent(location));
}

@Override
public GridFsResource getResource(GridFSFile file) {

Assert.notNull(file, "GridFSFile must not be null");

return new GridFsResource(file, getGridFs().openDownloadStream(file.getId()));
}

@Override
public GridFsResource[] getResources(String locationPattern) {

if (!StringUtils.hasText(locationPattern)) {
Expand All @@ -191,12 +211,14 @@ public GridFsResource[] getResources(String locationPattern) {
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);
}
Expand Down
Expand Up @@ -62,11 +62,16 @@
public class ReactiveGridFsTemplate extends GridFsOperationsSupport implements ReactiveGridFsOperations {

private final DataBufferFactory dataBufferFactory;
private Mono<GridFSBucket> bucketSupplier;
private final Mono<GridFSBucket> bucketSupplier;

/**
* Creates a new {@link ReactiveGridFsTemplate} using the given {@link ReactiveMongoDatabaseFactory} and
* {@link MongoConverter}.
* <p>
* 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}.
Expand All @@ -78,10 +83,15 @@ public ReactiveGridFsTemplate(ReactiveMongoDatabaseFactory dbFactory, MongoConve
/**
* Creates a new {@link ReactiveGridFsTemplate} using the given {@link ReactiveMongoDatabaseFactory} and
* {@link MongoConverter}.
* <p>
* 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) {
Expand All @@ -91,11 +101,16 @@ public ReactiveGridFsTemplate(ReactiveMongoDatabaseFactory dbFactory, MongoConve
/**
* Creates a new {@link ReactiveGridFsTemplate} using the given {@link DataBufferFactory},
* {@link ReactiveMongoDatabaseFactory} and {@link MongoConverter}.
* <p>
* 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) {
Expand All @@ -105,7 +120,7 @@ public ReactiveGridFsTemplate(DataBufferFactory dataBufferFactory, ReactiveMongo
/**
* 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}.
Expand All @@ -116,6 +131,7 @@ public ReactiveGridFsTemplate(MongoConverter converter, Mono<GridFSBucket> gridF

super(converter);

Assert.notNull(gridFSBucket, "GridFSBucket Mono must not be null");
Assert.notNull(dataBufferFactory, "DataBufferFactory must not be null");

this.bucketSupplier = gridFSBucket;
Expand All @@ -128,6 +144,8 @@ public Mono<ObjectId> store(Publisher<DataBuffer> content, @Nullable String file
return store(content, filename, contentType, toDocument(metadata));
}

@Override
@SuppressWarnings("unchecked")
public <T> Mono<T> store(GridFsObject<T, Publisher<DataBuffer>> upload) {

GridFSUploadOptions uploadOptions = computeUploadOptionsFor(upload.getOptions().getContentType(),
Expand Down Expand Up @@ -258,15 +276,18 @@ public <T> Flux<T> createFlux(ReactiveBucketCallback<T> callback) {
return doGetBucket().flatMapMany(callback::doInBucket);
}

static Mono<GridFSBucket> doGetBucket(ReactiveMongoDatabaseFactory dbFactory, @Nullable String bucket) {
return dbFactory.getMongoDatabase()
.map(db -> bucket == null ? GridFSBuckets.create(db) : GridFSBuckets.create(db, bucket));
}

protected Mono<GridFSBucket> doGetBucket() {
return bucketSupplier;
}

private static Mono<GridFSBucket> 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 <T>
* @author Mathieu Ouellet
Expand All @@ -289,6 +310,7 @@ public FindCallback(Query query, Document queryObject, Document sortObject) {
this.sortObject = sortObject;
}

@Override
public GridFSFindPublisher doInBucket(GridFSBucket bucket) {

GridFSFindPublisher findPublisher = bucket.find(queryObject).sort(sortObject);
Expand Down Expand Up @@ -326,55 +348,25 @@ public GridFSFindPublisher doInBucket(GridFSBucket bucket) {
}
}

private static class UploadCallback implements ReactiveBucketCallback<Void> {

private final BsonValue fileId;
private final String filename;
private final Publisher<ByteBuffer> source;
private final GridFSUploadOptions uploadOptions;

public UploadCallback(BsonValue fileId, String filename, Publisher<ByteBuffer> source,
GridFSUploadOptions uploadOptions) {

this.fileId = fileId;
this.filename = filename;
this.source = source;
this.uploadOptions = uploadOptions;
}
private record UploadCallback(BsonValue fileId, String filename, Publisher<ByteBuffer> source,
GridFSUploadOptions uploadOptions) implements ReactiveBucketCallback<Void> {

@Override
public GridFSUploadPublisher<Void> doInBucket(GridFSBucket bucket) {
return bucket.uploadFromPublisher(fileId, filename, source, uploadOptions);
}
}

private static class AutoIdCreatingUploadCallback implements ReactiveBucketCallback<ObjectId> {

private final String filename;
private final Publisher<ByteBuffer> source;
private final GridFSUploadOptions uploadOptions;

public AutoIdCreatingUploadCallback(String filename, Publisher<ByteBuffer> source,
GridFSUploadOptions uploadOptions) {

this.filename = filename;
this.source = source;
this.uploadOptions = uploadOptions;
}
private record AutoIdCreatingUploadCallback(String filename, Publisher<ByteBuffer> source,
GridFSUploadOptions uploadOptions) implements ReactiveBucketCallback<ObjectId> {

@Override
public GridFSUploadPublisher<ObjectId> doInBucket(GridFSBucket bucket) {
return bucket.uploadFromPublisher(filename, source, uploadOptions);
}
}

private static class DeleteCallback implements ReactiveBucketCallback<Void> {

private final BsonValue id;

public DeleteCallback(BsonValue id) {
this.id = id;
}
private record DeleteCallback(BsonValue id) implements ReactiveBucketCallback<Void> {

@Override
public Publisher<Void> doInBucket(GridFSBucket bucket) {
Expand Down
7 changes: 5 additions & 2 deletions src/main/asciidoc/reference/gridfs.adoc
Expand Up @@ -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"]
Expand Down Expand Up @@ -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")));
}
}
----
Expand Down Expand Up @@ -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<GridFSBucket>`.

0 comments on commit 370b414

Please sign in to comment.