diff --git a/pom.xml b/pom.xml index 74b7a38a74..50e5a08be3 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 1.8.0.BUILD-SNAPSHOT + 1.8.0.DATAMONGO-1269-SNAPSHOT pom Spring Data MongoDB diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index 7d18f752fc..a7491f916d 100644 --- a/spring-data-mongodb-cross-store/pom.xml +++ b/spring-data-mongodb-cross-store/pom.xml @@ -6,7 +6,7 @@ org.springframework.data spring-data-mongodb-parent - 1.8.0.BUILD-SNAPSHOT + 1.8.0.DATAMONGO-1269-SNAPSHOT ../pom.xml @@ -48,7 +48,7 @@ org.springframework.data spring-data-mongodb - 1.8.0.BUILD-SNAPSHOT + 1.8.0.DATAMONGO-1269-SNAPSHOT diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml index 13c0985a6a..ec3d3361fa 100644 --- a/spring-data-mongodb-distribution/pom.xml +++ b/spring-data-mongodb-distribution/pom.xml @@ -13,7 +13,7 @@ org.springframework.data spring-data-mongodb-parent - 1.8.0.BUILD-SNAPSHOT + 1.8.0.DATAMONGO-1269-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index 64d6f7864a..570680c088 100644 --- a/spring-data-mongodb-log4j/pom.xml +++ b/spring-data-mongodb-log4j/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 1.8.0.BUILD-SNAPSHOT + 1.8.0.DATAMONGO-1269-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 819112059b..b24bb3e1dc 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -11,7 +11,7 @@ org.springframework.data spring-data-mongodb-parent - 1.8.0.BUILD-SNAPSHOT + 1.8.0.DATAMONGO-1269-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java index bd5a5ccfec..5ba6ca37cd 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java @@ -867,7 +867,7 @@ private PersistentPropertyPath getPath(String pathExpre * @return */ protected Converter getPropertyConverter() { - return PropertyToFieldNameConverter.INSTANCE; + return new PositionParameterRetainingPropertyKeyConverter(name); } /** @@ -881,6 +881,24 @@ protected Converter getAssociationConverter() { return new AssociationConverter(getAssociation()); } + /** + * @author Christoph Strobl + * @since 1.8 + */ + static class PositionParameterRetainingPropertyKeyConverter implements Converter { + + private final KeyMapper keyMapper; + + PositionParameterRetainingPropertyKeyConverter(String rawKey) { + this.keyMapper = new KeyMapper(rawKey); + } + + @Override + public String convert(MongoPersistentProperty source) { + return keyMapper.mapPropertyName(source); + } + } + /* * (non-Javadoc) * @see org.springframework.data.mongodb.core.convert.QueryMapper.Field#getTypeHint() @@ -901,6 +919,63 @@ public TypeInformation getTypeHint() { return NESTED_DOCUMENT; } + + /** + * @author Christoph Strobl + * @since 1.8 + */ + static class KeyMapper { + + Iterator iterator; + + public KeyMapper(String key) { + + this.iterator = Arrays.asList(key.split("\\.")).iterator(); + this.iterator.next(); + } + + /** + * Maps the property name while retaining potential positional operator {@literal $}. + * + * @param property + * @return + */ + protected String mapPropertyName(MongoPersistentProperty property) { + + String mappedName = PropertyToFieldNameConverter.INSTANCE.convert(property); + + boolean inspect = iterator.hasNext(); + while (inspect) { + + String partial = iterator.next(); + + boolean isPositional = (isPositionalParameter(partial) && (property.isMap() || property.isCollectionLike() || property + .isArray())); + if (isPositional) { + mappedName += "." + partial; + } + + inspect = isPositional && iterator.hasNext(); + } + + return mappedName; + } + + boolean isPositionalParameter(String partial) { + + if (partial.equals("$")) { + return true; + } + + try { + Long.valueOf(partial); + return true; + } catch (NumberFormatException e) { + return false; + } + } + } + } /** diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java index 091a600d7a..ea60fbb7df 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java @@ -15,8 +15,6 @@ */ package org.springframework.data.mongodb.core.convert; -import java.util.Arrays; -import java.util.Iterator; import java.util.Map.Entry; import org.springframework.core.convert.converter.Converter; @@ -24,13 +22,11 @@ import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; -import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty.PropertyToFieldNameConverter; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update.Modifier; import org.springframework.data.mongodb.core.query.Update.Modifiers; import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; -import org.springframework.util.Assert; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; @@ -213,7 +209,7 @@ public String getMappedKey() { */ @Override protected Converter getPropertyConverter() { - return new UpdatePropertyConverter(key); + return new PositionParameterRetainingPropertyKeyConverter(key); } /* @@ -225,99 +221,6 @@ protected Converter getAssociationConverter() { return new UpdateAssociationConverter(getAssociation(), key); } - /** - * Special mapper handling positional parameter {@literal $} within property names. - * - * @author Christoph Strobl - * @since 1.7 - */ - private static class UpdateKeyMapper { - - private final Iterator iterator; - - protected UpdateKeyMapper(String rawKey) { - - Assert.hasText(rawKey, "Key must not be null or empty!"); - - this.iterator = Arrays.asList(rawKey.split("\\.")).iterator(); - this.iterator.next(); - } - - /** - * Maps the property name while retaining potential positional operator {@literal $}. - * - * @param property - * @return - */ - protected String mapPropertyName(MongoPersistentProperty property) { - - String mappedName = PropertyToFieldNameConverter.INSTANCE.convert(property); - - boolean inspect = iterator.hasNext(); - while (inspect) { - - String partial = iterator.next(); - - boolean isPositional = isPositionalParameter(partial); - if (isPositional) { - mappedName += "." + partial; - } - - inspect = isPositional && iterator.hasNext(); - } - - return mappedName; - } - - boolean isPositionalParameter(String partial) { - - if (partial.equals("$")) { - return true; - } - - try { - Long.valueOf(partial); - return true; - } catch (NumberFormatException e) { - return false; - } - } - - } - - /** - * Special {@link Converter} for {@link MongoPersistentProperty} instances that will concatenate the {@literal $} - * contained in the source update key. - * - * @author Oliver Gierke - * @author Christoph Strobl - */ - private static class UpdatePropertyConverter implements Converter { - - private final UpdateKeyMapper mapper; - - /** - * Creates a new {@link UpdatePropertyConverter} with the given update key. - * - * @param updateKey must not be {@literal null} or empty. - */ - public UpdatePropertyConverter(String updateKey) { - - Assert.hasText(updateKey, "Update key must not be null or empty!"); - - this.mapper = new UpdateKeyMapper(updateKey); - } - - /* - * (non-Javadoc) - * @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object) - */ - @Override - public String convert(MongoPersistentProperty property) { - return mapper.mapPropertyName(property); - } - } - /** * {@link Converter} retaining positional parameter {@literal $} for {@link Association}s. * @@ -325,7 +228,7 @@ public String convert(MongoPersistentProperty property) { */ protected static class UpdateAssociationConverter extends AssociationConverter { - private final UpdateKeyMapper mapper; + private final KeyMapper mapper; /** * Creates a new {@link AssociationConverter} for the given {@link Association}. @@ -335,7 +238,7 @@ protected static class UpdateAssociationConverter extends AssociationConverter { public UpdateAssociationConverter(Association association, String key) { super(association); - this.mapper = new UpdateKeyMapper(key); + this.mapper = new KeyMapper(key); } /* diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java index b510d7145e..8cf5852b76 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java @@ -790,6 +790,34 @@ public void intersectsShouldUseGeoJsonRepresentationCorrectly() { assertThat(dbo, isBsonObject().containing("geoJsonPoint.$geoIntersects.$geometry.coordinates")); } + /** + * @see DATAMONGO-1269 + */ + @Test + public void mappingShouldRetainNumericMapKey() { + + Query query = query(where("map.1.stringProperty").is("ba'alzamon")); + + DBObject dbo = mapper.getMappedObject(query.getQueryObject(), + context.getPersistentEntity(EntityWithComplexValueTypeMap.class)); + + assertThat(dbo.containsField("map.1.stringProperty"), is(true)); + } + + /** + * @see DATAMONGO-1269 + */ + @Test + public void mappingShouldRetainNumericPositionInList() { + + Query query = query(where("list.1.stringProperty").is("ba'alzamon")); + + DBObject dbo = mapper.getMappedObject(query.getQueryObject(), + context.getPersistentEntity(EntityWithComplexValueTypeList.class)); + + assertThat(dbo.containsField("list.1.stringProperty"), is(true)); + } + @Document public class Foo { @Id private ObjectId id; @@ -890,4 +918,18 @@ static class ClassWithGeoTypes { GeoJsonPoint geoJsonPoint; @Field("geoJsonPointWithNameViaFieldAnnotation") GeoJsonPoint namedGeoJsonPoint; } + + static class SimpeEntityWithoutId { + + String stringProperty; + Integer integerProperty; + } + + static class EntityWithComplexValueTypeMap { + Map map; + } + + static class EntityWithComplexValueTypeList { + List list; + } }