From d0f3668fb0c6f52057b164442bc7975fd39b577c Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 9 Apr 2025 14:38:40 +0200 Subject: [PATCH] Initial polishing. --- .../data/mongodb/core/CollectionOptions.java | 52 ++++++++++--------- .../data/mongodb/core/EntityOperations.java | 17 +++--- .../core/MappingMongoJsonSchemaCreator.java | 45 ++++++++-------- .../core/convert/MongoConversionContext.java | 39 ++++---------- .../mongodb/core/convert/QueryMapper.java | 3 +- .../encryption/MongoEncryptionConverter.java | 27 +++++----- .../mongodb/core/encryption/Encryption.java | 8 +-- .../data/mongodb/core/mapping/Queryable.java | 5 +- .../mongodb/core/mapping/RangeEncrypted.java | 11 ++-- .../core/schema/QueryCharacteristics.java | 20 +++++-- .../core/encryption/RangeEncryptionTests.java | 10 ++-- .../core/schema/MongoJsonSchemaUnitTests.java | 37 ++++++++----- 12 files changed, 145 insertions(+), 129 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 28215dc64..1def3e845 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.Collectors; 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; @@ -43,7 +43,6 @@ import org.springframework.data.mongodb.core.validation.Validator; import org.springframework.data.util.Optionals; import org.springframework.lang.CheckReturnValue; import org.springframework.lang.Contract; -import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -241,11 +240,11 @@ public class CollectionOptions { * Create new {@link CollectionOptions} with already given settings and {@code validationOptions} set to given * {@link MongoJsonSchema}. * - * @param schema can be {@literal null}. + * @param schema must not be {@literal null}. * @return new {@link CollectionOptions}. * @since 2.1 */ - public CollectionOptions schema(@Nullable MongoJsonSchema schema) { + public CollectionOptions schema(MongoJsonSchema schema) { return validator(Validator.schema(schema)); } @@ -473,7 +472,7 @@ public class CollectionOptions { * Get the {@code encryptedFields} if available. * * @return {@link Optional#empty()} if not specified. - * @since 4.5.0 + * @since 4.5 */ public Optional getEncryptedFieldsOptions() { return Optional.ofNullable(encryptedFieldsOptions); @@ -552,7 +551,8 @@ public class CollectionOptions { private final @Nullable ValidationLevel validationLevel; private final @Nullable ValidationAction validationAction; - public ValidationOptions(Validator validator, ValidationLevel validationLevel, ValidationAction validationAction) { + public ValidationOptions(@Nullable Validator validator, @Nullable ValidationLevel validationLevel, + @Nullable ValidationAction validationAction) { this.validator = validator; this.validationLevel = validationLevel; @@ -669,7 +669,7 @@ public class CollectionOptions { /** * Encapsulation of Encryption options for collections. - * + * * @author Christoph Strobl * @since 4.5 */ @@ -677,8 +677,19 @@ public class CollectionOptions { private static final EncryptedFieldsOptions NONE = new EncryptedFieldsOptions(); - private @Nullable MongoJsonSchema schema; - private List queryableProperties; + private final @Nullable MongoJsonSchema schema; + private final List queryableProperties; + + EncryptedFieldsOptions() { + this(null, List.of()); + } + + private EncryptedFieldsOptions(@Nullable MongoJsonSchema schema, + List queryableProperties) { + + this.schema = schema; + this.queryableProperties = queryableProperties; + } /** * @return {@link EncryptedFieldsOptions#NONE} @@ -701,17 +712,6 @@ public class CollectionOptions { return new EncryptedFieldsOptions(null, List.copyOf(properties)); } - EncryptedFieldsOptions() { - this(null, List.of()); - } - - private EncryptedFieldsOptions(@Nullable MongoJsonSchema schema, - List queryableProperties) { - - this.schema = schema; - this.queryableProperties = queryableProperties; - } - /** * Add a new {@link QueryableJsonSchemaProperty queryable property} for the given source property. *

@@ -739,7 +739,6 @@ public class CollectionOptions { return new Document("fields", selectPaths()); } - @NonNull private List selectPaths() { Map fields = new LinkedHashMap<>(); @@ -760,10 +759,13 @@ public class CollectionOptions { List converted = new ArrayList<>(queryableProperties.size()); for (QueryableJsonSchemaProperty property : queryableProperties) { + Document field = new Document("path", property.getIdentifier()); + if (!property.getTypes().isEmpty()) { field.append("bsonType", property.getTypes().iterator().next().toBsonType().value()); } + if (property .getTargetProperty() instanceof IdentifiableJsonSchemaProperty.EncryptedJsonSchemaProperty encrypted) { if (encrypted.getKeyId() != null) { @@ -775,11 +777,13 @@ public class CollectionOptions { } } } - field.append("queries", property.getCharacteristics().getCharacteristics().stream() - .map(QueryCharacteristic::toDocument).collect(Collectors.toList())); + + field.append("queries", property.getCharacteristics().map(QueryCharacteristic::toDocument).toList()); + if (!field.containsKey("keyId")) { field.append("keyId", BsonNull.VALUE); } + converted.add(field); } return converted; @@ -813,7 +817,7 @@ public class CollectionOptions { } } - private static void collectPaths(Document document, String currentPath, Map paths) { + private static void collectPaths(Document document, @Nullable String currentPath, Map paths) { if (document.containsKey("type") && document.get("type").equals("object")) { Object o = document.get("properties"); 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 24977c5af..38269787c 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 @@ -22,6 +22,7 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; import org.bson.BsonNull; import org.bson.Document; @@ -377,14 +378,16 @@ class EntityOperations { result.timeSeriesOptions(options); }); - collectionOptions.getChangeStreamOptions().ifPresent(it -> result - .changeStreamPreAndPostImagesOptions(new ChangeStreamPreAndPostImagesOptions(it.getPreAndPostImages()))); + collectionOptions.getChangeStreamOptions() // + .map(CollectionOptions.CollectionChangeStreamOptions::getPreAndPostImages) // + .map(ChangeStreamPreAndPostImagesOptions::new) // + .ifPresent(result::changeStreamPreAndPostImagesOptions); + + collectionOptions.getEncryptedFieldsOptions() // + .map(EncryptedFieldsOptions::toDocument) // + .filter(Predicate.not(Document::isEmpty)) // + .ifPresent(result::encryptedFields); - collectionOptions.getEncryptedFieldsOptions().map(EncryptedFieldsOptions::toDocument).ifPresent(encryptedFields -> { - if (!encryptedFields.isEmpty()) { - result.encryptedFields(encryptedFields); - } - }); return result; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MappingMongoJsonSchemaCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MappingMongoJsonSchemaCreator.java index 790fa9429..bc26dfb68 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MappingMongoJsonSchemaCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MappingMongoJsonSchemaCreator.java @@ -24,6 +24,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import org.bson.Document; + import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mongodb.core.convert.MongoConverter; @@ -32,7 +33,6 @@ import org.springframework.data.mongodb.core.mapping.Field; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.mongodb.core.mapping.Queryable; -import org.springframework.data.mongodb.core.mapping.RangeEncrypted; import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.ArrayJsonSchemaProperty; import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.EncryptedJsonSchemaProperty; import org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.ObjectJsonSchemaProperty; @@ -126,29 +126,31 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator { MongoPersistentEntity entity = mappingContext.getRequiredPersistentEntity(type); MongoJsonSchemaBuilder schemaBuilder = MongoJsonSchema.builder(); - { - Encrypted encrypted = entity.findAnnotation(Encrypted.class); - if (encrypted != null) { + Encrypted encrypted = entity.findAnnotation(Encrypted.class); + if (encrypted != null) { + schemaBuilder.encryptionMetadata(getEncryptionMetadata(entity, encrypted)); + } - Document encryptionMetadata = new Document(); + List schemaProperties = computePropertiesForEntity(Collections.emptyList(), entity); + schemaBuilder.properties(schemaProperties.toArray(new JsonSchemaProperty[0])); - Collection encryptionKeyIds = entity.getEncryptionKeyIds(); - if (!CollectionUtils.isEmpty(encryptionKeyIds)) { - encryptionMetadata.append("keyId", encryptionKeyIds); - } + return schemaBuilder.build(); + } - if (StringUtils.hasText(encrypted.algorithm())) { - encryptionMetadata.append("algorithm", encrypted.algorithm()); - } + private static Document getEncryptionMetadata(MongoPersistentEntity entity, Encrypted encrypted) { - schemaBuilder.encryptionMetadata(encryptionMetadata); - } + Document encryptionMetadata = new Document(); + + Collection encryptionKeyIds = entity.getEncryptionKeyIds(); + if (!CollectionUtils.isEmpty(encryptionKeyIds)) { + encryptionMetadata.append("keyId", encryptionKeyIds); } - List schemaProperties = computePropertiesForEntity(Collections.emptyList(), entity); - schemaBuilder.properties(schemaProperties.toArray(new JsonSchemaProperty[0])); + if (StringUtils.hasText(encrypted.algorithm())) { + encryptionMetadata.append("algorithm", encrypted.algorithm()); + } - return schemaBuilder.build(); + return encryptionMetadata; } private List computePropertiesForEntity(List path, @@ -190,8 +192,8 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator { Class rawTargetType = computeTargetType(property); // target type before conversion Class targetType = converter.getTypeMapper().getWriteTargetTypeFor(rawTargetType); // conversion target type - - if ((rawTargetType.isPrimitive() || ClassUtils.isPrimitiveArray(rawTargetType)) && targetType == Object.class || ClassUtils.isAssignable(targetType, rawTargetType) ) { + if ((rawTargetType.isPrimitive() || ClassUtils.isPrimitiveArray(rawTargetType)) && targetType == Object.class + || ClassUtils.isAssignable(targetType, rawTargetType)) { targetType = rawTargetType; } @@ -317,14 +319,15 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator { if (queryable.contentionFactor() >= 0) { options.put("contention", queryable.contentionFactor()); } - if (!queryable.queryAttributes().isEmpty()) { + + if (StringUtils.hasText(queryable.queryAttributes())) { options.putAll(Document.parse(queryable.queryAttributes())); } return options; } }; - return new QueryableJsonSchemaProperty(enc, QueryCharacteristics.of(List.of(characteristic))); + return new QueryableJsonSchemaProperty(enc, QueryCharacteristics.of(characteristic)); } private JsonSchemaProperty createObjectSchemaPropertyForEntity(List path, diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConversionContext.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConversionContext.java index 9d672ea92..da106715d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConversionContext.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConversionContext.java @@ -79,7 +79,6 @@ public class MongoConversionContext implements ValueConversionContext { if (isKeyword(key)) { - return convertValueWithConversionContext(documentField, val, val, valueConverter, conversionContext.forOperator(new QueryOperatorContext(key, conversionContext.getOperatorContext().getPath()))); + return convertValueWithConversionContext(documentField, val, val, valueConverter, conversionContext + .forOperator(new QueryOperatorContext(key, conversionContext.getOperatorContext().path()))); } return val; }); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/encryption/MongoEncryptionConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/encryption/MongoEncryptionConverter.java index c69653d2d..8d29847aa 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/encryption/MongoEncryptionConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/encryption/MongoEncryptionConverter.java @@ -15,9 +15,9 @@ */ package org.springframework.data.mongodb.core.convert.encryption; -import static java.util.Arrays.asList; -import static java.util.Collections.singletonList; -import static org.springframework.data.mongodb.core.encryption.EncryptionOptions.QueryableEncryptionOptions; +import static java.util.Arrays.*; +import static java.util.Collections.*; +import static org.springframework.data.mongodb.core.encryption.EncryptionOptions.*; import java.util.Collection; import java.util.LinkedHashMap; @@ -32,6 +32,7 @@ import org.bson.BsonDocument; import org.bson.BsonValue; import org.bson.Document; import org.bson.types.Binary; + import org.springframework.core.CollectionFactory; import org.springframework.data.mongodb.core.convert.MongoConversionContext; import org.springframework.data.mongodb.core.convert.MongoConversionContext.OperatorContext; @@ -59,8 +60,8 @@ import org.springframework.util.StringUtils; public class MongoEncryptionConverter implements EncryptingConverter { private static final Log LOGGER = LogFactory.getLog(MongoEncryptionConverter.class); - private static final String EQUALITY_OPERATOR = "$eq"; private static final List RANGE_OPERATORS = asList("$gt", "$gte", "$lt", "$lte"); + public static final String AND_OPERATOR = "$and"; private final Encryption encryption; private final EncryptionKeyResolver keyResolver; @@ -189,7 +190,7 @@ public class MongoEncryptionConverter implements EncryptingConverter plaintext type. + * @param ciphertext type. * @author Christoph Strobl * @author Ross Lawley * @since 4.1 */ -public interface Encryption { +public interface Encryption { /** * Encrypt the given value. @@ -33,7 +35,7 @@ public interface Encryption { * @param options must not be {@literal null}. * @return the encrypted value. */ - T encrypt(S value, EncryptionOptions options); + C encrypt(P value, EncryptionOptions options); /** * Decrypt the given value. @@ -41,7 +43,7 @@ public interface Encryption { * @param value must not be {@literal null}. * @return the decrypted value. */ - S decrypt(T value); + P decrypt(C value); /** * Encrypt the given expression. diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Queryable.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Queryable.java index abebc11a5..a0c67f718 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Queryable.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Queryable.java @@ -1,5 +1,5 @@ /* - * Copyright 2025. the original author or authors. + * Copyright 2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,13 +30,11 @@ public @interface Queryable { /** * @return empty {@link String} if not set. - * @since 4.5 */ String queryType() default ""; /** * @return empty {@link String} if not set. - * @since 4.5 */ String queryAttributes() default ""; @@ -46,4 +44,5 @@ public @interface Queryable { * @return the contention factor */ long contentionFactor() default -1; + } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/RangeEncrypted.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/RangeEncrypted.java index 5710c081f..8b2eccb6c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/RangeEncrypted.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/RangeEncrypted.java @@ -34,7 +34,7 @@ import org.springframework.core.annotation.AliasFor; public @interface RangeEncrypted { /** - * Set the contention factor + * Set the contention factor. * * @return the contention factor */ @@ -42,15 +42,16 @@ public @interface RangeEncrypted { long contentionFactor() default -1; /** - * Set the {@literal range} options + * Set the {@literal range} options. *

- * Should be valid extended json representing the range options and including the following values: {@code min}, - * {@code max}, {@code trimFactor} and {@code sparsity}. + * Should be valid extended {@link org.bson.Document#parse(String) JSON} representing the range options and including + * the following values: {@code min}, {@code max}, {@code trimFactor} and {@code sparsity}. *

* Please note that values are data type sensitive and may require proper identification via eg. {@code $numberLong}. * - * @return the json representation of range options + * @return the {@link org.bson.Document#parse(String) JSON} representation of range options. */ @AliasFor(annotation = Queryable.class, value = "queryAttributes") String rangeOptions() default ""; + } 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 ad64e85ea..8d9ea80fe 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 @@ -16,21 +16,25 @@ package org.springframework.data.mongodb.core.schema; import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; 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; /** * @author Christoph Strobl * @since 4.5 */ -public class QueryCharacteristics { +public class QueryCharacteristics implements Streamable { - private static final QueryCharacteristics NONE = new QueryCharacteristics(List.of()); + private static final QueryCharacteristics NONE = new QueryCharacteristics(Collections.emptyList()); private final List characteristics; @@ -46,14 +50,19 @@ public class QueryCharacteristics { return new QueryCharacteristics(List.copyOf(characteristics)); } - QueryCharacteristics(QueryCharacteristic... characteristics) { - this.characteristics = Arrays.asList(characteristics); + public static QueryCharacteristics of(QueryCharacteristic... characteristics) { + return new QueryCharacteristics(Arrays.asList(characteristics)); } public List getCharacteristics() { return characteristics; } + @Override + public Iterator iterator() { + return this.characteristics.iterator(); + } + public static RangeQuery range() { return new RangeQuery<>(); } @@ -96,7 +105,8 @@ public class QueryCharacteristics { this(Range.unbounded(), null, null, null); } - public RangeQuery(Range valueRange, Integer trimFactor, Long sparsity, Long contention) { + public RangeQuery(@Nullable Range valueRange, @Nullable Integer trimFactor, @Nullable Long sparsity, + @Nullable Long contention) { this.valueRange = valueRange; this.trimFactor = trimFactor; this.sparsity = sparsity; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/encryption/RangeEncryptionTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/encryption/RangeEncryptionTests.java index 08fdab921..5d3c6275e 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/encryption/RangeEncryptionTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/encryption/RangeEncryptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 the original author or authors. + * Copyright 2024-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +15,8 @@ */ package org.springframework.data.mongodb.core.encryption; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.springframework.data.mongodb.core.query.Criteria.where; +import static org.assertj.core.api.Assertions.*; +import static org.springframework.data.mongodb.core.query.Criteria.*; import java.security.SecureRandom; import java.util.LinkedHashMap; @@ -35,6 +34,7 @@ import org.bson.Document; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; @@ -359,7 +359,7 @@ class RangeEncryptionTests { path = StringUtils.arrayToDelimitedString(ctx.getProperty().getMongoField().getName().parts(), "."); } if (ctx.getOperatorContext() != null) { - path = ctx.getOperatorContext().getPath(); + path = ctx.getOperatorContext().path(); } return EncryptionKey.keyId(keyHolder.getEncryptionKey(path)); })); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/schema/MongoJsonSchemaUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/schema/MongoJsonSchemaUnitTests.java index e2c385464..169130561 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/schema/MongoJsonSchemaUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/schema/MongoJsonSchemaUnitTests.java @@ -15,13 +15,10 @@ */ package org.springframework.data.mongodb.core.schema; -import static org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.EncryptedJsonSchemaProperty.rangeEncrypted; +import static org.springframework.data.mongodb.core.schema.IdentifiableJsonSchemaProperty.EncryptedJsonSchemaProperty.*; +import static org.springframework.data.mongodb.core.schema.JsonSchemaProperty.*; import static org.springframework.data.mongodb.core.schema.JsonSchemaProperty.encrypted; -import static org.springframework.data.mongodb.core.schema.JsonSchemaProperty.number; -import static org.springframework.data.mongodb.core.schema.JsonSchemaProperty.queryable; -import static org.springframework.data.mongodb.core.schema.JsonSchemaProperty.string; -import static org.springframework.data.mongodb.test.util.Assertions.assertThat; -import static org.springframework.data.mongodb.test.util.Assertions.assertThatIllegalArgumentException; +import static org.springframework.data.mongodb.test.util.Assertions.*; import java.util.Arrays; import java.util.Collections; @@ -119,13 +116,27 @@ class MongoJsonSchemaUnitTests { List.of(QueryCharacteristics.range().contention(0).trimFactor(1).sparsity(1).min(0).max(200)))) .build(); - assertThat(schema.toDocument()).isEqualTo(new Document("$jsonSchema", - new Document("type", "object").append("properties", - new Document("ssn", - new Document("encrypt", - new Document("bsonType", "long").append("algorithm", "Range").append("queries", - List.of(new Document("contention", 0L).append("trimFactor", 1).append("sparsity", 1L) - .append("queryType", "range").append("min", 0).append("max", 200)))))))); + assertThat(schema.toDocument().get("$jsonSchema", Document.class)).isEqualTo(""" + { + "type": "object", + "properties": { + "ssn": { + "encrypt": { + "bsonType": "long", + "algorithm": "Range", + "queries": [{ + "queryType": "range", + "contention": {$numberLong: "0"}, + "trimFactor": 1, + "sparsity": {$numberLong: "1"}, + "min": 0, + "max": 200 + }] + } + } + } + } + """); } @Test // DATAMONGO-1835