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.
This commit is contained in:
committed by
Mark Paluch
parent
f4556406bd
commit
5a87dec2d5
@@ -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
|
||||
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
|
||||
}
|
||||
|
||||
@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
|
||||
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));
|
||||
|
||||
@@ -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 {
|
||||
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 {
|
||||
|
||||
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 {
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
.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 {
|
||||
@Nullable
|
||||
protected Object delegateConvertToMongoType(Object source, @Nullable MongoPersistentEntity<?> entity) {
|
||||
|
||||
if (entity != null && entity.isEmbedded()) {
|
||||
if (entity != null && entity.isUnwrapped()) {
|
||||
return converter.convertToMongoType(source, entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
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 {
|
||||
|
||||
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)) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
* @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 "";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@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 {
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for a nullable embedded property.
|
||||
* Shortcut for a nullable unwrapped property.
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Embedded.Nullable private Address address;
|
||||
* @Unwrapped.Nullable private Address address;
|
||||
* </pre>
|
||||
*
|
||||
* as alternative to the more verbose
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Embedded(onEmpty = USE_NULL) @javax.annotation.Nonnull(when = When.MAYBE) private Address address;
|
||||
* @Unwrapped(onEmpty = USE_NULL) @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 {
|
||||
@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">
|
||||
* @Embedded.Empty private Address address;
|
||||
* @Unwrapped.Empty private Address address;
|
||||
* </pre>
|
||||
*
|
||||
* as alternative to the more verbose
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Embedded(onEmpty = USE_EMPTY) @javax.annotation.Nonnull(when = When.NEVER) private Address address;
|
||||
* @Unwrapped(onEmpty = USE_EMPTY) @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 {
|
||||
@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 "";
|
||||
}
|
||||
}
|
||||
@@ -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> {
|
||||
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> {
|
||||
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> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmbedded() {
|
||||
return context.getProperty().isEmbedded();
|
||||
public boolean isUnwrapped() {
|
||||
return context.getProperty().isUnwrapped();
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
@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 {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmbedded() {
|
||||
return delegate.isEmbedded();
|
||||
public boolean isUnwrapped() {
|
||||
return delegate.isUnwrapped();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -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
|
||||
if (GEOSPATIAL_TYPES.contains(part.getType())) {
|
||||
return;
|
||||
}
|
||||
if (isIndexOnEmbeddedType(part)) {
|
||||
if (isIndexOnUnwrappedType(part)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
return false;
|
||||
}
|
||||
|
||||
return AnnotatedElementUtils.hasAnnotation(field, Embedded.class);
|
||||
return AnnotatedElementUtils.hasAnnotation(field, Unwrapped.class);
|
||||
}
|
||||
|
||||
private static Direction toDirection(Sort sort, String property) {
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@Test // GH-3583
|
||||
void mapsProjectionOnEmbedded() {
|
||||
void mapsProjectionOnUnwrapped() {
|
||||
|
||||
luke.address = new Address();
|
||||
luke.address.planet = "tatoine";
|
||||
@@ -164,7 +164,7 @@ class MongoTemplateFieldProjectionTests {
|
||||
@Field("last_name") //
|
||||
String lastname;
|
||||
|
||||
@Embedded.Nullable Address address;
|
||||
@Unwrapped.Nullable Address address;
|
||||
|
||||
Person toUpperCaseLastnameClone(Person source) {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
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 {
|
||||
|
||||
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;
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
assertThat(getPipelineElementFromAggregationAt(agg, 0).get("$project"))
|
||||
.isEqualTo(new Document("val", "$withEmbedded.with-at-field-annotation"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1902
|
||||
void rendersProjectOnNestedPrefixedEmbeddedFieldCorrectly() {
|
||||
|
||||
AggregationOperationContext context = getContext(WrapperAroundWithEmbedded.class);
|
||||
|
||||
Document agg = newAggregation(WrapperAroundWithEmbedded.class,
|
||||
project().and("withEmbedded.prefixedEmbeddableValue.stringValue").as("val")).toDocument("collection", context);
|
||||
|
||||
assertThat(getPipelineElementFromAggregationAt(agg, 0).get("$project"))
|
||||
.isEqualTo(new Document("val", "$withEmbedded.prefix-stringValue"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1902
|
||||
void rendersProjectOnNestedPrefixedEmbeddedFieldWithAtFieldAnnotationCorrectly() {
|
||||
|
||||
AggregationOperationContext context = getContext(WrapperAroundWithEmbedded.class);
|
||||
|
||||
Document agg = newAggregation(WrapperAroundWithEmbedded.class,
|
||||
project().and("withEmbedded.prefixedEmbeddableValue.atFieldAnnotatedValue").as("val")).toDocument("collection",
|
||||
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.prefix-with-at-field-annotation"));
|
||||
.isEqualTo(new Document("val", "$withUnwrapped.with-at-field-annotation"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1902
|
||||
void rendersProjectOnNestedPrefixedUnwrappedFieldCorrectly() {
|
||||
|
||||
AggregationOperationContext context = getContext(WrapperAroundWithUnwrapped.class);
|
||||
|
||||
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", "$withUnwrapped.prefix-stringValue"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1902
|
||||
void rendersProjectOnNestedPrefixedUnwrappedFieldWithAtFieldAnnotationCorrectly() {
|
||||
|
||||
AggregationOperationContext context = getContext(WrapperAroundWithUnwrapped.class);
|
||||
|
||||
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", "$withUnwrapped.prefix-with-at-field-annotation"));
|
||||
}
|
||||
|
||||
@org.springframework.data.mongodb.core.mapping.Document(collection = "person")
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
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 {
|
||||
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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
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
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
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 {
|
||||
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 {
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
public void errorsOnIndexOnEmbedded() {
|
||||
|
||||
assertThatExceptionOfType(InvalidDataAccessApiUsageException.class)
|
||||
.isThrownBy(() -> prepareMappingContextAndResolveIndexForType(InvalidIndexOnEmbedded.class));
|
||||
.isThrownBy(() -> prepareMappingContextAndResolveIndexForType(InvalidIndexOnUnwrapped.class));
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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 {
|
||||
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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]]
|
||||
|
||||
@@ -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[]
|
||||
|
||||
@@ -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 {
|
||||
@Id
|
||||
String userId;
|
||||
|
||||
@Embedded(onEmpty = USE_NULL) <1>
|
||||
@Unwrapped(onEmpty = USE_NULL) <1>
|
||||
UserName name;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
@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 {
|
||||
<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 {
|
||||
@Id
|
||||
private String userId;
|
||||
|
||||
@Embedded.Nullable(prefix = "u-") <1>
|
||||
@Unwrapped.Nullable(prefix = "u-") <1>
|
||||
UserName name;
|
||||
}
|
||||
|
||||
@@ -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({
|
||||
----
|
||||
====
|
||||
|
||||
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({
|
||||
----
|
||||
====
|
||||
|
||||
[[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({
|
||||
|
||||
[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({
|
||||
"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({
|
||||
"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> {
|
||||
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({
|
||||
----
|
||||
====
|
||||
|
||||
.Update an embedded object.
|
||||
.Update an unwrapped object.
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@@ -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 {
|
||||
@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 {
|
||||
}
|
||||
----
|
||||
<1> Index created for `lastname` in `users` collection.
|
||||
<2> Invalid `@Indexed` usage along with `@Embedded`
|
||||
<2> Invalid `@Indexed` usage along with `@Unwrapped`
|
||||
====
|
||||
|
||||
|
||||
Reference in New Issue
Block a user