From 2256ebac1bf0c82f2030d1b89209e4c0876c846f Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 6 Jul 2011 19:09:24 +0200 Subject: [PATCH] DATADOC-172 - Allow defining property order for document mapping. Entities can now use @Field annotation to define the order using the order attribute. We will simply start with the lower values and proceed to the higher ones. Unannotated properties are ordered behind all annotated (and order declared) ones. One might not assume any particular order for fields where the order is not manually defined. Removed @FieldName as it is superseeded by @Field. --- .../data/document/mongodb/geo/Box.java | 3 ++ .../data/document/mongodb/geo/Point.java | 3 ++ .../mapping/BasicMongoPersistentEntity.java | 33 ++++++++++++- .../mapping/BasicMongoPersistentProperty.java | 34 ++++++++----- .../data/document/mongodb/mapping/Field.java | 27 ++++++++++ .../document/mongodb/mapping/FieldName.java | 36 -------------- .../mapping/MongoPersistentProperty.java | 7 +++ .../mapping/SimpleMongoMappingContext.java | 8 +++ ...BasicMongoPersistentPropertyUnitTests.java | 10 +++- .../MappingMongoConverterUnitTests.java | 2 +- ...PersistentPropertyComparatorUnitTests.java | 49 +++++++++++++++++++ ...tractPersonRepositoryIntegrationTests.java | 2 - 12 files changed, 161 insertions(+), 53 deletions(-) create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/Field.java delete mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/FieldName.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MongoPersistentPropertyComparatorUnitTests.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Box.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Box.java index 9ef44fe9d..d642b053f 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Box.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Box.java @@ -15,6 +15,7 @@ */ package org.springframework.data.document.mongodb.geo; +import org.springframework.data.document.mongodb.mapping.Field; import org.springframework.util.Assert; /** @@ -25,7 +26,9 @@ import org.springframework.util.Assert; */ public class Box { + @Field(order = 10) private final Point first; + @Field(order = 20) private final Point second; public Box(Point lowerLeft, Point upperRight) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Point.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Point.java index fbac85687..29b3a20b8 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Point.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Point.java @@ -16,6 +16,7 @@ package org.springframework.data.document.mongodb.geo; import org.springframework.data.annotation.PersistenceConstructor; +import org.springframework.data.document.mongodb.mapping.Field; import org.springframework.util.Assert; /** @@ -26,7 +27,9 @@ import org.springframework.util.Assert; */ public class Point { + @Field(order = 10) private final double x; + @Field(order = 20) private final double y; @PersistenceConstructor diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/BasicMongoPersistentEntity.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/BasicMongoPersistentEntity.java index 8694ea612..d07ea8e5c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/BasicMongoPersistentEntity.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/BasicMongoPersistentEntity.java @@ -16,6 +16,8 @@ package org.springframework.data.document.mongodb.mapping; +import java.util.Comparator; + import org.springframework.data.document.mongodb.MongoCollectionUtils; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.model.BasicPersistentEntity; @@ -44,7 +46,7 @@ public class BasicMongoPersistentEntity extends BasicPersistentEntity typeInformation) { - super(typeInformation); + super(typeInformation, MongoPersistentPropertyComparator.INSTANCE); Class rawType = typeInformation.getType(); String fallback = MongoCollectionUtils.getPreferredCollectionName(rawType); @@ -73,8 +75,35 @@ public class BasicMongoPersistentEntity extends BasicPersistentEntity { + + INSTANCE; + + /* + * (non-Javadoc) + * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) + */ + public int compare(MongoPersistentProperty o1, MongoPersistentProperty o2) { + + if (o1.getFieldOrder() == Integer.MAX_VALUE) { + return 1; + } + + if (o2.getFieldOrder() == Integer.MAX_VALUE) { + return -1; + } + + return o1.getFieldOrder() - o2.getFieldOrder(); + } + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/BasicMongoPersistentProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/BasicMongoPersistentProperty.java index 7fe84af33..e66d28cf2 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/BasicMongoPersistentProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/BasicMongoPersistentProperty.java @@ -21,17 +21,19 @@ import java.math.BigInteger; import java.util.HashSet; import java.util.Set; -import com.mongodb.DBObject; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.bson.types.ObjectId; import org.springframework.data.mapping.Association; import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty; import org.springframework.data.mapping.model.SimpleTypeHolder; +import org.springframework.util.StringUtils; + +import com.mongodb.DBObject; /** * Mongo specific {@link org.springframework.data.mapping.PersistentProperty} implementation. - * + * * @author Oliver Gierke */ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentProperty implements @@ -39,6 +41,7 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope private static final Log LOG = LogFactory.getLog(BasicMongoPersistentProperty.class); + private static final String ID_FIELD_NAME = "_id"; private static final Set> SUPPORTED_ID_TYPES = new HashSet>(); private static final Set SUPPORTED_ID_PROPERTY_NAMES = new HashSet(); @@ -53,7 +56,7 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope /** * Creates a new {@link BasicMongoPersistentProperty}. - * + * * @param field * @param propertyDescriptor * @param owner @@ -63,8 +66,8 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope MongoPersistentEntity owner, SimpleTypeHolder simpleTypeHolder) { super(field, propertyDescriptor, owner, simpleTypeHolder); - if (isIdProperty() && field.isAnnotationPresent(FieldName.class)) { - LOG.warn(String.format("Invalid usage of %s on id property. Field name will not be considered!", FieldName.class)); + if (isIdProperty() && getFieldName() != ID_FIELD_NAME) { + LOG.warn("Customizing field name for id property not allowed! Custom name will not be considered!"); } } @@ -78,7 +81,7 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope /** * Also considers fields as id that are of supported id type and name. - * + * * @see #SUPPORTED_ID_PROPERTY_NAMES * @see #SUPPORTED_ID_TYPES */ @@ -90,22 +93,31 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope // We need to support a wider range of ID types than just the ones that can be converted to an ObjectId return SUPPORTED_ID_PROPERTY_NAMES.contains(field.getName()); - //return SUPPORTED_ID_TYPES.contains(field.getType()) && SUPPORTED_ID_PROPERTY_NAMES.contains(field.getName()); } /** * Returns the key to be used to store the value of the property inside a Mongo {@link DBObject}. - * + * * @return */ public String getFieldName() { if (isIdProperty()) { - return "_id"; + return ID_FIELD_NAME; } - FieldName annotation = getField().getAnnotation(FieldName.class); - return annotation != null ? annotation.value() : getName(); + org.springframework.data.document.mongodb.mapping.Field annotation = getField().getAnnotation( + org.springframework.data.document.mongodb.mapping.Field.class); + return annotation != null && StringUtils.hasText(annotation.value()) ? annotation.value() : field.getName(); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.mapping.MongoPersistentProperty#getFieldOrder() + */ + public int getFieldOrder() { + org.springframework.data.document.mongodb.mapping.Field annotation = getField().getAnnotation( + org.springframework.data.document.mongodb.mapping.Field.class); + return annotation != null ? annotation.order() : Integer.MAX_VALUE; } /* (non-Javadoc) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/Field.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/Field.java new file mode 100644 index 000000000..3a993b415 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/Field.java @@ -0,0 +1,27 @@ +package org.springframework.data.document.mongodb.mapping; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Annotation to define custom metadata for document fields. + * + * @author Oliver Gierke + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface Field { + + /** + * The key to be used to store the field inside the document. + * @return + */ + String value() default ""; + + /** + * The order in which various fields shall be stored. Has to be a positive integer. + * @return the order the field shall have in the document or -1 if undefined. + */ + int order() default Integer.MAX_VALUE; +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/FieldName.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/FieldName.java deleted file mode 100644 index cbcec956a..000000000 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/FieldName.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2011 by the original author(s). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.document.mongodb.mapping; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation to allow defining the name of the field a property should use in a Mongo document. This will cause the - * property annotated being persisted to a field with the configured name as wells as being read from it. - * - * @author Oliver Gierke - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.FIELD }) -@Documented -public @interface FieldName { - - String value(); -} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentProperty.java index 69cf73861..03bf62a6a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoPersistentProperty.java @@ -30,6 +30,13 @@ public interface MongoPersistentProperty extends PersistentProperty properties = Arrays.asList(firstName, lastName, ssn); + Collections.sort(properties, MongoPersistentPropertyComparator.INSTANCE); + + assertThat(properties.get(0), is(ssn)); + assertThat(properties.get(1), is(firstName)); + assertThat(properties.get(2), is(lastName)); + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java index e8b60ead5..2d4f6dac8 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java @@ -9,7 +9,6 @@ import java.util.HashSet; import java.util.List; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -220,7 +219,6 @@ public abstract class AbstractPersonRepositoryIntegrationTests { } @Test - @Ignore public void findsPeopleByLocationWithinBox() { Point point = new Point(-73.99171, 40.738868); dave.setLocation(point);