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 212d5edd3..815a68994 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 @@ -21,12 +21,11 @@ import java.util.Collections; import java.util.EnumSet; import java.util.List; -import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; -import org.springframework.data.mapping.SimplePropertyHandler; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mongodb.core.convert.MongoConverter; 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.schema.IdentifiableJsonSchemaProperty.ObjectJsonSchemaProperty; import org.springframework.data.mongodb.core.schema.JsonSchemaObject; @@ -35,7 +34,6 @@ import org.springframework.data.mongodb.core.schema.JsonSchemaProperty; import org.springframework.data.mongodb.core.schema.MongoJsonSchema; import org.springframework.data.mongodb.core.schema.MongoJsonSchema.MongoJsonSchemaBuilder; import org.springframework.data.mongodb.core.schema.TypedJsonSchemaObject; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; @@ -45,26 +43,28 @@ import org.springframework.util.ObjectUtils; * {@link MongoJsonSchemaCreator} implementation using both {@link MongoConverter} and {@link MappingContext} to obtain * domain type meta information which considers {@link org.springframework.data.mongodb.core.mapping.Field field names} * and {@link org.springframework.data.mongodb.core.convert.MongoCustomConversions custom conversions}. - * + * * @author Christoph Strobl + * @author Mark Paluch * @since 2.2 */ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator { - private MongoConverter converter; - private MappingContext mappingContext; + private final MongoConverter converter; + private final MappingContext, MongoPersistentProperty> mappingContext; /** * Create a new instance of {@link MappingMongoJsonSchemaCreator}. * * @param converter must not be {@literal null}. */ + @SuppressWarnings("unchecked") MappingMongoJsonSchemaCreator(MongoConverter converter) { Assert.notNull(converter, "Converter must not be null!"); this.converter = converter; - this.mappingContext = converter.getMappingContext(); - + this.mappingContext = (MappingContext, MongoPersistentProperty>) converter + .getMappingContext(); } /* @@ -74,7 +74,7 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator { @Override public MongoJsonSchema createSchemaFor(Class type) { - PersistentEntity entity = mappingContext.getPersistentEntity(type); + MongoPersistentEntity entity = mappingContext.getRequiredPersistentEntity(type); MongoJsonSchemaBuilder schemaBuilder = MongoJsonSchema.builder(); List schemaProperties = computePropertiesForEntity(Collections.emptyList(), entity); @@ -84,35 +84,33 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator { } - private List computePropertiesForEntity(List path, - PersistentEntity entity) { + private List computePropertiesForEntity(List path, + MongoPersistentEntity entity) { List schemaProperties = new ArrayList<>(); - entity.doWithProperties((SimplePropertyHandler) nested -> { - ArrayList currentPath = new ArrayList<>(path); + for (MongoPersistentProperty nested : entity) { + + List currentPath = new ArrayList<>(path); if (path.contains(nested)) { // cycle guard schemaProperties.add(createSchemaProperty(computePropertyFieldName(CollectionUtils.lastElement(currentPath)), Object.class, false)); - return; + break; } currentPath.add(nested); - JsonSchemaProperty jsonSchemaProperty = computeSchemaForProperty(currentPath, entity); - if (jsonSchemaProperty != null) { - schemaProperties.add(jsonSchemaProperty); - } - }); + schemaProperties.add(computeSchemaForProperty(currentPath)); + } return schemaProperties; } - private JsonSchemaProperty computeSchemaForProperty(List path, PersistentEntity parent) { + private JsonSchemaProperty computeSchemaForProperty(List path) { - PersistentProperty property = CollectionUtils.lastElement(path); + MongoPersistentProperty property = CollectionUtils.lastElement(path); - boolean required = isRequiredProperty(parent, property); + boolean required = isRequiredProperty(property); Class rawTargetType = computeTargetType(property); // target type before conversion Class targetType = converter.getTypeMapper().getWriteTargetTypeFor(rawTargetType); // conversion target type @@ -133,12 +131,12 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator { return createSchemaProperty(fieldName, targetType, required); } - private JsonSchemaProperty createObjectSchemaPropertyForEntity(List path, - PersistentProperty property, boolean required) { + private JsonSchemaProperty createObjectSchemaPropertyForEntity(List path, + MongoPersistentProperty property, boolean required) { ObjectJsonSchemaProperty target = JsonSchemaProperty.object(property.getName()); List nestedProperties = computePropertiesForEntity(path, - mappingContext.getPersistentEntity(property)); + mappingContext.getRequiredPersistentEntity(property)); return createPotentiallyRequiredSchemaProperty( target.properties(nestedProperties.toArray(new JsonSchemaProperty[0])), required); @@ -147,6 +145,7 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator { private JsonSchemaProperty createEnumSchemaProperty(String fieldName, Class targetType, boolean required) { List possibleValues = new ArrayList<>(); + for (Object enumValue : EnumSet.allOf((Class) targetType)) { possibleValues.add(converter.convertToMongoType(enumValue)); } @@ -178,10 +177,8 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator { : property.getName(); } - private boolean isRequiredProperty(PersistentEntity parent, PersistentProperty property) { - - return (parent.isConstructorArgument(property) && !property.isAnnotationPresent(Nullable.class)) - || property.getType().isPrimitive(); + private boolean isRequiredProperty(PersistentProperty property) { + return property.getType().isPrimitive(); } private Class computeTargetType(PersistentProperty property) { @@ -196,7 +193,7 @@ class MappingMongoJsonSchemaCreator implements MongoJsonSchemaCreator { } if (mongoProperty.hasExplicitWriteTarget()) { - return mongoProperty.findAnnotation(Field.class).targetType().getJavaClass(); + return mongoProperty.getRequiredAnnotation(Field.class).targetType().getJavaClass(); } return mongoProperty.getFieldType() != mongoProperty.getActualType() ? Object.class : mongoProperty.getFieldType(); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoJsonSchemaCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoJsonSchemaCreator.java index a3cbf48e8..a20b353e0 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoJsonSchemaCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoJsonSchemaCreator.java @@ -23,29 +23,30 @@ import org.springframework.util.Assert; * {@link MongoJsonSchemaCreator} extracts the {@link MongoJsonSchema} for a given {@link Class} by applying the * following mapping rules. *

- * Required Properties
- * - All Constructor arguments annotated with {@link org.springframework.lang.Nullable}.
- * - Properties of primitive type.
- *

- *

- * Ignored Properties
- * - All properties annotated with {@link org.springframework.data.annotation.Transient}.
- *

- *

- * Property Type Mapping
- * - {@link java.lang.Object} -> {@code type : 'object'}
- * - {@link java.util.Arrays} -> {@code type : 'array'}
- * - {@link java.util.Collection} -> {@code type : 'array'}
- * - {@link java.util.Map} -> {@code type : 'object'}
- * - {@link java.lang.Enum} -> {@code type : 'string', enum : [the enum values]}
- * - Simple Types -> {@code type : 'the corresponding bson type' }
- * - Domain Types -> {@code type : 'object', properties : {the types properties} }
+ * Required Properties + *

    + *
  • Properties of primitive type
  • + *
+ * Ignored Properties + *
    + *
  • All properties annotated with {@link org.springframework.data.annotation.Transient}
  • + *
+ * Property Type Mapping + *
    + *
  • {@link java.lang.Object} -> {@code type : 'object'}
  • + *
  • {@link java.util.Arrays} -> {@code type : 'array'}
  • + *
  • {@link java.util.Collection} -> {@code type : 'array'}
  • + *
  • {@link java.util.Map} -> {@code type : 'object'}
  • + *
  • {@link java.lang.Enum} -> {@code type : 'string', enum : [the enum values]}
  • + *
  • Simple Types -> {@code type : 'the corresponding bson type' }
  • + *
  • Domain Types -> {@code type : 'object', properties : {the types properties} }
  • + *
*
* {@link org.springframework.data.annotation.Id _id} properties using types that can be converted into * {@link org.bson.types.ObjectId} like {@link String} will be mapped to {@code type : 'object'} unless there is more * specific information available via the {@link org.springframework.data.mongodb.core.mapping.MongoId} annotation. *

- * + * * @author Christoph Strobl * @since 2.2 */ @@ -66,7 +67,7 @@ public interface MongoJsonSchemaCreator { * @param mongoConverter must not be {@literal null}. * @return new instance of {@link MongoJsonSchemaCreator}. */ - static MongoJsonSchemaCreator jsonSchemaCreator(MongoConverter mongoConverter) { + static MongoJsonSchemaCreator create(MongoConverter mongoConverter) { Assert.notNull(mongoConverter, "MongoConverter must not be null!"); return new MappingMongoJsonSchemaCreator(mongoConverter); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultMongoTypeMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultMongoTypeMapper.java index ee3b9aaa2..b16681561 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultMongoTypeMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultMongoTypeMapper.java @@ -15,14 +15,16 @@ */ package org.springframework.data.mongodb.core.convert; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.Function; +import java.util.function.UnaryOperator; import org.bson.Document; import org.bson.conversions.Bson; + +import org.springframework.data.convert.CustomConversions; import org.springframework.data.convert.DefaultTypeMapper; import org.springframework.data.convert.SimpleTypeInformationMapper; import org.springframework.data.convert.TypeAliasAccessor; @@ -59,29 +61,58 @@ public class DefaultMongoTypeMapper extends DefaultTypeMapper implements M private final TypeAliasAccessor accessor; private final @Nullable String typeKey; - private Function, Class> writeTarget = it -> it; + private UnaryOperator> writeTarget = UnaryOperator.identity(); + /** + * Create a new {@link MongoTypeMapper} with fully-qualified type hints using {@code _class}. + */ public DefaultMongoTypeMapper() { this(DEFAULT_TYPE_KEY); } + /** + * Create a new {@link MongoTypeMapper} with fully-qualified type hints using {@code typeKey}. + * + * @param typeKey name of the field to read and write type hints. Can be {@literal null} to disable type hints. + */ public DefaultMongoTypeMapper(@Nullable String typeKey) { - this(typeKey, Arrays.asList(new SimpleTypeInformationMapper())); + this(typeKey, Collections.singletonList(new SimpleTypeInformationMapper())); } + /** + * Create a new {@link MongoTypeMapper} with fully-qualified type hints using {@code typeKey}. + * + * @param typeKey name of the field to read and write type hints. Can be {@literal null} to disable type hints. + * @param mappingContext the mapping context. + */ public DefaultMongoTypeMapper(@Nullable String typeKey, MappingContext, ?> mappingContext) { this(typeKey, new DocumentTypeAliasAccessor(typeKey), mappingContext, - Arrays.asList(new SimpleTypeInformationMapper())); + Collections.singletonList(new SimpleTypeInformationMapper())); } + /** + * Create a new {@link MongoTypeMapper} with fully-qualified type hints using {@code typeKey}. Uses + * {@link UnaryOperator} to apply {@link CustomConversions}. + * + * @param typeKey name of the field to read and write type hints. Can be {@literal null} to disable type hints. + * @param mappingContext the mapping context to look up types using type hints. + * @see MappingMongoConverter#getWriteTarget(Class) + */ public DefaultMongoTypeMapper(@Nullable String typeKey, - MappingContext, ?> mappingContext, Function, Class> writeTarget) { + MappingContext, ?> mappingContext, UnaryOperator> writeTarget) { this(typeKey, new DocumentTypeAliasAccessor(typeKey), mappingContext, - Arrays.asList(new SimpleTypeInformationMapper())); + Collections.singletonList(new SimpleTypeInformationMapper())); this.writeTarget = writeTarget; } + /** + * Create a new {@link MongoTypeMapper} with fully-qualified type hints using {@code typeKey}. Uses + * {@link TypeInformationMapper} to map type hints. + * + * @param typeKey name of the field to read and write type hints. Can be {@literal null} to disable type hints. + * @param mappers + */ public DefaultMongoTypeMapper(@Nullable String typeKey, List mappers) { this(typeKey, new DocumentTypeAliasAccessor(typeKey), null, mappers); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java index ea1dd87cd..0d0e7a685 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java @@ -34,6 +34,7 @@ import org.bson.conversions.Bson; import org.bson.types.ObjectId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -122,7 +123,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App this.dbRefResolver = dbRefResolver; this.mappingContext = mappingContext; this.typeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext, - this::computeWriteTarget); + this::getWriteTarget); this.idMapper = new QueryMapper(this); this.spELContext = new SpELContext(DocumentPropertyAccessor.INSTANCE); @@ -672,7 +673,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App if (!property.isDbReference()) { if (property.hasExplicitWriteTarget()) { - return writeCollectionInternal(collection, new HijackedTypeInformation<>(property), new ArrayList<>()); + return writeCollectionInternal(collection, new TypeInformationWrapper<>(property), new ArrayList<>()); } return writeCollectionInternal(collection, property.getTypeInformation(), new BasicDBList()); } @@ -1608,6 +1609,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App * @param ref * @return */ + @Nullable Document readRef(DBRef ref) { return dbRefResolver.fetch(ref); } @@ -1630,7 +1632,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App * @return * @since 2.2 */ - protected Class computeWriteTarget(Class source) { + public Class getWriteTarget(Class source) { return conversions.getCustomWriteTarget(source).orElse(source); } @@ -1702,12 +1704,12 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App } } - private static class HijackedTypeInformation implements TypeInformation { + private static class TypeInformationWrapper implements TypeInformation { private MongoPersistentProperty persistentProperty; private TypeInformation delegate; - public HijackedTypeInformation(MongoPersistentProperty property) { + public TypeInformationWrapper(MongoPersistentProperty property) { this.persistentProperty = property; this.delegate = property.getTypeInformation(); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/FieldType.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/FieldType.java index 544d497c2..f550e8a58 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/FieldType.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/FieldType.java @@ -31,8 +31,9 @@ import org.bson.types.ObjectId; *

* Bson types are identified by a {@code byte} {@link #getBsonType() value}. This enumeration typically returns the * according bson type value except for {@link #IMPLICIT} which is a marker to derive the field type from a property. - * + * * @author Mark Paluch + * @author Christoph Strobl * @since 2.2 * @see org.bson.BsonType */ @@ -67,7 +68,7 @@ public enum FieldType { /** * Returns the BSON type identifier. Can be {@code -1} if {@link FieldType} maps to a synthetic Bson type. - * + * * @return the BSON type identifier. Can be {@code -1} if {@link FieldType} maps to a synthetic Bson type. */ public int getBsonType() { @@ -76,7 +77,7 @@ public enum FieldType { /** * Returns the Java class used to represent the type. - * + * * @return the Java class used to represent the type. */ public Class getJavaClass() { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MappingMongoJsonSchemaCreatorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MappingMongoJsonSchemaCreatorUnitTests.java index 03b6fc27a..de77ee6b0 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MappingMongoJsonSchemaCreatorUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MappingMongoJsonSchemaCreatorUnitTests.java @@ -15,15 +15,17 @@ */ package org.springframework.data.mongodb.core; +import static org.springframework.data.mongodb.test.util.Assertions.*; + import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; -import org.assertj.core.api.Assertions; import org.bson.Document; import org.junit.Before; import org.junit.Test; + import org.springframework.data.annotation.Transient; import org.springframework.data.convert.WritingConverter; import org.springframework.data.mongodb.core.convert.MappingMongoConverter; @@ -34,10 +36,12 @@ import org.springframework.data.mongodb.core.mapping.FieldType; import org.springframework.data.mongodb.core.mapping.MongoId; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.core.schema.MongoJsonSchema; -import org.springframework.lang.Nullable; /** + * Unit tests for {@link MappingMongoJsonSchemaCreator}. + * * @author Christoph Strobl + * @author Mark Paluch */ public class MappingMongoJsonSchemaCreatorUnitTests { @@ -58,52 +62,25 @@ public class MappingMongoJsonSchemaCreatorUnitTests { MongoJsonSchema schema = schemaCreator.createSchemaFor(VariousFieldTypes.class); - Assertions.assertThat(schema.toDocument().get("$jsonSchema", Document.class)) - .isEqualTo(Document.parse(VARIOUS_FIELD_TYPES)); - } - - @Test // DATAMONGO-1849 - public void requiredCtorArgs() { - - MongoJsonSchema schema = schemaCreator.createSchemaFor(RequiredArgsCtor.class); - Assertions.assertThat(schema.toDocument().get("$jsonSchema", Document.class)) - .isEqualTo(Document.parse(REQUIRED_ARGS_CTOR)); - } - - @Test // DATAMONGO-1849 - public void withNestedObject() { - - MongoJsonSchema schema = schemaCreator.createSchemaFor(WithNestedDomainType.class); - Assertions.assertThat(schema.toDocument().get("$jsonSchema", Document.class)) - .isEqualTo(Document.parse(WITH_NESTED_DOMAIN_TYPE)); - } - - @Test // DATAMONGO-1849 - public void withNestedThatHasRequiredFieldsObject() { - - MongoJsonSchema schema = schemaCreator.createSchemaFor(WithNestedDomainTypeHavingRequiredCtor.class); - - Assertions.assertThat(schema.toDocument().get("$jsonSchema", Document.class)) - .isEqualTo(Document.parse(WITH_NESTED_DOMAIN_TYPE_HAVING_REQUIRED_CTOR)); + assertThat(schema.toDocument().get("$jsonSchema", Document.class)).isEqualTo(Document.parse(VARIOUS_FIELD_TYPES)); } @Test // DATAMONGO-1849 public void withRemappedIdType() { MongoJsonSchema schema = schemaCreator.createSchemaFor(WithExplicitMongoIdTypeMapping.class); - Assertions.assertThat(schema.toDocument().get("$jsonSchema", Document.class)) - .isEqualTo(Document.parse(WITH_EXPLICIT_MONGO_ID_TYPE_MAPPING)); + assertThat(schema.toDocument().get("$jsonSchema", Document.class)).isEqualTo(WITH_EXPLICIT_MONGO_ID_TYPE_MAPPING); } @Test // DATAMONGO-1849 public void cyclic() { MongoJsonSchema schema = schemaCreator.createSchemaFor(Cyclic.class); - Assertions.assertThat(schema.toDocument().get("$jsonSchema", Document.class)).isEqualTo(Document.parse(CYCLIC)); + assertThat(schema.toDocument().get("$jsonSchema", Document.class)).isEqualTo(CYCLIC); } @Test // DATAMONGO-1849 - public void convterRegisterd() { + public void converterRegistered() { MappingMongoConverter converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mappingContext); MongoCustomConversions mcc = new MongoCustomConversions( @@ -114,8 +91,8 @@ public class MappingMongoJsonSchemaCreatorUnitTests { schemaCreator = new MappingMongoJsonSchemaCreator(converter); MongoJsonSchema schema = schemaCreator.createSchemaFor(WithNestedDomainType.class); - Assertions.assertThat(schema.toDocument().get("$jsonSchema", Document.class)).isEqualTo(Document.parse( - "{ 'type' : 'object', 'properties' : { '_id' : { 'type' : 'object' }, 'nested' : { 'type' : 'object' } } }")); + assertThat(schema.toDocument().get("$jsonSchema", Document.class)).isEqualTo( + "{ 'type' : 'object', 'properties' : { '_id' : { 'type' : 'object' }, 'nested' : { 'type' : 'object' } } }"); } // --> TYPES AND JSON @@ -171,32 +148,6 @@ public class MappingMongoJsonSchemaCreatorUnitTests { JustSomeEnum enumProperty; } - // --> REQUIRED ARGS (CTOR) - - static final String REQUIRED_ARGS_CTOR = "" + // - "{" + // - " 'type' : 'object'," + // - " 'required' : ['requiredCtorArg']," + // - " 'properties' : {" + // - " 'requiredCtorArg' : { 'type' : 'string' }," + // - " 'nullableCtorArg' : { 'type' : 'string' }," + // - " 'optionalArg' : { 'type' : 'string' }" + // - " }" + // - "}"; - - static class RequiredArgsCtor { - - String requiredCtorArg; - @Nullable String nullableCtorArg; - String optionalArg; - - public RequiredArgsCtor(String requiredCtorArg, @Nullable String nullableCtorArg) { - - this.requiredCtorArg = requiredCtorArg; - this.nullableCtorArg = nullableCtorArg; - } - } - // --> NESTED DOMAIN TYPE static final String WITH_NESTED_DOMAIN_TYPE = "" + // @@ -214,21 +165,6 @@ public class MappingMongoJsonSchemaCreatorUnitTests { VariousFieldTypes nested; } - static final String WITH_NESTED_DOMAIN_TYPE_HAVING_REQUIRED_CTOR = "" + // - "{" + // - " 'type' : 'object'," + // - " 'properties' : {" + // - " '_id' : { 'type' : 'object' }," + // - " 'nested' : " + REQUIRED_ARGS_CTOR + // - " }" + // - "}"; - - static class WithNestedDomainTypeHavingRequiredCtor { - - String id; - RequiredArgsCtor nested; - } - // --> EXPLICIT MONGO_ID MAPPING final String WITH_EXPLICIT_MONGO_ID_TYPE_MAPPING = "" + // diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index bff1c7aa1..56d296206 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -13,7 +13,7 @@ * Changed behavior of `Reactive/MongoOperations#count` now limiting the range to count matches within by passing on _offset_ & _limit_ to the server. * Kotlin extension methods accepting `KClass` are deprecated now in favor of `reified` methods. * Support of array filters in `Update` operations. -* <> from domain types. +* <> from domain types. [[new-features.2-1-0]] == What's New in Spring Data MongoDB 2.1 diff --git a/src/main/asciidoc/reference/mongo-custom-conversions.adoc b/src/main/asciidoc/reference/mongo-custom-conversions.adoc index 90d6be1aa..c823e6a81 100644 --- a/src/main/asciidoc/reference/mongo-custom-conversions.adoc +++ b/src/main/asciidoc/reference/mongo-custom-conversions.adoc @@ -2,7 +2,7 @@ == Custom Conversions - Overriding Default Mapping The most trivial way of influencing the the mapping result is by specifying the desired native MongoDB target type via the -`@Field` annotation. This allows to work with non mongoDB types like `BigDecimal` in the domain model while persisting +`@Field` annotation. This allows to work with non MongoDB types like `BigDecimal` in the domain model while persisting values in native `org.bson.types.Decimal128` format. .Explicit target type mapping diff --git a/src/main/asciidoc/reference/mongo-json-schema.adoc b/src/main/asciidoc/reference/mongo-json-schema.adoc index e53d63b3e..2f1bcf840 100644 --- a/src/main/asciidoc/reference/mongo-json-schema.adoc +++ b/src/main/asciidoc/reference/mongo-json-schema.adoc @@ -87,15 +87,14 @@ template.createCollection(Person.class, CollectionOptions.empty().schema(schema) ==== [[mongo.jsonSchema.generated]] -==== Generating the Schema +==== Generating a Schema -Setting up a schema can be a time consuming task and we encourage everyone who decides to do so, to really take the time -it takes. It's important, schema changes can be hard. However there might be times when one does not want to balked -with it, and that is where the `JsonSchemaCreator` comes into play. +Setting up a schema can be a time consuming task and we encourage everyone who decides to do so, to really take the time it takes. +It's important, schema changes can be hard. +However, there might be times when one does not want to balked with it, and that is where `JsonSchemaCreator` comes into play. -The `JsonSchemaCreator` and its default implementation generate the `MongoJsonSchema` out of the domain types metadata provided -by the mapping infrastructure. This means that <> as well as potential <> -are considered. +`JsonSchemaCreator` and its default implementation generates a `MongoJsonSchema` out of domain types metadata provided by the mapping infrastructure. +This means, that <> as well as potential <> are considered. .Generate Json Schema from domain type ==== @@ -103,25 +102,24 @@ are considered. ---- public class Person { - private final String firstname; <1> - private final @Nullable String lastname; <2> - private int age; <3> - private Species species; <4> - private Address address; <5> - private @Field(fieldType=SCRIPT) String theForce; <6> - private @Transient Boolean useTheForce; <7> + private final String firstname; <1> + private final int age; <2> + private Species species; <3> + private Address address; <4> + private @Field(fieldType=SCRIPT) String theForce; <5> + private @Transient Boolean useTheForce; <6> - public Person(String firstname, @Nullable String lastname) { <1> <2> + public Person(String firstname, int age) { <1> <2> this.firstname = firstname; - this.lastname = lastname; + this.age = age; } // gettter / setter omitted } -MongoJsonSchema schema = schemaCreator.jsonSchemaCreator(mongoOperations.getConverter()) - .createSchemaFor(DomainType.class); +MongoJsonSchema schema = MongoJsonSchemaCreator.create(mongoOperations.getConverter()) + .createSchemaFor(Person.class); template.createCollection(Person.class, CollectionOptions.empty().schema(schema)); ---- @@ -130,38 +128,36 @@ template.createCollection(Person.class, CollectionOptions.empty().schema(schema) ---- { 'type' : 'object', - 'required' : ['firstname', 'age'], <1> <3> + 'required' : ['age'], <2> 'properties' : { - 'firstname' : { 'type' : 'string' }, <1> - 'lastname' : { 'type' : 'string' }, <2> - 'age' : { 'bsonType' : 'int' } <3> - 'species' : { <4> + 'firstname' : { 'type' : 'string' }, <1> + 'age' : { 'bsonType' : 'int' } <2> + 'species' : { <3> 'type' : 'string', 'enum' : ['HUMAN', 'WOOKIE', 'UNKNOWN'] } - 'address' : { <5> + 'address' : { <4> 'type' : 'object' 'properties' : { 'postCode' : { 'type': 'string' } } }, - 'theForce' : { 'type' : 'javascript'} <6> + 'theForce' : { 'type' : 'javascript'} <5> } } ---- -<1> Required property as **not** `@Nullable` and used in the constructor. -<2> Optional property though used in the constructor it is still `@Nullable`. -<3> Primitive types are considered required properties. -<4> Enums are restricted to possible values. -<5> Object type properties get are inspected themselfes. -<6> `String` type property that is truned into `Code` by the mapping. -<7> `@Transient` properties are left out when generating the schema. +<1> Simple object properties are consideres regular properties. +<2> Primitive types are considered required properties +<3> Enums are restricted to possible values. +<4> Object type properties are inspected and represented as nested documents. +<5> `String` type property that is converted to `Code` by the converter. +<6> `@Transient` properties are omitted when generating the schema. ==== NOTE: `_id` properties using types that can be converted into `ObjectId` like `String` are mapped to `{ type : 'object' }` unless there is more specific information available via the `@MongoId` annotation. -[cols="3,1,6", options="header"] +[cols="2,2,6", options="header"] .Sepcial Schema Generation rules |=== | Java @@ -169,33 +165,33 @@ unless there is more specific information available via the `@MongoId` annotatio | Notes | `Object` -| type : object +| `type : object` | with `properties` if metadata available. | `Collection` -| type : array +| `type : array` | - | `Map` -| type : object +| `type : object` | - | `Enum` -| type : string +| `type : string` | with `enum` property holding the possible enumeration values. | `array` -| type : array +| `type : array` | simple type array unless it's a `byte[]` | `byte[]` -| bsonType : binData +| `bsonType : binData` | - |=== [[mongo.jsonSchema.query]] -==== Query a collection for matching Json Schema +==== Query a collection for matching JSON Schema You can use a schema to query any collection for documents that match a given structure defined by a JSON schema, as the following example shows: @@ -210,7 +206,7 @@ template.find(query(matchingDocumentStructure(schema)), Person.class); ==== [[mongo.jsonSchema.types]] -==== Json Schema Types +==== JSON Schema Types The following table shows the supported JSON schema types: