Browse Source

Rename Embedded annotation to Unwrapped.

The meaning of embedding a Document in MongoDB is different compared to column based stores. Typically the term is used for a Document in Document approach and not for flattening out a values into the enclosing Document.

Closes: #3600
Original pull request: #3604.
pull/3611/head
Christoph Strobl 5 years ago committed by Mark Paluch
parent
commit
5a87dec2d5
No known key found for this signature in database
GPG Key ID: 4406B84C1661DCD1
  1. 22
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
  2. 20
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java
  3. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java
  4. 8
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java
  5. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java
  6. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentEntity.java
  7. 8
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java
  8. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/UnwrapEntityContext.java
  9. 50
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Unwrapped.java
  10. 18
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/UnwrappedMongoPersistentEntity.java
  11. 18
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/UnwrappedMongoPersistentProperty.java
  12. 8
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/IndexEnsuringQueryCreationListener.java
  13. 6
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateFieldProjectionTests.java
  14. 46
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnwrappedTests.java
  15. 81
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/TypeBasedAggregationOperationContextUnitTests.java
  16. 68
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java
  17. 66
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoExampleMapperUnitTests.java
  18. 132
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java
  19. 74
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java
  20. 30
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java
  21. 12
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java
  22. 14
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Person.java
  23. 4
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java
  24. 2
      src/main/asciidoc/new-features.adoc
  25. 2
      src/main/asciidoc/reference/mapping.adoc
  26. 140
      src/main/asciidoc/reference/unwrapping-entities.adoc

22
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java

@ -62,10 +62,10 @@ import org.springframework.data.mapping.model.SpELExpressionEvaluator; @@ -62,10 +62,10 @@ import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.mapping.model.SpELExpressionParameterValueProvider;
import org.springframework.data.mongodb.CodecRegistryProvider;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.mapping.Embedded;
import org.springframework.data.mongodb.core.mapping.Embedded.OnEmpty;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.Unwrapped;
import org.springframework.data.mongodb.core.mapping.Unwrapped.OnEmpty;
import org.springframework.data.mongodb.core.mapping.event.AfterConvertCallback;
import org.springframework.data.mongodb.core.mapping.event.AfterConvertEvent;
import org.springframework.data.mongodb.core.mapping.event.AfterLoadEvent;
@ -447,10 +447,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -447,10 +447,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
continue;
}
if (prop.isEmbedded()) {
if (prop.isUnwrapped()) {
accessor.setProperty(prop,
readEmbedded(context, documentAccessor, prop, mappingContext.getRequiredPersistentEntity(prop)));
readUnwrapped(context, documentAccessor, prop, mappingContext.getRequiredPersistentEntity(prop)));
continue;
}
@ -500,17 +500,17 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -500,17 +500,17 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
@Nullable
private Object readEmbedded(ConversionContext context, DocumentAccessor documentAccessor,
private Object readUnwrapped(ConversionContext context, DocumentAccessor documentAccessor,
MongoPersistentProperty prop,
MongoPersistentEntity<?> embeddedEntity) {
MongoPersistentEntity<?> unwrappedEntity) {
if (prop.findAnnotation(Embedded.class).onEmpty().equals(OnEmpty.USE_EMPTY)) {
return read(context, embeddedEntity, (Document) documentAccessor.getDocument());
if (prop.findAnnotation(Unwrapped.class).onEmpty().equals(OnEmpty.USE_EMPTY)) {
return read(context, unwrappedEntity, (Document) documentAccessor.getDocument());
}
for (MongoPersistentProperty persistentProperty : embeddedEntity) {
for (MongoPersistentProperty persistentProperty : unwrappedEntity) {
if (documentAccessor.hasValue(persistentProperty)) {
return read(context, embeddedEntity, (Document) documentAccessor.getDocument());
return read(context, unwrappedEntity, (Document) documentAccessor.getDocument());
}
}
return null;
@ -680,7 +680,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -680,7 +680,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
TypeInformation<?> valueType = ClassTypeInformation.from(obj.getClass());
TypeInformation<?> type = prop.getTypeInformation();
if (prop.isEmbedded()) {
if (prop.isUnwrapped()) {
Document target = new Document();
writeInternal(obj, target, mappingContext.getPersistentEntity(prop));

20
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java

@ -144,7 +144,7 @@ public class QueryMapper { @@ -144,7 +144,7 @@ public class QueryMapper {
Field field = createPropertyField(entity, key, mappingContext);
// TODO: move to dedicated method
if (field.getProperty() != null && field.getProperty().isEmbedded()) {
if (field.getProperty() != null && field.getProperty().isUnwrapped()) {
Object theNestedObject = BsonUtils.get(query, key);
Document mappedValue = (Document) getMappedValue(field, theNestedObject);
@ -189,13 +189,13 @@ public class QueryMapper { @@ -189,13 +189,13 @@ public class QueryMapper {
return new Document();
}
sortObject = filterEmbeddedObjects(sortObject, entity);
sortObject = filterUnwrappedObjects(sortObject, entity);
Document mappedSort = new Document();
for (Map.Entry<String, Object> entry : BsonUtils.asMap(sortObject).entrySet()) {
Field field = createPropertyField(entity, entry.getKey(), mappingContext);
if (field.getProperty() != null && field.getProperty().isEmbedded()) {
if (field.getProperty() != null && field.getProperty().isUnwrapped()) {
continue;
}
@ -219,7 +219,7 @@ public class QueryMapper { @@ -219,7 +219,7 @@ public class QueryMapper {
Assert.notNull(fieldsObject, "FieldsObject must not be null!");
fieldsObject = filterEmbeddedObjects(fieldsObject, entity);
fieldsObject = filterUnwrappedObjects(fieldsObject, entity);
Document mappedFields = getMappedObject(fieldsObject, entity);
mapMetaAttributes(mappedFields, entity, MetaMapping.FORCE);
@ -241,7 +241,7 @@ public class QueryMapper { @@ -241,7 +241,7 @@ public class QueryMapper {
}
}
private Document filterEmbeddedObjects(Document fieldsObject, @Nullable MongoPersistentEntity<?> entity) {
private Document filterUnwrappedObjects(Document fieldsObject, @Nullable MongoPersistentEntity<?> entity) {
if (fieldsObject.isEmpty() || entity == null) {
return fieldsObject;
@ -258,13 +258,13 @@ public class QueryMapper { @@ -258,13 +258,13 @@ public class QueryMapper {
.getPersistentPropertyPath(path);
MongoPersistentProperty property = mappingContext.getPersistentPropertyPath(path).getRequiredLeafProperty();
if (property.isEmbedded() && property.isEntity()) {
if (property.isUnwrapped() && property.isEntity()) {
MongoPersistentEntity<?> embeddedEntity = mappingContext.getRequiredPersistentEntity(property);
MongoPersistentEntity<?> unwrappedEntity = mappingContext.getRequiredPersistentEntity(property);
for (MongoPersistentProperty embedded : embeddedEntity) {
for (MongoPersistentProperty unwrappedProperty : unwrappedEntity) {
DotPath dotPath = DotPath.from(persistentPropertyPath.toDotPath()).append(embedded.getName());
DotPath dotPath = DotPath.from(persistentPropertyPath.toDotPath()).append(unwrappedProperty.getName());
target.put(dotPath.toString(), field.getValue());
}
@ -564,7 +564,7 @@ public class QueryMapper { @@ -564,7 +564,7 @@ public class QueryMapper {
@Nullable
protected Object delegateConvertToMongoType(Object source, @Nullable MongoPersistentEntity<?> entity) {
if (entity != null && entity.isEmbedded()) {
if (entity != null && entity.isUnwrapped()) {
return converter.convertToMongoType(source, entity);
}

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

@ -133,7 +133,7 @@ public class UpdateMapper extends QueryMapper { @@ -133,7 +133,7 @@ public class UpdateMapper extends QueryMapper {
@Override
protected Object delegateConvertToMongoType(Object source, @Nullable MongoPersistentEntity<?> entity) {
if(entity != null && entity.isEmbedded()) {
if(entity != null && entity.isUnwrapped()) {
return converter.convertToMongoType(source, entity);
}

8
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java

@ -137,7 +137,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver { @@ -137,7 +137,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
try {
if (persistentProperty.isEntity()) {
indexes.addAll(resolveIndexForEntity(mappingContext.getPersistentEntity(persistentProperty),
persistentProperty.isEmbedded() ? "" : persistentProperty.getFieldName(), Path.of(persistentProperty),
persistentProperty.isUnwrapped() ? "" : persistentProperty.getFieldName(), Path.of(persistentProperty),
root.getCollection(), guard));
}
@ -187,7 +187,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver { @@ -187,7 +187,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
DotPath propertyDotPath = DotPath.from(dotPath);
if (!persistentProperty.isEmbedded()) {
if (!persistentProperty.isUnwrapped()) {
propertyDotPath = propertyDotPath.append(persistentProperty.getFieldName());
}
@ -216,11 +216,11 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver { @@ -216,11 +216,11 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
List<IndexDefinitionHolder> indices = new ArrayList<>(2);
if (persistentProperty.isEmbedded() && (persistentProperty.isAnnotationPresent(Indexed.class)
if (persistentProperty.isUnwrapped() && (persistentProperty.isAnnotationPresent(Indexed.class)
|| persistentProperty.isAnnotationPresent(HashIndexed.class)
|| persistentProperty.isAnnotationPresent(GeoSpatialIndexed.class))) {
throw new InvalidDataAccessApiUsageException(
String.format("Index annotation not allowed on embedded object for path '%s'.", dotPath));
String.format("Index annotation not allowed on unwrapped object for path '%s'.", dotPath));
}
if (persistentProperty.isAnnotationPresent(Indexed.class)) {

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoMappingContext.java

@ -133,10 +133,10 @@ public class MongoMappingContext extends AbstractMappingContext<MongoPersistentE @@ -133,10 +133,10 @@ public class MongoMappingContext extends AbstractMappingContext<MongoPersistentE
MongoPersistentEntity<?> entity = super.getPersistentEntity(persistentProperty);
if(entity == null || !persistentProperty.isEmbedded()) {
if(entity == null || !persistentProperty.isUnwrapped()) {
return entity;
}
return new EmbeddedMongoPersistentEntity<>(entity, new EmbeddedEntityContext(persistentProperty));
return new UnwrappedMongoPersistentEntity<>(entity, new UnwrapEntityContext(persistentProperty));
}
}

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentEntity.java

@ -95,10 +95,10 @@ public interface MongoPersistentEntity<T> extends MutablePersistentEntity<T, Mon @@ -95,10 +95,10 @@ public interface MongoPersistentEntity<T> extends MutablePersistentEntity<T, Mon
}
/**
* @return {@literal true} if the entity should be embedded.
* @return {@literal true} if the entity should be unwrapped.
* @since 3.2
*/
default boolean isEmbedded() {
default boolean isUnwrapped() {
return false;
}

8
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoPersistentProperty.java

@ -124,11 +124,11 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist @@ -124,11 +124,11 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist
}
/**
* @return {@literal true} if the property should be embedded.
* @return {@literal true} if the property should be unwrapped.
* @since 3.2
*/
default boolean isEmbedded() {
return isEntity() && isAnnotationPresent(Embedded.class);
default boolean isUnwrapped() {
return isEntity() && isAnnotationPresent(Unwrapped.class);
}
/**
@ -145,7 +145,7 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist @@ -145,7 +145,7 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
public String convert(MongoPersistentProperty source) {
if (!source.isEmbedded()) {
if (!source.isUnwrapped()) {
return source.getFieldName();
}
return "";

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/EmbeddedEntityContext.java → spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/UnwrapEntityContext.java

@ -19,11 +19,11 @@ package org.springframework.data.mongodb.core.mapping; @@ -19,11 +19,11 @@ package org.springframework.data.mongodb.core.mapping;
* @author Christoph Strobl
* @since 3.2
*/
class EmbeddedEntityContext {
class UnwrapEntityContext {
private final MongoPersistentProperty property;
public EmbeddedEntityContext(MongoPersistentProperty property) {
public UnwrapEntityContext(MongoPersistentProperty property) {
this.property = property;
}

50
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Embedded.java → spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Unwrapped.java

@ -26,10 +26,10 @@ import javax.annotation.meta.When; @@ -26,10 +26,10 @@ import javax.annotation.meta.When;
import org.springframework.core.annotation.AliasFor;
/**
* The annotation to configure a value object as embedded (flattened out) in the target document.
* The annotation to configure a value object as flattened out in the target document.
* <p />
* Depending on the {@link OnEmpty value} of {@link #onEmpty()} the property is set to {@literal null} or an empty
* instance in the case all embedded values are {@literal null} when reading from the result set.
* instance in the case all unwrapped values are {@literal null} when reading from the result set.
*
* @author Christoph Strobl
* @since 3.2
@ -37,24 +37,24 @@ import org.springframework.core.annotation.AliasFor; @@ -37,24 +37,24 @@ import org.springframework.core.annotation.AliasFor;
@Documented
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD })
public @interface Embedded {
public @interface Unwrapped {
/**
* Set the load strategy for the embedded object if all contained fields yield {@literal null} values.
* Set the load strategy for the unwrapped object if all contained fields yield {@literal null} values.
* <p />
* {@link Nullable @Embedded.Nullable} and {@link Empty @Embedded.Empty} offer shortcuts for this.
* {@link Nullable @Unwrapped.Nullable} and {@link Empty @Unwrapped.Empty} offer shortcuts for this.
*
* @return never {@link} null.
*/
OnEmpty onEmpty();
/**
* @return prefix for columns in the embedded value object. An empty {@link String} by default.
* @return prefix for columns in the unwrapped value object. An empty {@link String} by default.
*/
String prefix() default "";
/**
* Load strategy to be used {@link Embedded#onEmpty()}.
* Load strategy to be used {@link Unwrapped#onEmpty()}.
*
* @author Christoph Strobl
*/
@ -63,22 +63,22 @@ public @interface Embedded { @@ -63,22 +63,22 @@ public @interface Embedded {
}
/**
* Shortcut for a nullable embedded property.
* Shortcut for a nullable unwrapped property.
*
* <pre class="code">
* &#64;Embedded.Nullable private Address address;
* &#64;Unwrapped.Nullable private Address address;
* </pre>
*
* as alternative to the more verbose
*
* <pre class="code">
* &#64;Embedded(onEmpty = USE_NULL) &#64;javax.annotation.Nonnull(when = When.MAYBE) private Address address;
* &#64;Unwrapped(onEmpty = USE_NULL) &#64;javax.annotation.Nonnull(when = When.MAYBE) private Address address;
* </pre>
*
* @author Christoph Strobl
* @see Embedded#onEmpty()
* @see Unwrapped#onEmpty()
*/
@Embedded(onEmpty = OnEmpty.USE_NULL)
@Unwrapped(onEmpty = OnEmpty.USE_NULL)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
@ -86,35 +86,35 @@ public @interface Embedded { @@ -86,35 +86,35 @@ public @interface Embedded {
@interface Nullable {
/**
* @return prefix for columns in the embedded value object. An empty {@link String} by default.
* @return prefix for columns in the unwrapped value object. An empty {@link String} by default.
*/
@AliasFor(annotation = Embedded.class, attribute = "prefix")
@AliasFor(annotation = Unwrapped.class, attribute = "prefix")
String prefix() default "";
/**
* @return value for columns in the embedded value object. An empty {@link String} by default.
* @return value for columns in the unwrapped value object. An empty {@link String} by default.
*/
@AliasFor(annotation = Embedded.class, attribute = "prefix")
@AliasFor(annotation = Unwrapped.class, attribute = "prefix")
String value() default "";
}
/**
* Shortcut for an empty embedded property.
* Shortcut for an empty unwrapped property.
*
* <pre class="code">
* &#64;Embedded.Empty private Address address;
* &#64;Unwrapped.Empty private Address address;
* </pre>
*
* as alternative to the more verbose
*
* <pre class="code">
* &#64;Embedded(onEmpty = USE_EMPTY) &#64;javax.annotation.Nonnull(when = When.NEVER) private Address address;
* &#64;Unwrapped(onEmpty = USE_EMPTY) &#64;javax.annotation.Nonnull(when = When.NEVER) private Address address;
* </pre>
*
* @author Christoph Strobl
* @see Embedded#onEmpty()
* @see Unwrapped#onEmpty()
*/
@Embedded(onEmpty = OnEmpty.USE_EMPTY)
@Unwrapped(onEmpty = OnEmpty.USE_EMPTY)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
@ -122,15 +122,15 @@ public @interface Embedded { @@ -122,15 +122,15 @@ public @interface Embedded {
@interface Empty {
/**
* @return prefix for columns in the embedded value object. An empty {@link String} by default.
* @return prefix for columns in the unwrapped value object. An empty {@link String} by default.
*/
@AliasFor(annotation = Embedded.class, attribute = "prefix")
@AliasFor(annotation = Unwrapped.class, attribute = "prefix")
String prefix() default "";
/**
* @return value for columns in the embedded value object. An empty {@link String} by default.
* @return value for columns in the unwrapped value object. An empty {@link String} by default.
*/
@AliasFor(annotation = Embedded.class, attribute = "prefix")
@AliasFor(annotation = Unwrapped.class, attribute = "prefix")
String value() default "";
}
}

18
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/EmbeddedMongoPersistentEntity.java → spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/UnwrappedMongoPersistentEntity.java

@ -32,18 +32,18 @@ import org.springframework.data.util.TypeInformation; @@ -32,18 +32,18 @@ import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
/**
* Embedded variant of {@link MongoPersistentEntity}.
* Unwrapped variant of {@link MongoPersistentEntity}.
*
* @author Christoph Strobl
* @since 3.2
* @see Embedded
* @see Unwrapped
*/
class EmbeddedMongoPersistentEntity<T> implements MongoPersistentEntity<T> {
class UnwrappedMongoPersistentEntity<T> implements MongoPersistentEntity<T> {
private final EmbeddedEntityContext context;
private final UnwrapEntityContext context;
private final MongoPersistentEntity<T> delegate;
public EmbeddedMongoPersistentEntity(MongoPersistentEntity<T> delegate, EmbeddedEntityContext context) {
public UnwrappedMongoPersistentEntity(MongoPersistentEntity<T> delegate, UnwrapEntityContext context) {
this.context = context;
this.delegate = delegate;
@ -153,7 +153,7 @@ class EmbeddedMongoPersistentEntity<T> implements MongoPersistentEntity<T> { @@ -153,7 +153,7 @@ class EmbeddedMongoPersistentEntity<T> implements MongoPersistentEntity<T> {
return persistentProperty;
}
throw new RuntimeException(":kladjnf");
throw new IllegalStateException(String.format("Required property %s not found for %s!", name, getType()));
}
@Override
@ -291,7 +291,7 @@ class EmbeddedMongoPersistentEntity<T> implements MongoPersistentEntity<T> { @@ -291,7 +291,7 @@ class EmbeddedMongoPersistentEntity<T> implements MongoPersistentEntity<T> {
if (source == null) {
return source;
}
return new EmbeddedMongoPersistentProperty(source, context);
return new UnwrappedMongoPersistentProperty(source, context);
}
@Override
@ -320,7 +320,7 @@ class EmbeddedMongoPersistentEntity<T> implements MongoPersistentEntity<T> { @@ -320,7 +320,7 @@ class EmbeddedMongoPersistentEntity<T> implements MongoPersistentEntity<T> {
}
@Override
public boolean isEmbedded() {
return context.getProperty().isEmbedded();
public boolean isUnwrapped() {
return context.getProperty().isUnwrapped();
}
}

18
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/EmbeddedMongoPersistentProperty.java → spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/UnwrappedMongoPersistentProperty.java

@ -26,18 +26,18 @@ import org.springframework.data.util.TypeInformation; @@ -26,18 +26,18 @@ import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
/**
* Embedded variant of {@link MongoPersistentProperty}.
* Unwrapped variant of {@link MongoPersistentProperty}.
*
* @author Christoph Strobl
* @since 3.2
* @see Embedded
* @see Unwrapped
*/
class EmbeddedMongoPersistentProperty implements MongoPersistentProperty {
class UnwrappedMongoPersistentProperty implements MongoPersistentProperty {
private final MongoPersistentProperty delegate;
private final EmbeddedEntityContext context;
private final UnwrapEntityContext context;
public EmbeddedMongoPersistentProperty(MongoPersistentProperty delegate, EmbeddedEntityContext context) {
public UnwrappedMongoPersistentProperty(MongoPersistentProperty delegate, UnwrapEntityContext context) {
this.delegate = delegate;
this.context = context;
@ -46,11 +46,11 @@ class EmbeddedMongoPersistentProperty implements MongoPersistentProperty { @@ -46,11 +46,11 @@ class EmbeddedMongoPersistentProperty implements MongoPersistentProperty {
@Override
public String getFieldName() {
if (!context.getProperty().isEmbedded()) {
if (!context.getProperty().isUnwrapped()) {
return delegate.getFieldName();
}
return context.getProperty().findAnnotation(Embedded.class).prefix() + delegate.getFieldName();
return context.getProperty().findAnnotation(Unwrapped.class).prefix() + delegate.getFieldName();
}
@Override
@ -241,8 +241,8 @@ class EmbeddedMongoPersistentProperty implements MongoPersistentProperty { @@ -241,8 +241,8 @@ class EmbeddedMongoPersistentProperty implements MongoPersistentProperty {
}
@Override
public boolean isEmbedded() {
return delegate.isEmbedded();
public boolean isUnwrapped() {
return delegate.isUnwrapped();
}
@Override

8
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/IndexEnsuringQueryCreationListener.java

@ -30,7 +30,7 @@ import org.springframework.data.mongodb.UncategorizedMongoDbException; @@ -30,7 +30,7 @@ import org.springframework.data.mongodb.UncategorizedMongoDbException;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.index.Index;
import org.springframework.data.mongodb.core.index.IndexOperationsProvider;
import org.springframework.data.mongodb.core.mapping.Embedded;
import org.springframework.data.mongodb.core.mapping.Unwrapped;
import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.data.mongodb.repository.query.MongoEntityMetadata;
import org.springframework.data.mongodb.repository.query.PartTreeMongoQuery;
@ -90,7 +90,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr @@ -90,7 +90,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr
if (GEOSPATIAL_TYPES.contains(part.getType())) {
return;
}
if (isIndexOnEmbeddedType(part)) {
if (isIndexOnUnwrappedType(part)) {
return;
}
@ -138,7 +138,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr @@ -138,7 +138,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr
LOG.debug(String.format("Created %s!", index));
}
public boolean isIndexOnEmbeddedType(Part part) {
public boolean isIndexOnUnwrappedType(Part part) {
// TODO we could do it for nested fields in the
Field field = ReflectionUtils.findField(part.getProperty().getOwningType().getType(),
@ -148,7 +148,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr @@ -148,7 +148,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr
return false;
}
return AnnotatedElementUtils.hasAnnotation(field, Embedded.class);
return AnnotatedElementUtils.hasAnnotation(field, Unwrapped.class);
}
private static Direction toDirection(Sort sort, String property) {

6
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateFieldProjectionTests.java

@ -30,8 +30,8 @@ import org.springframework.data.annotation.Id; @@ -30,8 +30,8 @@ import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.MongoExpression;
import org.springframework.data.mongodb.core.aggregation.AggregationSpELExpression;
import org.springframework.data.mongodb.core.aggregation.StringOperators;
import org.springframework.data.mongodb.core.mapping.Embedded;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.Unwrapped;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.test.util.MongoTemplateExtension;
@ -126,7 +126,7 @@ class MongoTemplateFieldProjectionTests { @@ -126,7 +126,7 @@ class MongoTemplateFieldProjectionTests {
}
@Test // GH-3583
void mapsProjectionOnEmbedded() {
void mapsProjectionOnUnwrapped() {
luke.address = new Address();
luke.address.planet = "tatoine";
@ -164,7 +164,7 @@ class MongoTemplateFieldProjectionTests { @@ -164,7 +164,7 @@ class MongoTemplateFieldProjectionTests {
@Field("last_name") //
String lastname;
@Embedded.Nullable Address address;
@Unwrapped.Nullable Address address;
Person toUpperCaseLastnameClone(Person source) {

46
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateEmbeddedTests.java → spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnwrappedTests.java

@ -20,50 +20,50 @@ import static org.springframework.data.mongodb.core.query.Criteria.*; @@ -20,50 +20,50 @@ import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.Query.*;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Arrays;
import java.util.List;
import lombok.ToString;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.data.mongodb.core.mapping.Embedded;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.Unwrapped;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.test.util.MongoTemplateExtension;
import org.springframework.data.mongodb.test.util.Template;
/**
* Integration tests for {@link Embedded}.
* Integration tests for {@link Unwrapped}.
*
* @author Christoph Strobl
*/
@ExtendWith(MongoTemplateExtension.class)
class MongoTemplateEmbeddedTests {
class MongoTemplateUnwrappedTests {
private static @Template MongoTemplate template;
@Test // DATAMONGO-1902
void readWrite() {
WithEmbedded source = new WithEmbedded();
WithUnwrapped source = new WithUnwrapped();
source.id = "id-1";
source.embeddableValue = new EmbeddableType();
source.embeddableValue = new UnwrappableType();
source.embeddableValue.stringValue = "string-val";
source.embeddableValue.listValue = Arrays.asList("list-val-1", "list-val-2");
source.embeddableValue.atFieldAnnotatedValue = "@Field";
template.save(source);
assertThat(template.findOne(query(where("id").is(source.id)), WithEmbedded.class)).isEqualTo(source);
assertThat(template.findOne(query(where("id").is(source.id)), WithUnwrapped.class)).isEqualTo(source);
}
@Test // DATAMONGO-1902
void filterOnEmbeddedValue() {
void filterOnUnwrappedValue() {
WithEmbedded source = new WithEmbedded();
WithUnwrapped source = new WithUnwrapped();
source.id = "id-1";
source.embeddableValue = new EmbeddableType();
source.embeddableValue = new UnwrappableType();
source.embeddableValue.stringValue = "string-val";
source.embeddableValue.listValue = Arrays.asList("list-val-1", "list-val-2");
source.embeddableValue.atFieldAnnotatedValue = "@Field";
@ -71,31 +71,31 @@ class MongoTemplateEmbeddedTests { @@ -71,31 +71,31 @@ class MongoTemplateEmbeddedTests {
template.save(source);
assertThat(template.findOne(
Query.query(where("embeddableValue.stringValue").is(source.embeddableValue.stringValue)), WithEmbedded.class))
Query.query(where("embeddableValue.stringValue").is(source.embeddableValue.stringValue)), WithUnwrapped.class))
.isEqualTo(source);
}
@Test // DATAMONGO-1902
void readWritePrefixed() {
WithPrefixedEmbedded source = new WithPrefixedEmbedded();
WithPrefixedUnwrapped source = new WithPrefixedUnwrapped();
source.id = "id-1";
source.embeddableValue = new EmbeddableType();
source.embeddableValue = new UnwrappableType();
source.embeddableValue.stringValue = "string-val";
source.embeddableValue.listValue = Arrays.asList("list-val-1", "list-val-2");
source.embeddableValue.atFieldAnnotatedValue = "@Field";
template.save(source);
assertThat(template.findOne(query(where("id").is(source.id)), WithPrefixedEmbedded.class)).isEqualTo(source);
assertThat(template.findOne(query(where("id").is(source.id)), WithPrefixedUnwrapped.class)).isEqualTo(source);
}
@Test // DATAMONGO-1902
void filterOnPrefixedEmbeddedValue() {
void filterOnPrefixedUnwrappedValue() {
WithPrefixedEmbedded source = new WithPrefixedEmbedded();
WithPrefixedUnwrapped source = new WithPrefixedUnwrapped();
source.id = "id-1";
source.embeddableValue = new EmbeddableType();
source.embeddableValue = new UnwrappableType();
source.embeddableValue.stringValue = "string-val";
source.embeddableValue.listValue = Arrays.asList("list-val-1", "list-val-2");
source.embeddableValue.atFieldAnnotatedValue = "@Field";
@ -104,30 +104,30 @@ class MongoTemplateEmbeddedTests { @@ -104,30 +104,30 @@ class MongoTemplateEmbeddedTests {
assertThat(
template.findOne(Query.query(where("embeddableValue.stringValue").is(source.embeddableValue.stringValue)),
WithPrefixedEmbedded.class)).isEqualTo(source);
WithPrefixedUnwrapped.class)).isEqualTo(source);
}
@EqualsAndHashCode
@ToString
static class WithEmbedded {
static class WithUnwrapped {
String id;
@Embedded.Nullable EmbeddableType embeddableValue;
@Unwrapped.Nullable UnwrappableType embeddableValue;
}
@EqualsAndHashCode
@ToString
static class WithPrefixedEmbedded {
static class WithPrefixedUnwrapped {
String id;
@Embedded.Nullable("prefix-") EmbeddableType embeddableValue;
@Unwrapped.Nullable("prefix-") UnwrappableType embeddableValue;
}
@EqualsAndHashCode
@ToString
static class EmbeddableType {
static class UnwrappableType {
String stringValue;
List<String> listValue;

81
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/TypeBasedAggregationOperationContextUnitTests.java

@ -45,8 +45,8 @@ import org.springframework.data.mongodb.core.convert.DbRefResolver; @@ -45,8 +45,8 @@ import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.mapping.Embedded;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.Unwrapped;
import org.springframework.data.mongodb.core.query.Criteria;
/**
@ -358,11 +358,11 @@ public class TypeBasedAggregationOperationContextUnitTests { @@ -358,11 +358,11 @@ public class TypeBasedAggregationOperationContextUnitTests {
}
@Test // DATAMONGO-1902
void rendersProjectOnEmbeddedFieldCorrectly() {
void rendersProjectOnUnwrappableTypeFieldCorrectly() {
AggregationOperationContext context = getContext(WithEmbedded.class);
AggregationOperationContext context = getContext(WithUnwrapped.class);
Document agg = newAggregation(WithEmbedded.class, project().and("embeddableType.stringValue").as("val"))
Document agg = newAggregation(WithUnwrapped.class, project().and("unwrappedValue.stringValue").as("val"))
.toDocument("collection", context);
assertThat(getPipelineElementFromAggregationAt(agg, 0).get("$project"))
@ -370,11 +370,11 @@ public class TypeBasedAggregationOperationContextUnitTests { @@ -370,11 +370,11 @@ public class TypeBasedAggregationOperationContextUnitTests {
}
@Test // DATAMONGO-1902
void rendersProjectOnEmbeddedFieldWithAtFieldAnnotationCorrectly() {
void rendersProjectOnUnwrappedFieldWithAtFieldAnnotationCorrectly() {
AggregationOperationContext context = getContext(WithEmbedded.class);
AggregationOperationContext context = getContext(WithUnwrapped.class);
Document agg = newAggregation(WithEmbedded.class, project().and("embeddableType.atFieldAnnotatedValue").as("val"))
Document agg = newAggregation(WithUnwrapped.class, project().and("unwrappedValue.atFieldAnnotatedValue").as("val"))
.toDocument("collection", context);
assertThat(getPipelineElementFromAggregationAt(agg, 0).get("$project"))
@ -382,11 +382,11 @@ public class TypeBasedAggregationOperationContextUnitTests { @@ -382,11 +382,11 @@ public class TypeBasedAggregationOperationContextUnitTests {
}
@Test // DATAMONGO-1902
void rendersProjectOnPrefixedEmbeddedFieldCorrectly() {
void rendersProjectOnPrefixedUnwrappedFieldCorrectly() {
AggregationOperationContext context = getContext(WithEmbedded.class);
AggregationOperationContext context = getContext(WithUnwrapped.class);
Document agg = newAggregation(WithEmbedded.class, project().and("prefixedEmbeddableValue.stringValue").as("val"))
Document agg = newAggregation(WithUnwrapped.class, project().and("prefixedUnwrappedValue.stringValue").as("val"))
.toDocument("collection", context);
assertThat(getPipelineElementFromAggregationAt(agg, 0).get("$project"))
@ -394,64 +394,65 @@ public class TypeBasedAggregationOperationContextUnitTests { @@ -394,64 +394,65 @@ public class TypeBasedAggregationOperationContextUnitTests {
}
@Test // DATAMONGO-1902
void rendersProjectOnPrefixedEmbeddedFieldWithAtFieldAnnotationCorrectly() {
void rendersProjectOnPrefixedUnwrappedFieldWithAtFieldAnnotationCorrectly() {
AggregationOperationContext context = getContext(WithEmbedded.class);
AggregationOperationContext context = getContext(WithUnwrapped.class);
Document agg = newAggregation(WithEmbedded.class,
project().and("prefixedEmbeddableValue.atFieldAnnotatedValue").as("val")).toDocument("collection", context);
Document agg = newAggregation(WithUnwrapped.class,
project().and("prefixedUnwrappedValue.atFieldAnnotatedValue").as("val")).toDocument("collection", context);
assertThat(getPipelineElementFromAggregationAt(agg, 0).get("$project"))
.isEqualTo(new Document("val", "$prefix-with-at-field-annotation"));
}
@Test // DATAMONGO-1902
void rendersProjectOnNestedEmbeddedFieldCorrectly() {
void rendersProjectOnNestedUnwrappedFieldCorrectly() {
AggregationOperationContext context = getContext(WrapperAroundWithEmbedded.class);
AggregationOperationContext context = getContext(WrapperAroundWithUnwrapped.class);
Document agg = newAggregation(WrapperAroundWithEmbedded.class,
project().and("withEmbedded.embeddableType.stringValue").as("val")).toDocument("collection", context);
Document agg = newAggregation(WrapperAroundWithUnwrapped.class,
project().and("withUnwrapped.unwrappedValue.stringValue").as("val")).toDocument("collection", context);
assertThat(getPipelineElementFromAggregationAt(agg, 0).get("$project"))
.isEqualTo(new Document("val", "$withEmbedded.stringValue"));
.isEqualTo(new Document("val", "$withUnwrapped.stringValue"));
}
@Test // DATAMONGO-1902
void rendersProjectOnNestedEmbeddedFieldWithAtFieldAnnotationCorrectly() {
void rendersProjectOnNestedUnwrappedFieldWithAtFieldAnnotationCorrectly() {
AggregationOperationContext context = getContext(WrapperAroundWithEmbedded.class);
AggregationOperationContext context = getContext(WrapperAroundWithUnwrapped.class);
Document agg = newAggregation(WrapperAroundWithEmbedded.class,
project().and("withEmbedded.embeddableType.atFieldAnnotatedValue").as("val")).toDocument("collection", context);
Document agg = newAggregation(WrapperAroundWithUnwrapped.class,
project().and("withUnwrapped.unwrappedValue.atFieldAnnotatedValue").as("val")).toDocument("collection",
context);
assertThat(getPipelineElementFromAggregationAt(agg, 0).get("$project"))
.isEqualTo(new Document("val", "$withEmbedded.with-at-field-annotation"));
.isEqualTo(new Document("val", "$withUnwrapped.with-at-field-annotation"));
}
@Test // DATAMONGO-1902
void rendersProjectOnNestedPrefixedEmbeddedFieldCorrectly() {
void rendersProjectOnNestedPrefixedUnwrappedFieldCorrectly() {
AggregationOperationContext context = getContext(WrapperAroundWithEmbedded.class);
AggregationOperationContext context = getContext(WrapperAroundWithUnwrapped.class);
Document agg = newAggregation(WrapperAroundWithEmbedded.class,
project().and("withEmbedded.prefixedEmbeddableValue.stringValue").as("val")).toDocument("collection", context);
Document agg = newAggregation(WrapperAroundWithUnwrapped.class,
project().and("withUnwrapped.prefixedUnwrappedValue.stringValue").as("val")).toDocument("collection", context);
assertThat(getPipelineElementFromAggregationAt(agg, 0).get("$project"))
.isEqualTo(new Document("val", "$withEmbedded.prefix-stringValue"));
.isEqualTo(new Document("val", "$withUnwrapped.prefix-stringValue"));
}
@Test // DATAMONGO-1902
void rendersProjectOnNestedPrefixedEmbeddedFieldWithAtFieldAnnotationCorrectly() {
void rendersProjectOnNestedPrefixedUnwrappedFieldWithAtFieldAnnotationCorrectly() {
AggregationOperationContext context = getContext(WrapperAroundWithEmbedded.class);
AggregationOperationContext context = getContext(WrapperAroundWithUnwrapped.class);
Document agg = newAggregation(WrapperAroundWithEmbedded.class,
project().and("withEmbedded.prefixedEmbeddableValue.atFieldAnnotatedValue").as("val")).toDocument("collection",
Document agg = newAggregation(WrapperAroundWithUnwrapped.class,
project().and("withUnwrapped.prefixedUnwrappedValue.atFieldAnnotatedValue").as("val")).toDocument("collection",
context);
assertThat(getPipelineElementFromAggregationAt(agg, 0).get("$project"))
.isEqualTo(new Document("val", "$withEmbedded.prefix-with-at-field-annotation"));
.isEqualTo(new Document("val", "$withUnwrapped.prefix-with-at-field-annotation"));
}
@org.springframework.data.mongodb.core.mapping.Document(collection = "person")
@ -531,21 +532,21 @@ public class TypeBasedAggregationOperationContextUnitTests { @@ -531,21 +532,21 @@ public class TypeBasedAggregationOperationContextUnitTests {
@org.springframework.data.mongodb.core.mapping.Field("nestedValue2") String value2;
}
static class WrapperAroundWithEmbedded {
static class WrapperAroundWithUnwrapped {
String id;
WithEmbedded withEmbedded;
WithUnwrapped withUnwrapped;
}
static class WithEmbedded {
static class WithUnwrapped {
String id;
@Embedded.Nullable EmbeddableType embeddableType;
@Embedded.Nullable("prefix-") EmbeddableType prefixedEmbeddableValue;
@Unwrapped.Nullable UnwrappableType unwrappedValue;
@Unwrapped.Nullable("prefix-") UnwrappableType prefixedUnwrappedValue;
}
static class EmbeddableType {
static class UnwrappableType {
String stringValue;

68
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java

@ -72,13 +72,13 @@ import org.springframework.data.mongodb.core.convert.DocumentAccessorUnitTests.P @@ -72,13 +72,13 @@ import org.springframework.data.mongodb.core.convert.DocumentAccessorUnitTests.P
import org.springframework.data.mongodb.core.convert.MappingMongoConverterUnitTests.ClassWithMapUsingEnumAsKey.FooBarEnum;
import org.springframework.data.mongodb.core.geo.Sphere;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Embedded;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.FieldType;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.PersonPojoStringId;
import org.springframework.data.mongodb.core.mapping.TextScore;
import org.springframework.data.mongodb.core.mapping.Unwrapped;
import org.springframework.data.mongodb.core.mapping.event.AfterConvertCallback;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.test.util.ReflectionTestUtils;
@ -2193,9 +2193,9 @@ class MappingMongoConverterUnitTests { @@ -2193,9 +2193,9 @@ class MappingMongoConverterUnitTests {
}
@Test // DATAMONGO-1902
void writeFlattensEmbeddedType() {
void writeFlattensUnwrappedType() {
WithNullableEmbedded source = new WithNullableEmbedded();
WithNullableUnwrapped source = new WithNullableUnwrapped();
source.id = "id-1";
source.embeddableValue = new EmbeddableType();
source.embeddableValue.listValue = Arrays.asList("list-val-1", "list-val-2");
@ -2215,9 +2215,9 @@ class MappingMongoConverterUnitTests { @@ -2215,9 +2215,9 @@ class MappingMongoConverterUnitTests {
}
@Test // DATAMONGO-1902
void writePrefixesEmbeddedType() {
void writePrefixesUnwrappedType() {
WithPrefixedNullableEmbedded source = new WithPrefixedNullableEmbedded();
WithPrefixedNullableUnwrapped source = new WithPrefixedNullableUnwrapped();
source.id = "id-1";
source.embeddableValue = new EmbeddableType();
source.embeddableValue.listValue = Arrays.asList("list-val-1", "list-val-2");
@ -2238,9 +2238,9 @@ class MappingMongoConverterUnitTests { @@ -2238,9 +2238,9 @@ class MappingMongoConverterUnitTests {
}
@Test // DATAMONGO-1902
void writeNullEmbeddedType() {
void writeNullUnwrappedType() {
WithNullableEmbedded source = new WithNullableEmbedded();
WithNullableUnwrapped source = new WithNullableUnwrapped();
source.id = "id-1";
source.embeddableValue = null;
@ -2253,11 +2253,11 @@ class MappingMongoConverterUnitTests { @@ -2253,11 +2253,11 @@ class MappingMongoConverterUnitTests {
}
@Test // DATAMONGO-1902
void writeDeepNestedEmbeddedType() {
void writeDeepNestedUnwrappedType() {
WrapperAroundWithEmbedded source = new WrapperAroundWithEmbedded();
WrapperAroundWithUnwrapped source = new WrapperAroundWithUnwrapped();
source.someValue = "root-level-value";
source.nullableEmbedded = new WithNullableEmbedded();
source.nullableEmbedded = new WithNullableUnwrapped();
source.nullableEmbedded.id = "id-1";
source.nullableEmbedded.embeddableValue = new EmbeddableType();
source.nullableEmbedded.embeddableValue.listValue = Arrays.asList("list-val-1", "list-val-2");
@ -2275,7 +2275,7 @@ class MappingMongoConverterUnitTests { @@ -2275,7 +2275,7 @@ class MappingMongoConverterUnitTests {
}
@Test // DATAMONGO-1902
void readEmbeddedType() {
void readUnwrappedType() {
org.bson.Document source = new org.bson.Document("_id", "id-1") //
.append("stringValue", "string-val") //
@ -2287,12 +2287,12 @@ class MappingMongoConverterUnitTests { @@ -2287,12 +2287,12 @@ class MappingMongoConverterUnitTests {
embeddableValue.listValue = Arrays.asList("list-val-1", "list-val-2");
embeddableValue.atFieldAnnotatedValue = "@Field";
WithNullableEmbedded target = converter.read(WithNullableEmbedded.class, source);
WithNullableUnwrapped target = converter.read(WithNullableUnwrapped.class, source);
assertThat(target.embeddableValue).isEqualTo(embeddableValue);
}
@Test // DATAMONGO-1902
void readPrefixedEmbeddedType() {
void readPrefixedUnwrappedType() {
org.bson.Document source = new org.bson.Document("_id", "id-1") //
.append("prefix-stringValue", "string-val") //
@ -2304,37 +2304,37 @@ class MappingMongoConverterUnitTests { @@ -2304,37 +2304,37 @@ class MappingMongoConverterUnitTests {
embeddableValue.listValue = Arrays.asList("list-val-1", "list-val-2");
embeddableValue.atFieldAnnotatedValue = "@Field";
WithPrefixedNullableEmbedded target = converter.read(WithPrefixedNullableEmbedded.class, source);
WithPrefixedNullableUnwrapped target = converter.read(WithPrefixedNullableUnwrapped.class, source);
assertThat(target.embeddableValue).isEqualTo(embeddableValue);
}
@Test // DATAMONGO-1902
void readNullableEmbeddedTypeWhenSourceDoesNotContainValues() {
void readNullableUnwrappedTypeWhenSourceDoesNotContainValues() {
org.bson.Document source = new org.bson.Document("_id", "id-1");
WithNullableEmbedded target = converter.read(WithNullableEmbedded.class, source);
WithNullableUnwrapped target = converter.read(WithNullableUnwrapped.class, source);
assertThat(target.embeddableValue).isNull();
}
@Test // DATAMONGO-1902
void readEmptyEmbeddedTypeWhenSourceDoesNotContainValues() {
void readEmptyUnwrappedTypeWhenSourceDoesNotContainValues() {
org.bson.Document source = new org.bson.Document("_id", "id-1");
WithEmptyEmbeddedType target = converter.read(WithEmptyEmbeddedType.class, source);
WithEmptyUnwrappedType target = converter.read(WithEmptyUnwrappedType.class, source);
assertThat(target.embeddableValue).isNotNull();
}
@Test // DATAMONGO-1902
void readDeepNestedEmbeddedType() {
void readDeepNestedUnwrappedType() {
org.bson.Document source = new org.bson.Document("someValue", "root-level-value").append("nullableEmbedded",
new org.bson.Document("_id", "id-1").append("stringValue", "string-val") //
.append("listValue", Arrays.asList("list-val-1", "list-val-2")) //
.append("with-at-field-annotation", "@Field"));
WrapperAroundWithEmbedded target = converter.read(WrapperAroundWithEmbedded.class, source);
WrapperAroundWithUnwrapped target = converter.read(WrapperAroundWithUnwrapped.class, source);
EmbeddableType embeddableValue = new EmbeddableType();
embeddableValue.stringValue = "string-val";
@ -2347,12 +2347,12 @@ class MappingMongoConverterUnitTests { @@ -2347,12 +2347,12 @@ class MappingMongoConverterUnitTests {
}
@Test // DATAMONGO-1902
void readEmbeddedTypeWithComplexValue() {
void readUnwrappedTypeWithComplexValue() {
org.bson.Document source = new org.bson.Document("_id", "id-1").append("address",
new org.bson.Document("street", "1007 Mountain Drive").append("city", "Gotham"));
WithNullableEmbedded target = converter.read(WithNullableEmbedded.class, source);
WithNullableUnwrapped target = converter.read(WithNullableUnwrapped.class, source);
Address expected = new Address();
expected.city = "Gotham";
@ -2363,9 +2363,9 @@ class MappingMongoConverterUnitTests { @@ -2363,9 +2363,9 @@ class MappingMongoConverterUnitTests {
}
@Test // DATAMONGO-1902
void writeEmbeddedTypeWithComplexValue() {
void writeUnwrappedTypeWithComplexValue() {
WithNullableEmbedded source = new WithNullableEmbedded();
WithNullableUnwrapped source = new WithNullableUnwrapped();
source.id = "id-1";
source.embeddableValue = new EmbeddableType();
source.embeddableValue.address = new Address();
@ -2891,33 +2891,33 @@ class MappingMongoConverterUnitTests { @@ -2891,33 +2891,33 @@ class MappingMongoConverterUnitTests {
Date dateAsObjectId;
}
static class WrapperAroundWithEmbedded {
static class WrapperAroundWithUnwrapped {
String someValue;
WithNullableEmbedded nullableEmbedded;
WithEmptyEmbeddedType emptyEmbedded;
WithPrefixedNullableEmbedded prefixedEmbedded;
WithNullableUnwrapped nullableEmbedded;
WithEmptyUnwrappedType emptyEmbedded;
WithPrefixedNullableUnwrapped prefixedEmbedded;
}
static class WithNullableEmbedded {
static class WithNullableUnwrapped {
String id;
@Embedded.Nullable EmbeddableType embeddableValue;
@Unwrapped.Nullable EmbeddableType embeddableValue;
}
static class WithPrefixedNullableEmbedded {
static class WithPrefixedNullableUnwrapped {
String id;
@Embedded.Nullable("prefix-") EmbeddableType embeddableValue;
@Unwrapped.Nullable("prefix-") EmbeddableType embeddableValue;
}
static class WithEmptyEmbeddedType {
static class WithEmptyUnwrappedType {
String id;
@Embedded.Empty EmbeddableType embeddableValue;
@Unwrapped.Empty EmbeddableType embeddableValue;
}
@EqualsAndHashCode

66
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoExampleMapperUnitTests.java

@ -43,9 +43,9 @@ import org.springframework.data.mongodb.core.convert.QueryMapperUnitTests.WithDB @@ -43,9 +43,9 @@ import org.springframework.data.mongodb.core.convert.QueryMapperUnitTests.WithDB
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Embedded;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.Unwrapped;
import org.springframework.data.mongodb.core.query.UntypedExampleMatcher;
import org.springframework.data.util.TypeInformation;
@ -456,12 +456,12 @@ public class MongoExampleMapperUnitTests { @@ -456,12 +456,12 @@ public class MongoExampleMapperUnitTests {
}
@Test // DATAMONGO-1902
void mapsEmbeddedType() {
void mapsUnwrappedType() {
WithEmbedded probe = new WithEmbedded();
probe.embeddableType = new EmbeddableType();
probe.embeddableType.atFieldAnnotatedValue = "@Field";
probe.embeddableType.stringValue = "string-value";
WithUnwrapped probe = new WithUnwrapped();
probe.unwrappedValue = new UnwrappableType();
probe.unwrappedValue.atFieldAnnotatedValue = "@Field";
probe.unwrappedValue.stringValue = "string-value";
org.bson.Document document = mapper.getMappedExample(Example.of(probe, UntypedExampleMatcher.matching()));
assertThat(document).containsEntry("stringValue", "string-value").containsEntry("with-at-field-annotation",
@ -469,12 +469,12 @@ public class MongoExampleMapperUnitTests { @@ -469,12 +469,12 @@ public class MongoExampleMapperUnitTests {
}
@Test // DATAMONGO-1902
void mapsPrefixedEmbeddedType() {
void mapsPrefixedUnwrappedType() {
WithEmbedded probe = new WithEmbedded();
probe.prefixedEmbeddableValue = new EmbeddableType();
probe.prefixedEmbeddableValue.atFieldAnnotatedValue = "@Field";
probe.prefixedEmbeddableValue.stringValue = "string-value";
WithUnwrapped probe = new WithUnwrapped();
probe.prefixedUnwrappedValue = new UnwrappableType();
probe.prefixedUnwrappedValue.atFieldAnnotatedValue = "@Field";
probe.prefixedUnwrappedValue.stringValue = "string-value";
org.bson.Document document = mapper.getMappedExample(Example.of(probe, UntypedExampleMatcher.matching()));
assertThat(document).containsEntry("prefix-stringValue", "string-value")
@ -482,31 +482,31 @@ public class MongoExampleMapperUnitTests { @@ -482,31 +482,31 @@ public class MongoExampleMapperUnitTests {
}
@Test // DATAMONGO-1902
void mapsNestedEmbeddedType() {
void mapsNestedUnwrappedType() {
WrapperAroundWithEmbedded probe = new WrapperAroundWithEmbedded();
probe.withEmbedded = new WithEmbedded();
probe.withEmbedded.embeddableType = new EmbeddableType();
probe.withEmbedded.embeddableType.atFieldAnnotatedValue = "@Field";
probe.withEmbedded.embeddableType.stringValue = "string-value";
WrapperAroundWithUnwrapped probe = new WrapperAroundWithUnwrapped();
probe.withUnwrapped = new WithUnwrapped();
probe.withUnwrapped.unwrappedValue = new UnwrappableType();
probe.withUnwrapped.unwrappedValue.atFieldAnnotatedValue = "@Field";
probe.withUnwrapped.unwrappedValue.stringValue = "string-value";
org.bson.Document document = mapper.getMappedExample(Example.of(probe, UntypedExampleMatcher.matching()));
assertThat(document).containsEntry("withEmbedded.stringValue", "string-value")
.containsEntry("withEmbedded.with-at-field-annotation", "@Field");
assertThat(document).containsEntry("withUnwrapped.stringValue", "string-value")
.containsEntry("withUnwrapped.with-at-field-annotation", "@Field");
}
@Test // DATAMONGO-1902
void mapsNestedPrefixedEmbeddedType() {
void mapsNestedPrefixedUnwrappedType() {
WrapperAroundWithEmbedded probe = new WrapperAroundWithEmbedded();
probe.withEmbedded = new WithEmbedded();
probe.withEmbedded.prefixedEmbeddableValue = new EmbeddableType();
probe.withEmbedded.prefixedEmbeddableValue.atFieldAnnotatedValue = "@Field";
probe.withEmbedded.prefixedEmbeddableValue.stringValue = "string-value";
WrapperAroundWithUnwrapped probe = new WrapperAroundWithUnwrapped();
probe.withUnwrapped = new WithUnwrapped();
probe.withUnwrapped.prefixedUnwrappedValue = new UnwrappableType();
probe.withUnwrapped.prefixedUnwrappedValue.atFieldAnnotatedValue = "@Field";
probe.withUnwrapped.prefixedUnwrappedValue.stringValue = "string-value";
org.bson.Document document = mapper.getMappedExample(Example.of(probe, UntypedExampleMatcher.matching()));
assertThat(document).containsEntry("withEmbedded.prefix-stringValue", "string-value")
.containsEntry("withEmbedded.prefix-with-at-field-annotation", "@Field");
assertThat(document).containsEntry("withUnwrapped.prefix-stringValue", "string-value")
.containsEntry("withUnwrapped.prefix-with-at-field-annotation", "@Field");
}
static class FlatDocument {
@ -538,22 +538,22 @@ public class MongoExampleMapperUnitTests { @@ -538,22 +538,22 @@ public class MongoExampleMapperUnitTests {
}
@Document
static class WrapperAroundWithEmbedded {
static class WrapperAroundWithUnwrapped {
String id;
WithEmbedded withEmbedded;
WithUnwrapped withUnwrapped;
}
@Document
static class WithEmbedded {
static class WithUnwrapped {
String id;
@Embedded.Nullable EmbeddableType embeddableType;
@Embedded.Nullable("prefix-") EmbeddableType prefixedEmbeddableValue;
@Unwrapped.Nullable UnwrappableType unwrappedValue;
@Unwrapped.Nullable("prefix-") UnwrappableType prefixedUnwrappedValue;
}
static class EmbeddableType {
static class UnwrappableType {
@Indexed String stringValue;

132
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java

@ -48,12 +48,12 @@ import org.springframework.data.mongodb.core.geo.GeoJsonPoint; @@ -48,12 +48,12 @@ import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.geo.GeoJsonPolygon;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Embedded;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.FieldType;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.TextScore;
import org.springframework.data.mongodb.core.mapping.Unwrapped;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
@ -1014,179 +1014,179 @@ public class QueryMapperUnitTests { @@ -1014,179 +1014,179 @@ public class QueryMapperUnitTests {
}
@Test // DATAMONGO-1902
void rendersQueryOnEmbeddedObjectCorrectly() {
void rendersQueryOnUnwrappedObjectCorrectly() {
EmbeddableType embeddableType = new EmbeddableType();
embeddableType.stringValue = "test";
UnwrappableType unwrappableType = new UnwrappableType();
unwrappableType.stringValue = "test";
Query source = query(Criteria.where("embeddableValue").is(embeddableType));
Query source = query(Criteria.where("unwrappedValue").is(unwrappableType));
org.bson.Document target = mapper.getMappedObject(source.getQueryObject(),
context.getPersistentEntity(WithEmbedded.class));
context.getPersistentEntity(WithUnwrapped.class));
assertThat(target).isEqualTo(new org.bson.Document("stringValue", "test"));
}
@Test // DATAMONGO-1902
void rendersQueryOnEmbeddedCorrectly() {
void rendersQueryOnUnwrappedCorrectly() {
Query source = query(Criteria.where("embeddableValue.stringValue").is("test"));
Query source = query(Criteria.where("unwrappedValue.stringValue").is("test"));
org.bson.Document target = mapper.getMappedObject(source.getQueryObject(),
context.getPersistentEntity(WithEmbedded.class));
context.getPersistentEntity(WithUnwrapped.class));
assertThat(target).isEqualTo(new org.bson.Document("stringValue", "test"));
}
@Test // DATAMONGO-1902
void rendersQueryOnPrefixedEmbeddedCorrectly() {
void rendersQueryOnPrefixedUnwrappedCorrectly() {
Query source = query(Criteria.where("embeddableValue.stringValue").is("test"));
Query source = query(Criteria.where("unwrappedValue.stringValue").is("test"));
org.bson.Document target = mapper.getMappedObject(source.getQueryObject(),
context.getPersistentEntity(WithPrefixedEmbedded.class));
context.getPersistentEntity(WithPrefixedUnwrapped.class));
assertThat(target).isEqualTo(new org.bson.Document("prefix-stringValue", "test"));
}
@Test // DATAMONGO-1902
void rendersQueryOnNestedEmbeddedObjectCorrectly() {
void rendersQueryOnNestedUnwrappedObjectCorrectly() {
EmbeddableType embeddableType = new EmbeddableType();
embeddableType.stringValue = "test";
Query source = query(Criteria.where("withEmbedded.embeddableValue").is(embeddableType));
UnwrappableType unwrappableType = new UnwrappableType();
unwrappableType.stringValue = "test";
Query source = query(Criteria.where("withUnwrapped.unwrappedValue").is(unwrappableType));
org.bson.Document target = mapper.getMappedObject(source.getQueryObject(),
context.getPersistentEntity(WrapperAroundWithEmbedded.class));
context.getPersistentEntity(WrapperAroundWithUnwrapped.class));
assertThat(target).isEqualTo(new org.bson.Document("withEmbedded", new org.bson.Document("stringValue", "test")));
assertThat(target).isEqualTo(new org.bson.Document("withUnwrapped", new org.bson.Document("stringValue", "test")));
}
@Test // DATAMONGO-1902
void rendersQueryOnNestedPrefixedEmbeddedObjectCorrectly() {
void rendersQueryOnNestedPrefixedUnwrappedObjectCorrectly() {
EmbeddableType embeddableType = new EmbeddableType();
embeddableType.stringValue = "test";
Query source = query(Criteria.where("withPrefixedEmbedded.embeddableValue").is(embeddableType));
UnwrappableType unwrappableType = new UnwrappableType();
unwrappableType.stringValue = "test";
Query source = query(Criteria.where("withPrefixedUnwrapped.unwrappedValue").is(unwrappableType));
org.bson.Document target = mapper.getMappedObject(source.getQueryObject(),
context.getPersistentEntity(WrapperAroundWithEmbedded.class));
context.getPersistentEntity(WrapperAroundWithUnwrapped.class));
assertThat(target)
.isEqualTo(new org.bson.Document("withPrefixedEmbedded", new org.bson.Document("prefix-stringValue", "test")));
.isEqualTo(new org.bson.Document("withPrefixedUnwrapped", new org.bson.Document("prefix-stringValue", "test")));
}
@Test // DATAMONGO-1902
void rendersQueryOnNestedEmbeddedCorrectly() {
void rendersQueryOnNestedUnwrappedCorrectly() {
Query source = query(Criteria.where("withEmbedded.embeddableValue.stringValue").is("test"));
Query source = query(Criteria.where("withUnwrapped.unwrappedValue.stringValue").is("test"));
org.bson.Document target = mapper.getMappedObject(source.getQueryObject(),
context.getPersistentEntity(WrapperAroundWithEmbedded.class));
context.getPersistentEntity(WrapperAroundWithUnwrapped.class));
assertThat(target).isEqualTo(new org.bson.Document("withEmbedded.stringValue", "test"));
assertThat(target).isEqualTo(new org.bson.Document("withUnwrapped.stringValue", "test"));
}
@Test // DATAMONGO-1902
void rendersQueryOnNestedPrefixedEmbeddedCorrectly() {
void rendersQueryOnNestedPrefixedUnwrappedCorrectly() {
Query source = query(Criteria.where("withPrefixedEmbedded.embeddableValue.stringValue").is("test"));
Query source = query(Criteria.where("withPrefixedUnwrapped.unwrappedValue.stringValue").is("test"));
org.bson.Document target = mapper.getMappedObject(source.getQueryObject(),
context.getPersistentEntity(WrapperAroundWithEmbedded.class));
context.getPersistentEntity(WrapperAroundWithUnwrapped.class));
assertThat(target).isEqualTo(new org.bson.Document("withPrefixedEmbedded.prefix-stringValue", "test"));
assertThat(target).isEqualTo(new org.bson.Document("withPrefixedUnwrapped.prefix-stringValue", "test"));
}
@Test // DATAMONGO-1902
void sortByEmbeddableIsEmpty() {
void sortByUnwrappedIsEmpty() {
Query query = new Query().with(Sort.by("embeddableValue"));
Query query = new Query().with(Sort.by("unwrappedValue"));
org.bson.Document document = mapper.getMappedSort(query.getSortObject(),
context.getPersistentEntity(WithEmbedded.class));
context.getPersistentEntity(WithUnwrapped.class));
assertThat(document).isEqualTo(
new org.bson.Document("stringValue", 1).append("listValue", 1).append("with-at-field-annotation", 1));
}
@Test // DATAMONGO-1902
void sortByEmbeddableValue() {
void sortByUnwrappedValue() {
// atFieldAnnotatedValue
Query query = new Query().with(Sort.by("embeddableValue.stringValue"));
Query query = new Query().with(Sort.by("unwrappedValue.stringValue"));
org.bson.Document document = mapper.getMappedSort(query.getSortObject(),
context.getPersistentEntity(WithEmbedded.class));
context.getPersistentEntity(WithUnwrapped.class));
assertThat(document).isEqualTo(new org.bson.Document("stringValue", 1));
}
@Test // DATAMONGO-1902
void sortByEmbeddableValueWithFieldAnnotation() {
void sortByUnwrappedValueWithFieldAnnotation() {
Query query = new Query().with(Sort.by("embeddableValue.atFieldAnnotatedValue"));
Query query = new Query().with(Sort.by("unwrappedValue.atFieldAnnotatedValue"));
org.bson.Document document = mapper.getMappedSort(query.getSortObject(),
context.getPersistentEntity(WithEmbedded.class));
context.getPersistentEntity(WithUnwrapped.class));
assertThat(document).isEqualTo(new org.bson.Document("with-at-field-annotation", 1));
}
@Test // DATAMONGO-1902
void sortByPrefixedEmbeddableValueWithFieldAnnotation() {
void sortByPrefixedUnwrappedValueWithFieldAnnotation() {
Query query = new Query().with(Sort.by("embeddableValue.atFieldAnnotatedValue"));
Query query = new Query().with(Sort.by("unwrappedValue.atFieldAnnotatedValue"));
org.bson.Document document = mapper.getMappedSort(query.getSortObject(),
context.getPersistentEntity(WithPrefixedEmbedded.class));
context.getPersistentEntity(WithPrefixedUnwrapped.class));
assertThat(document).isEqualTo(new org.bson.Document("prefix-with-at-field-annotation", 1));
}
@Test // DATAMONGO-1902
void sortByNestedEmbeddableValueWithFieldAnnotation() {
void sortByNestedUnwrappedValueWithFieldAnnotation() {
Query query = new Query().with(Sort.by("withEmbedded.embeddableValue.atFieldAnnotatedValue"));
Query query = new Query().with(Sort.by("withUnwrapped.unwrappedValue.atFieldAnnotatedValue"));
org.bson.Document document = mapper.getMappedSort(query.getSortObject(),
context.getPersistentEntity(WrapperAroundWithEmbedded.class));
context.getPersistentEntity(WrapperAroundWithUnwrapped.class));
assertThat(document).isEqualTo(new org.bson.Document("withEmbedded.with-at-field-annotation", 1));
assertThat(document).isEqualTo(new org.bson.Document("withUnwrapped.with-at-field-annotation", 1));
}
@Test // DATAMONGO-1902
void sortByNestedPrefixedEmbeddableValueWithFieldAnnotation() {
void sortByNestedPrefixedUnwrappedValueWithFieldAnnotation() {
Query query = new Query().with(Sort.by("withPrefixedEmbedded.embeddableValue.atFieldAnnotatedValue"));
Query query = new Query().with(Sort.by("withPrefixedUnwrapped.unwrappedValue.atFieldAnnotatedValue"));
org.bson.Document document = mapper.getMappedSort(query.getSortObject(),
context.getPersistentEntity(WrapperAroundWithEmbedded.class));
context.getPersistentEntity(WrapperAroundWithUnwrapped.class));
assertThat(document).isEqualTo(new org.bson.Document("withPrefixedEmbedded.prefix-with-at-field-annotation", 1));
assertThat(document).isEqualTo(new org.bson.Document("withPrefixedUnwrapped.prefix-with-at-field-annotation", 1));
}
@Test // DATAMONGO-1902
void projectOnEmbeddableUsesFields() {
void projectOnUnwrappedUsesFields() {
Query query = new Query();
query.fields().include("embeddableValue");
query.fields().include("unwrappedValue");
org.bson.Document document = mapper.getMappedFields(query.getFieldsObject(),
context.getPersistentEntity(WithEmbedded.class));
context.getPersistentEntity(WithUnwrapped.class));
assertThat(document).isEqualTo(
new org.bson.Document("stringValue", 1).append("listValue", 1).append("with-at-field-annotation", 1));
}
@Test // DATAMONGO-1902
void projectOnEmbeddableValue() {
void projectOnUnwrappedValue() {
Query query = new Query();
query.fields().include("embeddableValue.stringValue");
query.fields().include("unwrappedValue.stringValue");
org.bson.Document document = mapper.getMappedFields(query.getFieldsObject(),
context.getPersistentEntity(WithEmbedded.class));
context.getPersistentEntity(WithUnwrapped.class));
assertThat(document).isEqualTo(new org.bson.Document("stringValue", 1));
}
@ -1375,28 +1375,28 @@ public class QueryMapperUnitTests { @@ -1375,28 +1375,28 @@ public class QueryMapperUnitTests {
}
}
static class WrapperAroundWithEmbedded {
static class WrapperAroundWithUnwrapped {
String someValue;
WithEmbedded withEmbedded;
WithPrefixedEmbedded withPrefixedEmbedded;
WithUnwrapped withUnwrapped;
WithPrefixedUnwrapped withPrefixedUnwrapped;
}
static class WithEmbedded {
static class WithUnwrapped {
String id;
@Embedded.Nullable EmbeddableType embeddableValue;
@Unwrapped.Nullable UnwrappableType unwrappedValue;
}
static class WithPrefixedEmbedded {
static class WithPrefixedUnwrapped {
String id;
@Embedded.Nullable("prefix-") EmbeddableType embeddableValue;
@Unwrapped.Nullable("prefix-") UnwrappableType unwrappedValue;
}
static class EmbeddableType {
static class UnwrappableType {
String stringValue;
List<String> listValue;

74
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java

@ -48,9 +48,9 @@ import org.springframework.data.domain.Sort.Order; @@ -48,9 +48,9 @@ import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mapping.MappingException;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.DocumentTestUtils;
import org.springframework.data.mongodb.core.mapping.Embedded;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.Unwrapped;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
@ -1091,71 +1091,71 @@ class UpdateMapperUnitTests { @@ -1091,71 +1091,71 @@ class UpdateMapperUnitTests {
}
@Test // DATAMONGO-1902
void mappingShouldConsiderValueOfEmbeddedType() {
void mappingShouldConsiderValueOfUnwrappedType() {
Update update = new Update().set("embeddableValue.stringValue", "updated");
Update update = new Update().set("unwrappedValue.stringValue", "updated");
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
context.getPersistentEntity(WithEmbedded.class));
context.getPersistentEntity(WithUnwrapped.class));
assertThat(mappedUpdate).isEqualTo(new Document("$set", new Document("stringValue", "updated")));
}
@Test // DATAMONGO-1902
void mappingShouldConsiderEmbeddedType() {
void mappingShouldConsiderUnwrappedType() {
EmbeddableType embeddableType = new EmbeddableType();
embeddableType.stringValue = "updated";
embeddableType.listValue = Arrays.asList("val-1", "val-2");
Update update = new Update().set("embeddableValue", embeddableType);
UnwrappableType unwrappableType = new UnwrappableType();
unwrappableType.stringValue = "updated";
unwrappableType.listValue = Arrays.asList("val-1", "val-2");
Update update = new Update().set("unwrappedValue", unwrappableType);
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
context.getPersistentEntity(WithEmbedded.class));
context.getPersistentEntity(WithUnwrapped.class));
assertThat(mappedUpdate).isEqualTo(new Document("$set",
new Document("stringValue", "updated").append("listValue", Arrays.asList("val-1", "val-2"))));
}
@Test // DATAMONGO-1902
void mappingShouldConsiderValueOfPrefixedEmbeddedType() {
void mappingShouldConsiderValueOfPrefixedUnwrappedType() {
Update update = new Update().set("embeddableValue.stringValue", "updated");
Update update = new Update().set("unwrappedValue.stringValue", "updated");
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
context.getPersistentEntity(WithPrefixedEmbedded.class));
context.getPersistentEntity(WithPrefixedUnwrapped.class));
assertThat(mappedUpdate).isEqualTo(new Document("$set", new Document("prefix-stringValue", "updated")));
}
@Test // DATAMONGO-1902
void mappingShouldConsiderPrefixedEmbeddedType() {
void mappingShouldConsiderPrefixedUnwrappedType() {
EmbeddableType embeddableType = new EmbeddableType();
embeddableType.stringValue = "updated";
embeddableType.listValue = Arrays.asList("val-1", "val-2");
UnwrappableType unwrappableType = new UnwrappableType();
unwrappableType.stringValue = "updated";
unwrappableType.listValue = Arrays.asList("val-1", "val-2");
Update update = new Update().set("embeddableValue", embeddableType);
Update update = new Update().set("unwrappedValue", unwrappableType);
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
context.getPersistentEntity(WithPrefixedEmbedded.class));
context.getPersistentEntity(WithPrefixedUnwrapped.class));
assertThat(mappedUpdate).isEqualTo(new Document("$set",
new Document("prefix-stringValue", "updated").append("prefix-listValue", Arrays.asList("val-1", "val-2"))));
}
@Test // DATAMONGO-1902
void mappingShouldConsiderNestedPrefixedEmbeddedType() {
void mappingShouldConsiderNestedPrefixedUnwrappedType() {
EmbeddableType embeddableType = new EmbeddableType();
embeddableType.stringValue = "updated";
embeddableType.listValue = Arrays.asList("val-1", "val-2");
UnwrappableType unwrappableType = new UnwrappableType();
unwrappableType.stringValue = "updated";
unwrappableType.listValue = Arrays.asList("val-1", "val-2");
Update update = new Update().set("withPrefixedEmbedded.embeddableValue", embeddableType);
Update update = new Update().set("withPrefixedUnwrapped.unwrappedValue", unwrappableType);
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
context.getPersistentEntity(WrapperAroundWithEmbedded.class));
context.getPersistentEntity(WrapperAroundWithUnwrapped.class));
assertThat(mappedUpdate).isEqualTo(new Document("$set", new Document("withPrefixedEmbedded",
assertThat(mappedUpdate).isEqualTo(new Document("$set", new Document("withPrefixedUnwrapped",
new Document("prefix-stringValue", "updated").append("prefix-listValue", Arrays.asList("val-1", "val-2")))));
}
@ -1176,8 +1176,7 @@ class UpdateMapperUnitTests { @@ -1176,8 +1176,7 @@ class UpdateMapperUnitTests {
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
context.getPersistentEntity(EntityWithObjectMap.class));
assertThat(mappedUpdate)
.isEqualTo("{\"$set\": {\"map.601218778970110001827396.value\": \"testing\"}}");
assertThat(mappedUpdate).isEqualTo("{\"$set\": {\"map.601218778970110001827396.value\": \"testing\"}}");
}
@Test // GH-3566
@ -1187,8 +1186,7 @@ class UpdateMapperUnitTests { @@ -1187,8 +1186,7 @@ class UpdateMapperUnitTests {
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
context.getPersistentEntity(EntityWithObjectMap.class));
assertThat(mappedUpdate)
.isEqualTo("{\"$set\": {\"map.class\": \"value\"}}");
assertThat(mappedUpdate).isEqualTo("{\"$set\": {\"map.class\": \"value\"}}");
}
static class DomainTypeWrappingConcreteyTypeHavingListOfInterfaceTypeAttributes {
@ -1520,28 +1518,28 @@ class UpdateMapperUnitTests { @@ -1520,28 +1518,28 @@ class UpdateMapperUnitTests {
}
static class WrapperAroundWithEmbedded {
static class WrapperAroundWithUnwrapped {
String someValue;
WithEmbedded withEmbedded;
WithPrefixedEmbedded withPrefixedEmbedded;
WithUnwrapped withUnwrapped;
WithPrefixedUnwrapped withPrefixedUnwrapped;
}
static class WithEmbedded {
static class WithUnwrapped {
String id;
@Embedded.Nullable EmbeddableType embeddableValue;
@Unwrapped.Nullable UnwrappableType unwrappedValue;
}
static class WithPrefixedEmbedded {
static class WithPrefixedUnwrapped {
String id;
@Embedded.Nullable("prefix-") EmbeddableType embeddableValue;
@Unwrapped.Nullable("prefix-") UnwrappableType unwrappedValue;
}
static class EmbeddableType {
static class UnwrappableType {
String stringValue;
List<String> listValue;

30
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java

@ -44,12 +44,12 @@ import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexRes @@ -44,12 +44,12 @@ import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexRes
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Embedded;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.Language;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.Unwrapped;
import org.springframework.data.util.ClassTypeInformation;
/**
@ -1286,10 +1286,10 @@ public class MongoPersistentEntityIndexResolverUnitTests { @@ -1286,10 +1286,10 @@ public class MongoPersistentEntityIndexResolverUnitTests {
}
@Test // DATAMONGO-1902
public void resolvedIndexOnEmbeddedType() {
public void resolvedIndexOnUnwrappedType() {
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(WithEmbedded.class,
EmbeddableType.class);
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(WithUnwrapped.class,
UnwrappableType.class);
assertThat(indexDefinitions).hasSize(2);
assertThat(indexDefinitions.get(0)).satisfies(it -> {
@ -1301,10 +1301,10 @@ public class MongoPersistentEntityIndexResolverUnitTests { @@ -1301,10 +1301,10 @@ public class MongoPersistentEntityIndexResolverUnitTests {
}
@Test // DATAMONGO-1902
public void resolvedIndexOnNestedEmbeddedType() {
public void resolvedIndexOnNestedUnwrappedType() {
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(
WrapperAroundWithEmbedded.class, WithEmbedded.class, EmbeddableType.class);
WrapperAroundWithUnwrapped.class, WithUnwrapped.class, UnwrappableType.class);
assertThat(indexDefinitions).hasSize(2);
assertThat(indexDefinitions.get(0)).satisfies(it -> {
@ -1319,7 +1319,7 @@ public class MongoPersistentEntityIndexResolverUnitTests { @@ -1319,7 +1319,7 @@ public class MongoPersistentEntityIndexResolverUnitTests {
public void errorsOnIndexOnEmbedded() {
assertThatExceptionOfType(InvalidDataAccessApiUsageException.class)
.isThrownBy(() -> prepareMappingContextAndResolveIndexForType(InvalidIndexOnEmbedded.class));
.isThrownBy(() -> prepareMappingContextAndResolveIndexForType(InvalidIndexOnUnwrapped.class));
}
@ -1514,30 +1514,30 @@ public class MongoPersistentEntityIndexResolverUnitTests { @@ -1514,30 +1514,30 @@ public class MongoPersistentEntityIndexResolverUnitTests {
}
@Document
static class WrapperAroundWithEmbedded {
static class WrapperAroundWithUnwrapped {
String id;
WithEmbedded withEmbedded;
WithUnwrapped withEmbedded;
}
@Document
static class WithEmbedded {
static class WithUnwrapped {
String id;
@Embedded.Nullable EmbeddableType embeddableType;
@Unwrapped.Nullable UnwrappableType unwrappableType;
}
@Document
class InvalidIndexOnEmbedded {
class InvalidIndexOnUnwrapped {
@Indexed //
@Embedded.Nullable //
EmbeddableType embeddableType;
@Unwrapped.Nullable //
UnwrappableType unwrappableType;
}
static class EmbeddableType {
static class UnwrappableType {
@Indexed String stringValue;

12
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java

@ -1366,34 +1366,34 @@ public abstract class AbstractPersonRepositoryIntegrationTests { @@ -1366,34 +1366,34 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
}
@Test // DATAMONGO-1902
void findByValueInsideEmbedded() {
void findByValueInsideUnwrapped() {
Person bart = new Person("bart", "simpson");
User user = new User();
user.setUsername("bartman");
user.setId("84r1m4n");
bart.setEmbeddedUser(user);
bart.setUnwrappedUser(user);
operations.save(bart);
List<Person> result = repository.findByEmbeddedUserUsername(user.getUsername());
List<Person> result = repository.findByUnwrappedUserUsername(user.getUsername());
assertThat(result).hasSize(1);
assertThat(result.get(0).getId().equals(bart.getId()));
}
@Test // DATAMONGO-1902
void findByEmbedded() {
void findByUnwrapped() {
Person bart = new Person("bart", "simpson");
User user = new User();
user.setUsername("bartman");
user.setId("84r1m4n");
bart.setEmbeddedUser(user);
bart.setUnwrappedUser(user);
operations.save(bart);
List<Person> result = repository.findByEmbeddedUser(user);
List<Person> result = repository.findByUnwrappedUser(user);
assertThat(result).hasSize(1);
assertThat(result.get(0).getId().equals(bart.getId()));

14
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/Person.java

@ -27,8 +27,8 @@ import org.springframework.data.mongodb.core.index.GeoSpatialIndexed; @@ -27,8 +27,8 @@ import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Embedded;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.Unwrapped;
/**
* Sample domain class.
@ -71,8 +71,8 @@ public class Person extends Contact { @@ -71,8 +71,8 @@ public class Person extends Contact {
Credentials credentials;
@Embedded.Nullable(prefix = "u") //
User embeddedUser;
@Unwrapped.Nullable(prefix = "u") //
User unwrappedUser;
public Person() {
@ -300,12 +300,12 @@ public class Person extends Contact { @@ -300,12 +300,12 @@ public class Person extends Contact {
return skills;
}
public User getEmbeddedUser() {
return embeddedUser;
public User getUnwrappedUser() {
return unwrappedUser;
}
public void setEmbeddedUser(User embeddedUser) {
this.embeddedUser = embeddedUser;
public void setUnwrappedUser(User unwrappedUser) {
this.unwrappedUser = unwrappedUser;
}
/*

4
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java

@ -407,7 +407,7 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query @@ -407,7 +407,7 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
Date createdAt, List<String> skills, String street, String zipCode, //
String city, UUID uniqueId, String username, String password);
List<Person> findByEmbeddedUserUsername(String username);
List<Person> findByUnwrappedUserUsername(String username);
List<Person> findByEmbeddedUser(User user);
List<Person> findByUnwrappedUser(User user);
}

2
src/main/asciidoc/new-features.adoc

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
[[new-features.3.2]]
== What's New in Spring Data MongoDB 3.2
* Support for <<embedded-entities,Embedded Types>> to unwrap nested objects into the parent `Document`.
* Support for <<unwrapped-entities,unwrapping>> nested objects into the parent `Document`.
* <<mongo-template.querying.field-selection,Support expressions to define field projections>>.
[[new-features.3.1]]

2
src/main/asciidoc/reference/mapping.adoc

@ -833,6 +833,6 @@ Events are fired throughout the lifecycle of the mapping process. This is descri @@ -833,6 +833,6 @@ Events are fired throughout the lifecycle of the mapping process. This is descri
Declaring these beans in your Spring ApplicationContext causes them to be invoked whenever the event is dispatched.
include::embedded-documents.adoc[]
include::unwrapping-entities.adoc[]
include::mongo-custom-conversions.adoc[]

140
src/main/asciidoc/reference/embedded-documents.adoc → src/main/asciidoc/reference/unwrapping-entities.adoc

@ -1,15 +1,15 @@ @@ -1,15 +1,15 @@
[[embedded-entities]]
== Embedded Types
[[unwrapped-entities]]
== Unwrapping Types
Embedded entities are used to design value objects in your Java domain model whose properties are flattened out into the parent's MongoDB Document.
Unwrapped entities are used to design value objects in your Java domain model whose properties are flattened out into the parent's MongoDB Document.
[[embedded-entities.mapping]]
=== Embedded Types Mapping
[[unwrapped-entities.mapping]]
=== Unwrapped Types Mapping
Consider the following domain model where `User.name` is annotated with `@Embedded`.
The `@Embedded` annotation signals that all properties of `UserName` should be unwrapped into the `user` document that owns the `name` property.
Consider the following domain model where `User.name` is annotated with `@Unwrapped`.
The `@Unwrapped` annotation signals that all properties of `UserName` should be flattened out into the `user` document that owns the `name` property.
.Sample Code of embedding objects
.Sample Code of unwrapping objects
====
[source,java]
----
@ -18,7 +18,7 @@ class User { @@ -18,7 +18,7 @@ class User {
@Id
String userId;
@Embedded(onEmpty = USE_NULL) <1>
@Unwrapped(onEmpty = USE_NULL) <1>
UserName name;
}
@ -43,23 +43,23 @@ class UserName { @@ -43,23 +43,23 @@ class UserName {
By using `onEmpty=USE_EMPTY` an empty `UserName`, with potential `null` value for its properties, will be created.
====
For less verbose embeddable type declarations use `@Embedded.Nullable` and `@Embedded.Empty` instead `@Embedded(onEmpty = USE_NULL)` and `@Embedded(onEmpty = USE_EMPTY)`.
For less verbose embeddable type declarations use `@Unwrapped.Nullable` and `@Unwrapped.Empty` instead `@Unwrapped(onEmpty = USE_NULL)` and `@Unwrapped(onEmpty = USE_EMPTY)`.
Both annotations are meta-annotated with JSR-305 `@javax.annotation.Nonnull` to aid with nullability inspections.
[WARNING]
====
It is possible to use complex types within an embedded object.
However, those must not be, nor contain embedded fields themselves.
It is possible to use complex types within an unwrapped object.
However, those must not be, nor contain unwrapped fields themselves.
====
[[embedded-entities.mapping.field-names]]
=== Embedded Types field names
[[unwrapped-entities.mapping.field-names]]
=== Unwrapped Types field names
A value object can be embedded multiple times by using the optional `prefix` attribute of the `@Embedded` annotation.
By dosing so the chosen prefix is prepended to each property or `@Field("…")` name in the embedded object.
A value object can be unwrapped multiple times by using the optional `prefix` attribute of the `@Unwrapped` annotation.
By dosing so the chosen prefix is prepended to each property or `@Field("…")` name in the unwrapped object.
Please note that values will overwrite each other if multiple properties render to the same field name.
.Sample Code of embedded object with name prefix
.Sample Code of unwrapped object with name prefix
====
[source,java]
----
@ -68,10 +68,10 @@ class User { @@ -68,10 +68,10 @@ class User {
@Id
String userId;
@Embedded.Nullable(prefix = "u_") <1>
@Unwrapped.Nullable(prefix = "u_") <1>
UserName name;
@Embedded.Nullable(prefix = "a_") <2>
@Unwrapped.Nullable(prefix = "a_") <2>
UserName name;
}
@ -97,10 +97,10 @@ class UserName { @@ -97,10 +97,10 @@ class UserName {
<2> All properties of `UserName` are prefixed with `a_`.
====
While combining the `@Field` annotation with `@Embedded` on the very same property does not make sense and therefore leads to an error.
It is a totally valid approach to use `@Field` on any of the embedded types properties.
While combining the `@Field` annotation with `@Unwrapped` on the very same property does not make sense and therefore leads to an error.
It is a totally valid approach to use `@Field` on any of the unwrapped types properties.
.Sample Code embedded object with `@Field` annotation
.Sample Code unwrapping objects with `@Field` annotation
====
[source,java]
----
@ -109,7 +109,7 @@ public class User { @@ -109,7 +109,7 @@ public class User {
@Id
private String userId;
@Embedded.Nullable(prefix = "u-") <1>
@Unwrapped.Nullable(prefix = "u-") <1>
UserName name;
}
@ -132,17 +132,17 @@ public class UserName { @@ -132,17 +132,17 @@ public class UserName {
}
----
<1> All properties of `UserName` are prefixed with `u-`.
<2> Final field names are a result of concatenating `@Embedded(prefix)` and `@Field(name)`.
<2> Final field names are a result of concatenating `@Unwrapped(prefix)` and `@Field(name)`.
====
[[embedded-entities.queries]]
=== Query on Embedded Objects
[[unwrapped-entities.queries]]
=== Query on Unwrapped Objects
Defining queries on embedded properties is possible on type- as well as field-level as the provided `Criteria` is matched against the domain type.
Defining queries on unwrapped properties is possible on type- as well as field-level as the provided `Criteria` is matched against the domain type.
Prefixes and potential custom field names will be considered when rendering the actual query.
Use the property name of the embedded object to match against all contained fields as shown in the sample below.
Use the property name of the unwrapped object to match against all contained fields as shown in the sample below.
.Query on embedded object
.Query on unwrapped object
====
[source,java]
----
@ -160,9 +160,9 @@ db.collection.find({ @@ -160,9 +160,9 @@ db.collection.find({
----
====
It is also possible to address any field of the embedded object directly using its property name as shown in the snippet below.
It is also possible to address any field of the unwrapped object directly using its property name as shown in the snippet below.
.Query on field of embedded object
.Query on field of unwrapped object
====
[source,java]
----
@ -178,12 +178,12 @@ db.collection.find({ @@ -178,12 +178,12 @@ db.collection.find({
----
====
[[embedded-entities.queries.sort]]
==== Sort by embedded field.
[[unwrapped-entities.queries.sort]]
==== Sort by unwrapped field.
Fields of embedded objects can be used for sorting via their property path as shown in the sample below.
Fields of unwrapped objects can be used for sorting via their property path as shown in the sample below.
.Sort on embedded field
.Sort on unwrapped field
====
[source,java]
----
@ -201,15 +201,15 @@ db.collection.find({ @@ -201,15 +201,15 @@ db.collection.find({
[NOTE]
====
Though possible, using the embedded object itself as sort criteria includes all of its fields in unpredictable order and may result in inaccurate ordering.
Though possible, using the unwrapped object itself as sort criteria includes all of its fields in unpredictable order and may result in inaccurate ordering.
====
[[embedded-entities.queries.project]]
==== Field projection on embedded objects
[[unwrapped-entities.queries.project]]
==== Field projection on unwrapped objects
Fields of embedded objects can be subject for projection either as a whole or via single fields as shown in the samples below.
Fields of unwrapped objects can be subject for projection either as a whole or via single fields as shown in the samples below.
.Project on embedded object.
.Project on unwrapped object.
====
[source,java]
----
@ -228,10 +228,10 @@ db.collection.find({ @@ -228,10 +228,10 @@ db.collection.find({
"lastname" : 1
})
----
<1> A field projection on an embedded object includes all of its properties.
<1> A field projection on an unwrapped object includes all of its properties.
====
.Project on a field of an embedded object.
.Project on a field of an unwrapped object.
====
[source,java]
----
@ -249,21 +249,21 @@ db.collection.find({ @@ -249,21 +249,21 @@ db.collection.find({
"firstname" : 1
})
----
<1> A field projection on an embedded object includes all of its properties.
<1> A field projection on an unwrapped object includes all of its properties.
====
[[embedded-entities.queries.by-example]]
==== Query By Example on embedded object.
[[unwrapped-entities.queries.by-example]]
==== Query By Example on unwrapped object.
Embedded objects can be used within an `Example` probe just as any other type.
Unwrapped objects can be used within an `Example` probe just as any other type.
Please review the <<query-by-example.running,Query By Example>> section, to learn more about this feature.
[[embedded-entities.queries.repository]]
==== Repository Queries on embedded objects.
[[unwrapped-entities.queries.repository]]
==== Repository Queries on unwrapped objects.
The `Repository` abstraction allows deriving queries on fields of embedded objects as well as the entire object.
The `Repository` abstraction allows deriving queries on fields of unwrapped objects as well as the entire object.
.Repository queries on embedded objects.
.Repository queries on unwrapped objects.
====
[source,java]
----
@ -274,23 +274,23 @@ interface UserRepository extends CrudRepository<User, String> { @@ -274,23 +274,23 @@ interface UserRepository extends CrudRepository<User, String> {
List<User> findByNameFirstname(String firstname); <2>
}
----
<1> Matches against all fields of the embedded object.
<1> Matches against all fields of the unwrapped object.
<2> Matches against the `firstname`.
====
[NOTE]
====
Index creation for embedded objects is suspended even if the repository `create-query-indexes` namespace attribute is set to `true`.
Index creation for unwrapped objects is suspended even if the repository `create-query-indexes` namespace attribute is set to `true`.
====
[[embedded-entities.update]]
=== Update on Embedded Objects
[[unwrapped-entities.update]]
=== Update on Unwrapped Objects
Embedded objects can be updated as any other object that is part of the domain model.
The mapping layer takes care of flattening embedded structures into their surroundings.
It is possible to update single attributes of the embedded object as well as the entire value as shown in the examples below.
Unwrapped objects can be updated as any other object that is part of the domain model.
The mapping layer takes care of flattening structures into their surroundings.
It is possible to update single attributes of the unwrapped object as well as the entire value as shown in the examples below.
.Update a single field of an embedded object.
.Update a single field of an unwrapped object.
====
[source,java]
----
@ -312,7 +312,7 @@ db.collection.update({ @@ -312,7 +312,7 @@ db.collection.update({
----
====
.Update an embedded object.
.Update an unwrapped object.
====
[source,java]
----
@ -337,18 +337,18 @@ db.collection.update({ @@ -337,18 +337,18 @@ db.collection.update({
----
====
[[embedded-entities.aggregations]]
=== Aggregations on Embedded Objects
[[unwrapped-entities.aggregations]]
=== Aggregations on Unwrapped Objects
The <<mongo.aggregation,Aggregation Framework>> will attempt to map embedded values of typed aggregations.
Please make sure to work with the property path including the embedded wrapper object when referencing one of its values.
The <<mongo.aggregation,Aggregation Framework>> will attempt to map unwrapped values of typed aggregations.
Please make sure to work with the property path including the wrapper object when referencing one of its values.
Other than that no special action is required.
[[embedded-entities.indexes]]
=== Index on Embedded Objects
[[unwrapped-entities.indexes]]
=== Index on Unwrapped Objects
It is possible to attach the `@Indexed` annotation to properties of an embedded type just as it is done with regular objects.
It is not possible to use `@Indexed` along with the `@Embedded` annotation on the owning property.
It is possible to attach the `@Indexed` annotation to properties of an unwrapped type just as it is done with regular objects.
It is not possible to use `@Indexed` along with the `@Unwrapped` annotation on the owning property.
====
[source,java]
@ -358,12 +358,12 @@ public class User { @@ -358,12 +358,12 @@ public class User {
@Id
private String userId;
@Embedded(onEmpty = USE_NULL)
@Unwrapped(onEmpty = USE_NULL)
UserName name; <1>
// Invalid -> InvalidDataAccessApiUsageException
@Indexed <2>
@Embedded(onEmpty = USE_Empty)
@Unwrapped(onEmpty = USE_Empty)
Address address;
}
@ -376,7 +376,7 @@ public class UserName { @@ -376,7 +376,7 @@ public class UserName {
}
----
<1> Index created for `lastname` in `users` collection.
<2> Invalid `@Indexed` usage along with `@Embedded`
<2> Invalid `@Indexed` usage along with `@Unwrapped`
====
Loading…
Cancel
Save