Browse Source

Polishing.

Add Javadoc and since tags. Refine value lookup. Include missing properties in Meta.hashCode and equals. Update documentation using boolean Meta.allowDiskUse. Add assertions to prevent accidental null propagation.

See: #4667
Original pull request: #5035
pull/5044/head
Mark Paluch 4 months ago
parent
commit
41fd839bfb
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
  2. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
  3. 7
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationOptions.java
  4. 18
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/DiskUse.java
  5. 35
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java
  6. 17
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java
  7. 19
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/QueryBlocks.java
  8. 2
      src/main/antora/modules/ROOT/pages/mongodb/aot.adoc
  9. 4
      src/main/antora/modules/ROOT/pages/mongodb/repositories/query-methods.adoc

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

@ -3558,7 +3558,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, @@ -3558,7 +3558,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
Meta meta = query.getMeta();
HintFunction hintFunction = HintFunction.from(query.getHint());
if (skip <= 0 && limit <= 0 && ObjectUtils.isEmpty(sortObject) && hintFunction.isEmpty() && !meta.hasValues()
if (skip <= 0 && limit <= 0 && ObjectUtils.isEmpty(sortObject) && hintFunction.isEmpty() && meta.isEmpty()
&& query.getCollation().isEmpty()) {
return cursorToUse;
}

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

@ -3419,7 +3419,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -3419,7 +3419,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
HintFunction hintFunction = HintFunction.from(query.getHint());
Meta meta = query.getMeta();
if (skip <= 0 && limit <= 0 && ObjectUtils.isEmpty(sortObject) && hintFunction.isEmpty() && !meta.hasValues()) {
if (skip <= 0 && limit <= 0 && ObjectUtils.isEmpty(sortObject) && hintFunction.isEmpty() && meta.isEmpty()) {
return findPublisherToUse;
}

7
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationOptions.java

@ -146,6 +146,8 @@ public class AggregationOptions implements ReadConcernAware, ReadPreferenceAware @@ -146,6 +146,8 @@ public class AggregationOptions implements ReadConcernAware, ReadPreferenceAware
private AggregationOptions(DiskUse diskUse, boolean explain, @Nullable Document cursor,
@Nullable Collation collation, @Nullable String comment, @Nullable Object hint) {
Assert.notNull(diskUse, "DiskUse must not be null");
this.diskUse = diskUse;
this.explain = explain;
this.cursor = Optional.ofNullable(cursor);
@ -442,7 +444,7 @@ public class AggregationOptions implements ReadConcernAware, ReadPreferenceAware @@ -442,7 +444,7 @@ public class AggregationOptions implements ReadConcernAware, ReadPreferenceAware
*/
public static class Builder {
private @Nullable DiskUse diskUse = DiskUse.DEFAULT;
private DiskUse diskUse = DiskUse.DEFAULT;
private boolean explain;
private @Nullable Document cursor;
private @Nullable Collation collation;
@ -470,10 +472,13 @@ public class AggregationOptions implements ReadConcernAware, ReadPreferenceAware @@ -470,10 +472,13 @@ public class AggregationOptions implements ReadConcernAware, ReadPreferenceAware
*
* @param diskUse use {@literal true} to allow disk use during the aggregation.
* @return this.
* @since 5.0
*/
@Contract("_ -> this")
public Builder diskUse(DiskUse diskUse) {
Assert.notNull(diskUse, "DiskUse must not be null");
this.diskUse = diskUse;
return this;
}

18
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/DiskUse.java

@ -15,31 +15,35 @@ @@ -15,31 +15,35 @@
*/
package org.springframework.data.mongodb.core.query;
import java.util.Locale;
import org.jspecify.annotations.Nullable;
import org.springframework.util.StringUtils;
/**
* Disk use indicates if the MongoDB server is allowed to write temporary files to disk during query/aggregation
* execution. MongoDB 6.0 server (and later) default for {@literal allowDiskUseByDefault} is {@literal true} on server
* side.
* execution. MongoDB 6.0 server (and later) default for {@literal allowDiskUseByDefault} is {@literal true} on the
* server side.
*
* @author Christoph Strobl
* @since 5.0
* @see com.mongodb.client.FindIterable#allowDiskUse(Boolean)
* @see com.mongodb.reactivestreams.client.FindPublisher#allowDiskUse(Boolean)
*/
public enum DiskUse {
/**
* Go with the server default value and do not specify any override.
* Use the server default value and do not specify any override.
*/
DEFAULT,
/**
* Override server default value and explicitly allow disk writes.
* Allow disk writes.
*/
ALLOW,
/**
* Override server default value and explicitly deny disk writes.
* Explicitly deny disk writes.
*/
DENY;
@ -69,10 +73,10 @@ public enum DiskUse { @@ -69,10 +73,10 @@ public enum DiskUse {
return DEFAULT;
}
return switch (value) {
return switch (value.toLowerCase(Locale.ROOT)) {
case "true" -> ALLOW;
case "false" -> DENY;
default -> valueOf(value.toUpperCase());
default -> valueOf(value.toUpperCase(Locale.ROOT));
};
}
}

35
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java

@ -247,15 +247,33 @@ public class Meta { @@ -247,15 +247,33 @@ public class Meta {
setDiskUse(DiskUse.of(allowDiskUse));
}
/**
* Sets the {@link DiskUse} to control whether temporary files are allowed to be written to disk during query.
*
* @param diskUse must not be {@literal null}.
* @since 5.0
*/
public void setDiskUse(DiskUse diskUse) {
Assert.notNull(diskUse, "DiskUse must not be null");
this.diskUse = diskUse;
}
/**
* @return
* @return {@literal true} there is at least one values, flags, cursor batch size, or disk use set; {@literal false}
* otherwise.
*/
public boolean hasValues() {
return !this.values.isEmpty() || !this.flags.isEmpty() || this.cursorBatchSize != null || !this.diskUse.equals(DiskUse.DEFAULT);
return !isEmpty();
}
/**
* @return {@literal true} if no values, flags, cursor batch size and disk use are set; {@literal false} otherwise.
*/
public boolean isEmpty() {
return this.values.isEmpty() && this.flags.isEmpty() && this.cursorBatchSize == null
&& this.diskUse.equals(DiskUse.DEFAULT);
}
/**
@ -303,6 +321,8 @@ public class Meta { @@ -303,6 +321,8 @@ public class Meta {
int hash = ObjectUtils.nullSafeHashCode(this.values);
hash += ObjectUtils.nullSafeHashCode(this.flags);
hash += ObjectUtils.nullSafeHashCode(this.cursorBatchSize);
hash += ObjectUtils.nullSafeHashCode(this.diskUse);
return hash;
}
@ -320,7 +340,16 @@ public class Meta { @@ -320,7 +340,16 @@ public class Meta {
if (!ObjectUtils.nullSafeEquals(this.values, other.values)) {
return false;
}
return ObjectUtils.nullSafeEquals(this.flags, other.flags);
if (!ObjectUtils.nullSafeEquals(this.flags, other.flags)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(this.cursorBatchSize, other.cursorBatchSize)) {
return false;
}
return ObjectUtils.nullSafeEquals(this.diskUse, other.diskUse);
}
/**

17
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java

@ -15,9 +15,8 @@ @@ -15,9 +15,8 @@
*/
package org.springframework.data.mongodb.core.query;
import static org.springframework.data.mongodb.core.query.SerializationUtils.serializeToJsonSafely;
import static org.springframework.util.ObjectUtils.nullSafeEquals;
import static org.springframework.util.ObjectUtils.nullSafeHashCode;
import static org.springframework.data.mongodb.core.query.SerializationUtils.*;
import static org.springframework.util.ObjectUtils.*;
import java.time.Duration;
import java.util.ArrayList;
@ -32,6 +31,7 @@ import java.util.Set; @@ -32,6 +31,7 @@ import java.util.Set;
import org.bson.Document;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.Limit;
import org.springframework.data.domain.OffsetScrollPosition;
@ -585,6 +585,17 @@ public class Query implements ReadConcernAware, ReadPreferenceAware { @@ -585,6 +585,17 @@ public class Query implements ReadConcernAware, ReadPreferenceAware {
return diskUse(DiskUse.of(allowDiskUse));
}
/**
* Configures writing to temporary files for aggregation stages and queries. When set to {@link DiskUse#ALLOW},
* aggregation stages can write data to the {@code _tmp} subdirectory in the {@code dbPath} directory.
* <p>
* Note that the default value for {@literal allowDiskUseByDefault} is {@literal true} on the server side since
* MongoDB 6.0.
*
* @param diskUse
* @return this.
* @since 5.0
*/
@Contract("_ -> this")
public Query diskUse(DiskUse diskUse) {

19
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/QueryBlocks.java

@ -239,14 +239,16 @@ class QueryBlocks { @@ -239,14 +239,16 @@ class QueryBlocks {
if (StringUtils.hasText(source.getQuery().getFieldsString())) {
VariableSnippet fields = Snippet.declare(builder).variable(Document.class, context.localVariable("fields"))
.of(MongoCodeBlocks.asDocument(context.getExpressionMarker(), source.getQuery().getFieldsString(), queryParameters.get()));
.of(MongoCodeBlocks.asDocument(context.getExpressionMarker(), source.getQuery().getFieldsString(),
queryParameters.get()));
builder.addStatement("$L.setFieldsObject($L)", queryVariableName, fields.getVariableName());
}
if (StringUtils.hasText(source.getQuery().getSortString())) {
VariableSnippet sort = Snippet.declare(builder).variable(Document.class, context.localVariable("sort"))
.of(MongoCodeBlocks.asDocument(context.getExpressionMarker(), source.getQuery().getSortString(), getQueryParameters()));
.of(MongoCodeBlocks.asDocument(context.getExpressionMarker(), source.getQuery().getSortString(),
getQueryParameters()));
builder.addStatement("$L.setSortObject($L)", queryVariableName, sort.getVariableName());
}
@ -312,13 +314,11 @@ class QueryBlocks { @@ -312,13 +314,11 @@ class QueryBlocks {
} else {
if (getQueryParameters().isEmpty()) {
builder.addStatement(
"$L.collation(collationOf(evaluate($L, $S)))",
queryVariableName, context.getExpressionMarker().enclosingMethod(), collationString);
builder.addStatement("$L.collation(collationOf(evaluate($L, $S)))", queryVariableName,
context.getExpressionMarker().enclosingMethod(), collationString);
} else {
builder.addStatement(
"$L.collation(collationOf(evaluate($L, $S, $L)))",
queryVariableName, context.getExpressionMarker().enclosingMethod(), collationString, getQueryParameters());
builder.addStatement("$L.collation(collationOf(evaluate($L, $S, $L)))", queryVariableName,
context.getExpressionMarker().enclosingMethod(), collationString, getQueryParameters());
}
}
}
@ -346,7 +346,8 @@ class QueryBlocks { @@ -346,7 +346,8 @@ class QueryBlocks {
if (getQueryParameters().isEmpty()) {
builder.add("createQuery($L, $S)", context.getExpressionMarker().enclosingMethod(), source);
} else {
builder.add("createQuery($L, $S, $L)", context.getExpressionMarker().enclosingMethod(), source, getQueryParameters());
builder.add("createQuery($L, $S, $L)", context.getExpressionMarker().enclosingMethod(), source,
getQueryParameters());
}
return builder.build();
} else {

2
src/main/antora/modules/ROOT/pages/mongodb/aot.adoc

@ -76,7 +76,7 @@ These are typically all query methods that are not backed by an xref:repositorie @@ -76,7 +76,7 @@ These are typically all query methods that are not backed by an xref:repositorie
**Limitations**
* `@Meta.allowDiskUse` and `flags` are not evaluated.
* `@Meta.flags` is not evaluated.
* Limited `Collation` detection.
* No support for in-clauses with pattern matching / case insensitivity

4
src/main/antora/modules/ROOT/pages/mongodb/repositories/query-methods.adoc

@ -672,7 +672,7 @@ Use the `@Meta` annotation to set those options via `maxExecutionTimeMs`, `comme @@ -672,7 +672,7 @@ Use the `@Meta` annotation to set those options via `maxExecutionTimeMs`, `comme
----
interface PersonRepository extends CrudRepository<Person, String> {
@Meta(allowDiskUse = true)
@Meta(allowDiskUse = "true")
@Aggregation("{ $group: { _id : $lastname, names : { $addToSet : $firstname } } }")
List<PersonAggregate> groupByLastnameAndFirstnames();
}
@ -684,7 +684,7 @@ Or use `@Meta` to create your own annotation as shown in the sample below. @@ -684,7 +684,7 @@ Or use `@Meta` to create your own annotation as shown in the sample below.
----
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
@Meta(allowDiskUse = true)
@Meta(allowDiskUse = "true")
@interface AllowDiskUse { }
interface PersonRepository extends CrudRepository<Person, String> {

Loading…
Cancel
Save