From 272a06247396b70fc36b91b0e3b387d924177b7b Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 14 Apr 2025 09:40:45 +0200 Subject: [PATCH] Update Javadoc. Original Pull Request: #4885 --- .../data/mongodb/core/CollectionOptions.java | 5 +- .../IdentifiableJsonSchemaProperty.java | 4 +- .../core/schema/QueryCharacteristic.java | 6 + .../core/schema/QueryCharacteristics.java | 144 +++++++++++++++--- .../util/MongoCompatibilityAdapter.java | 2 +- 5 files changed, 137 insertions(+), 24 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/CollectionOptions.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/CollectionOptions.java index 1def3e845..5df30e0b9 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/CollectionOptions.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/CollectionOptions.java @@ -24,12 +24,12 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.function.Function; +import java.util.stream.StreamSupport; import org.bson.BsonBinary; import org.bson.BsonBinarySubType; import org.bson.BsonNull; import org.bson.Document; - import org.springframework.data.mongodb.core.mapping.Field; import org.springframework.data.mongodb.core.query.Collation; import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty; @@ -778,7 +778,8 @@ public class CollectionOptions { } } - field.append("queries", property.getCharacteristics().map(QueryCharacteristic::toDocument).toList()); + field.append("queries", StreamSupport.stream(property.getCharacteristics().spliterator(), false) + .map(QueryCharacteristic::toDocument).toList()); if (!field.containsKey("keyId")) { field.append("keyId", BsonNull.VALUE); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/IdentifiableJsonSchemaProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/IdentifiableJsonSchemaProperty.java index c95bd4c73..26dbd7dff 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/IdentifiableJsonSchemaProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/IdentifiableJsonSchemaProperty.java @@ -1205,8 +1205,8 @@ public class IdentifiableJsonSchemaProperty implemen } /** - * {@link JsonSchemaProperty} implementation typically wrapping {@link EncryptedJsonSchemaProperty encrypted - * properties} to mark them as queryable. + * {@link JsonSchemaProperty} implementation typically wrapping an {@link EncryptedJsonSchemaProperty encrypted + * property} to mark it as queryable. * * @author Christoph Strobl * @since 4.5 diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/QueryCharacteristic.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/QueryCharacteristic.java index 2b405c56c..8604ba9d6 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/QueryCharacteristic.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/QueryCharacteristic.java @@ -18,6 +18,9 @@ package org.springframework.data.mongodb.core.schema; import org.bson.Document; /** + * Defines the specific character of a query that can be executed. Mainly used to define the characteristic of queryable + * encrypted fields. + * * @author Christoph Strobl * @since 4.5 */ @@ -28,6 +31,9 @@ public interface QueryCharacteristic { */ String queryType(); + /** + * @return the raw {@link Document} representation of the instance. + */ default Document toDocument() { return new Document("queryType", queryType()); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/QueryCharacteristics.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/QueryCharacteristics.java index 8d9ea80fe..4ec775c5e 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/QueryCharacteristics.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/schema/QueryCharacteristics.java @@ -22,18 +22,22 @@ import java.util.List; import org.bson.BsonNull; import org.bson.Document; - import org.springframework.data.domain.Range; import org.springframework.data.domain.Range.Bound; -import org.springframework.data.util.Streamable; import org.springframework.lang.Nullable; /** + * Encapsulation of individual {@link QueryCharacteristic query characteristics} used to define queries that can be + * executed when using queryable encryption. + * * @author Christoph Strobl * @since 4.5 */ -public class QueryCharacteristics implements Streamable { +public class QueryCharacteristics implements Iterable { + /** + * instance indicating none + */ private static final QueryCharacteristics NONE = new QueryCharacteristics(Collections.emptyList()); private final List characteristics; @@ -42,18 +46,36 @@ public class QueryCharacteristics implements Streamable { this.characteristics = characteristics; } + /** + * @return marker instance indicating no characteristics have been defined. + */ public static QueryCharacteristics none() { return NONE; } + /** + * Create new {@link QueryCharacteristics} from given list of {@link QueryCharacteristic characteristics}. + * + * @param characteristics must not be {@literal null}. + * @return new instance of {@link QueryCharacteristics}. + */ public static QueryCharacteristics of(List characteristics) { return new QueryCharacteristics(List.copyOf(characteristics)); } + /** + * Create new {@link QueryCharacteristics} from given {@link QueryCharacteristic characteristics}. + * + * @param characteristics must not be {@literal null}. + * @return new instance of {@link QueryCharacteristics}. + */ public static QueryCharacteristics of(QueryCharacteristic... characteristics) { return new QueryCharacteristics(Arrays.asList(characteristics)); } + /** + * @return the list of {@link QueryCharacteristic characteristics}. + */ public List getCharacteristics() { return characteristics; } @@ -63,22 +85,50 @@ public class QueryCharacteristics implements Streamable { return this.characteristics.iterator(); } + /** + * Create a new {@link RangeQuery range query characteristic} used to define range queries against an encrypted field. + * + * @param targeted field type + * @return new instance of {@link RangeQuery}. + */ public static RangeQuery range() { return new RangeQuery<>(); } + /** + * Create a new {@link EqualityQuery equality query characteristic} used to define equality queries against an + * encrypted field. + * + * @param targeted field type + * @return new instance of {@link EqualityQuery}. + */ public static EqualityQuery equality() { return new EqualityQuery<>(null); } + /** + * {@link QueryCharacteristic} for equality comparison. + * + * @param + * @since 4.5 + */ public static class EqualityQuery implements QueryCharacteristic { private final @Nullable Long contention; + /** + * Create new instance of {@link EqualityQuery}. + * + * @param contention can be {@literal null}. + */ public EqualityQuery(@Nullable Long contention) { this.contention = contention; } + /** + * @param contention concurrent counter partition factor. + * @return new instance of {@link EqualityQuery}. + */ public EqualityQuery contention(long contention) { return new EqualityQuery<>(contention); } @@ -94,64 +144,120 @@ public class QueryCharacteristics implements Streamable { } } + /** + * {@link QueryCharacteristic} for range comparison. + * + * @param + * @since 4.5 + */ public static class RangeQuery implements QueryCharacteristic { private final @Nullable Range valueRange; private final @Nullable Integer trimFactor; private final @Nullable Long sparsity; + private final @Nullable Long precision; private final @Nullable Long contention; private RangeQuery() { - this(Range.unbounded(), null, null, null); + this(Range.unbounded(), null, null, null, null); } + /** + * Create new instance of {@link RangeQuery}. + * + * @param valueRange + * @param trimFactor + * @param sparsity + * @param contention + */ public RangeQuery(@Nullable Range valueRange, @Nullable Integer trimFactor, @Nullable Long sparsity, - @Nullable Long contention) { + @Nullable Long precision, @Nullable Long contention) { this.valueRange = valueRange; this.trimFactor = trimFactor; this.sparsity = sparsity; + this.precision = precision; this.contention = contention; } - @Override - public String queryType() { - return "range"; - } - + /** + * @param lower the lower value range boundary for the queryable field. + * @return new instance of {@link RangeQuery}. + */ public RangeQuery min(T lower) { Range range = Range.of(Bound.inclusive(lower), valueRange != null ? valueRange.getUpperBound() : Bound.unbounded()); - return new RangeQuery<>(range, trimFactor, sparsity, contention); + return new RangeQuery<>(range, trimFactor, sparsity, precision, contention); } + /** + * @param upper the upper value range boundary for the queryable field. + * @return new instance of {@link RangeQuery}. + */ public RangeQuery max(T upper) { Range range = Range.of(valueRange != null ? valueRange.getLowerBound() : Bound.unbounded(), Bound.inclusive(upper)); - return new RangeQuery<>(range, trimFactor, sparsity, contention); + return new RangeQuery<>(range, trimFactor, sparsity, precision, contention); } + /** + * @param trimFactor value to control the throughput of concurrent inserts and updates. + * @return new instance of {@link RangeQuery}. + */ public RangeQuery trimFactor(int trimFactor) { - return new RangeQuery<>(valueRange, trimFactor, sparsity, contention); + return new RangeQuery<>(valueRange, trimFactor, sparsity, precision, contention); } + /** + * @param sparsity value to control the value density within the index. + * @return new instance of {@link RangeQuery}. + */ public RangeQuery sparsity(long sparsity) { - return new RangeQuery<>(valueRange, trimFactor, sparsity, contention); + return new RangeQuery<>(valueRange, trimFactor, sparsity, precision, contention); } + /** + * @param contention concurrent counter partition factor. + * @return new instance of {@link RangeQuery}. + */ public RangeQuery contention(long contention) { - return new RangeQuery<>(valueRange, trimFactor, sparsity, contention); + return new RangeQuery<>(valueRange, trimFactor, sparsity, precision, contention); + } + + /** + * @param precision digits considered comparing floating point numbers. + * @return new instance of {@link RangeQuery}. + */ + public RangeQuery precision(long precision) { + return new RangeQuery<>(valueRange, trimFactor, sparsity, precision, contention); + } + + @Override + public String queryType() { + return "range"; } @Override @SuppressWarnings("unchecked") public Document toDocument() { - return QueryCharacteristic.super.toDocument().append("contention", contention).append("trimFactor", trimFactor) - .append("sparsity", sparsity).append("min", valueRange.getLowerBound().getValue().orElse((T) BsonNull.VALUE)) - .append("max", valueRange.getUpperBound().getValue().orElse((T) BsonNull.VALUE)); + Document target = QueryCharacteristic.super.toDocument(); + if (contention != null) { + target.append("contention", contention); + } + if (trimFactor != null) { + target.append("trimFactor", trimFactor); + } + if (valueRange != null) { + target.append("min", valueRange.getLowerBound().getValue().orElse((T) BsonNull.VALUE)).append("max", + valueRange.getUpperBound().getValue().orElse((T) BsonNull.VALUE)); + } + if (sparsity != null) { + target.append("sparsity", sparsity); + } + + return target; } } - } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/MongoCompatibilityAdapter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/MongoCompatibilityAdapter.java index a61fe0eca..8bd422c49 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/MongoCompatibilityAdapter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/MongoCompatibilityAdapter.java @@ -61,7 +61,7 @@ public class MongoCompatibilityAdapter { static { - // method name changed in between + // method name changed in between Method trimFactor = ReflectionUtils.findMethod(RangeOptions.class, "setTrimFactor", Integer.class); if (trimFactor != null) { setTrimFactor = trimFactor;