diff --git a/pom.xml b/pom.xml index 1d9b760700..4b6a149317 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 1.9.0.BUILD-SNAPSHOT + 1.9.0.DATAMONGO-1373-SNAPSHOT pom Spring Data MongoDB diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index fd36debedd..85c49dd5db 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.9.0.BUILD-SNAPSHOT + 1.9.0.DATAMONGO-1373-SNAPSHOT ../pom.xml @@ -48,7 +48,7 @@ org.springframework.data spring-data-mongodb - 1.9.0.BUILD-SNAPSHOT + 1.9.0.DATAMONGO-1373-SNAPSHOT diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml index 28c91bc332..4e8ae3941a 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.9.0.BUILD-SNAPSHOT + 1.9.0.DATAMONGO-1373-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index dfe146ff96..424cb4e52b 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.9.0.BUILD-SNAPSHOT + 1.9.0.DATAMONGO-1373-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 0fcdb2f39f..7b008f84d7 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.9.0.BUILD-SNAPSHOT + 1.9.0.DATAMONGO-1373-SNAPSHOT ../pom.xml @@ -19,6 +19,7 @@ 1.0.0.GA 1.3 1.5 + 1.12.0.DATACMNS-825-SNAPSHOT diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java index 119066877e..fd5c878787 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 the original author or authors. + * Copyright 2010-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,8 +27,9 @@ * @author Laurent Canet * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ -@Target(ElementType.FIELD) +@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface GeoSpatialIndexed { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/TextIndexed.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/TextIndexed.java index 9348aacd43..4f8fd83df1 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/TextIndexed.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/TextIndexed.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,10 +26,11 @@ * all fields marked with {@link TextIndexed} are combined into one single index.
* * @author Christoph Strobl + * @author Mark Paluch * @since 1.6 */ @Documented -@Target({ ElementType.FIELD }) +@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.RUNTIME) public @interface TextIndexed { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java index d182a9460a..a1196fca46 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java @@ -26,7 +26,6 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.context.expression.BeanFactoryAccessor; import org.springframework.context.expression.BeanFactoryResolver; -import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.annotation.Id; import org.springframework.data.mapping.Association; import org.springframework.data.mapping.AssociationHandler; @@ -78,7 +77,7 @@ public BasicMongoPersistentEntity(TypeInformation typeInformation) { Class rawType = typeInformation.getType(); String fallback = MongoCollectionUtils.getPreferredCollectionName(rawType); - Document document = AnnotationUtils.findAnnotation(rawType, Document.class); + Document document = this.findAnnotation(Document.class); this.expression = detectExpression(document); this.context = new StandardEvaluationContext(); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Field.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Field.java index 173aaa25b4..33d1eada88 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Field.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/Field.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2015 the original author or authors. + * + * 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.mongodb.core.mapping; import java.lang.annotation.Documented; diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Meta.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Meta.java index 9fe6c7cc7d..a24503b5ce 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Meta.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Meta.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,10 +25,11 @@ /** * @author Christoph Strobl + * @author Mark Paluch * @since 1.6 */ @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) +@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Documented @QueryAnnotation public @interface Meta { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Query.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Query.java index f79df312c6..8870ef3a61 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Query.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Query.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,9 +30,10 @@ * @author Oliver Gierke * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) +@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Documented @QueryAnnotation public @interface Query { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java index 85f0805f5c..afbecf83d3 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2015 the original author or authors. + * Copyright 2011-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.util.Arrays; import java.util.List; +import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.geo.GeoPage; import org.springframework.data.geo.GeoResult; @@ -43,6 +44,7 @@ * * @author Oliver Gierke * @author Christoph Strobl + * @author Mark Paluch */ public class MongoQueryMethod extends QueryMethod { @@ -191,7 +193,7 @@ private boolean isGeoNearQuery(Method method) { * @return */ Query getQueryAnnotation() { - return method.getAnnotation(Query.class); + return AnnotatedElementUtils.findMergedAnnotation(method, Query.class); } TypeInformation getReturnType() { @@ -213,7 +215,7 @@ public boolean hasQueryMetaAttributes() { * @since 1.6 */ Meta getMetaAnnotation() { - return method.getAnnotation(Meta.class); + return AnnotatedElementUtils.findMergedAnnotation(method, Meta.class); } /** diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java index 4768db366f..ecfa60e042 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2015 the original author or authors. + * Copyright 2014-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import static org.springframework.data.mongodb.test.util.IsBsonObject.isBsonObject; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -30,6 +31,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; +import org.springframework.core.annotation.AliasFor; import org.springframework.data.annotation.Id; import org.springframework.data.geo.Point; import org.springframework.data.mongodb.core.DBObjectTestUtils; @@ -54,6 +56,7 @@ /** * @author Christoph Strobl + * @author Mark Paluch */ @RunWith(Suite.class) @SuiteClasses({ IndexResolutionTests.class, GeoSpatialIndexResolutionTests.class, CompoundIndexResolutionTests.class, @@ -195,6 +198,42 @@ public void resolveIndexDefinitionInMetaAnnotatedFields() { assertThat(indexDefinitions.get(0).getIndexOptions(), equalTo(new BasicDBObjectBuilder().add("name", "_name").get())); } + + /** + * @see DATAMONGO-1373 + */ + @Test + public void resolveIndexDefinitionInComposedAnnotatedFields() { + + List indexDefinitions = prepareMappingContextAndResolveIndexForType( + IndexedDocumentWithComposedAnnotations.class); + + assertThat(indexDefinitions, hasSize(2)); + + IndexDefinitionHolder indexDefinitionHolder = indexDefinitions.get(1); + + assertThat(indexDefinitionHolder.getIndexKeys(), isBsonObject().containing("fieldWithMyIndexName", 1)); + assertThat(indexDefinitionHolder.getIndexOptions(), + isBsonObject().containing("sparse", true).containing("unique", true).containing("name", "my_index_name")); + } + + /** + * @see DATAMONGO-1373 + */ + @Test + public void resolveIndexDefinitionInCustomComposedAnnotatedFields() { + + List indexDefinitions = prepareMappingContextAndResolveIndexForType( + IndexedDocumentWithComposedAnnotations.class); + + assertThat(indexDefinitions, hasSize(2)); + + IndexDefinitionHolder indexDefinitionHolder = indexDefinitions.get(0); + + assertThat(indexDefinitionHolder.getIndexKeys(), isBsonObject().containing("fieldWithDifferentIndexName", 1)); + assertThat(indexDefinitionHolder.getIndexOptions(), + isBsonObject().containing("sparse", true).containing("name", "different_name").notContaining("unique")); + } @Document(collection = "Zero") static class IndexOnLevelZero { @@ -247,6 +286,44 @@ static class WithDbRef { static class NoIndex { @Id String id; } + + @Document + static class IndexedDocumentWithComposedAnnotations { + + @Id String id; + @CustomIndexedAnnotation String fieldWithDifferentIndexName; + @ComposedIndexedAnnotation String fieldWithMyIndexName; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.FIELD }) + @ComposedIndexedAnnotation(indexName = "different_name", beUnique = false) + static @interface CustomIndexedAnnotation { + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE }) + @Indexed + static @interface ComposedIndexedAnnotation { + + @AliasFor(annotation = Indexed.class, attribute = "unique") + boolean beUnique() default true; + + @AliasFor(annotation = Indexed.class, attribute = "sparse") + boolean beSparse() default true; + + @AliasFor(annotation = Indexed.class, attribute = "name") + String indexName() default "my_index_name"; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @org.springframework.data.mongodb.core.mapping.Field + static @interface ComposedFieldAnnotation { + + @AliasFor(annotation = org.springframework.data.mongodb.core.mapping.Field.class, attribute = "value") + String name() default "_id"; + } } @@ -319,6 +396,24 @@ public void resolvesIndexDefinitionOptionsCorrectly() { indexDefinition.getIndexOptions(), equalTo(new BasicDBObjectBuilder().add("name", "location").add("min", 1).add("max", 100).add("bits", 2).get())); } + + /** + * @see DATAMONGO-1373 + */ + @Test + public void resolvesComposedAnnotationIndexDefinitionOptionsCorrectly() { + + List indexDefinitions = prepareMappingContextAndResolveIndexForType(GeoSpatialIndexedDocumentWithComposedAnnotation.class); + + IndexDefinition indexDefinition = indexDefinitions.get(0).getIndexDefinition(); + + assertThat( + indexDefinition.getIndexKeys(), + isBsonObject().containing("location", "geoHaystack").containing("What light?", 1)); + assertThat( + indexDefinition.getIndexOptions(), + isBsonObject().containing("name", "my_geo_index_name").containing("bucketSize", 2.0)); + } @Document(collection = "Zero") static class GeoSpatialIndexOnLevelZero { @@ -342,6 +437,31 @@ static class WithOptionsOnGeoSpatialIndexProperty { type = GeoSpatialIndexType.GEO_2D)// Point location; } + + @Document(collection = "WithComposedAnnotation") + static class GeoSpatialIndexedDocumentWithComposedAnnotation { + + @ComposedGeoSpatialIndexed// + Point location; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.FIELD }) + @GeoSpatialIndexed + @interface ComposedGeoSpatialIndexed { + + @AliasFor(annotation = GeoSpatialIndexed.class, attribute = "name") + String indexName() default "my_geo_index_name"; + + @AliasFor(annotation = GeoSpatialIndexed.class, attribute = "additionalField") + String theAdditionalFieldINeedToDefine() default "What light?"; + + @AliasFor(annotation = GeoSpatialIndexed.class, attribute = "bucketSize") + double size() default 2; + + @AliasFor(annotation = GeoSpatialIndexed.class, attribute = "type") + GeoSpatialIndexType indexType() default GeoSpatialIndexType.GEO_HAYSTACK; + } } @@ -445,6 +565,20 @@ public void singleCompoundIndexPathOnLevelZeroIsResolvedCorrectly() { assertThat(indexDefinitions, hasSize(1)); assertIndexPathAndCollection(new String[] { "foo", "bar" }, "CompoundIndexOnLevelZero", indexDefinitions.get(0)); } + + /** + * @see DATAMONGO-1373 + */ + @Test + public void singleCompoundIndexUsingComposedAnnotationsOnTypeResolvedCorrectly() { + + List indexDefinitions = prepareMappingContextAndResolveIndexForType(CompoundIndexDocumentWithComposedAnnotation.class); + + assertThat(indexDefinitions, hasSize(1)); + assertThat(indexDefinitions.get(0).getIndexKeys(), isBsonObject().containing("foo", 1).containing("bar", -1)); + assertThat(indexDefinitions.get(0).getIndexOptions(), isBsonObject().containing("name", "my_compound_index_name"). + containing("unique", true).containing("background", true)); + } @Document(collection = "CompoundIndexOnLevelOne") static class CompoundIndexOnLevelOne { @@ -482,6 +616,34 @@ static class IndexDefinedOnSuperClass extends CompoundIndexOnLevelZero { static class ComountIndexWithAutogeneratedName { } + + @Document(collection = "WithComposedAnnotation") + @ComposedCompoundIndex + static class CompoundIndexDocumentWithComposedAnnotation { + + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.TYPE }) + @CompoundIndex + @interface ComposedCompoundIndex { + + @AliasFor(annotation = CompoundIndex.class, attribute = "def") + String fields() default "{'foo': 1, 'bar': -1}"; + + @AliasFor(annotation = CompoundIndex.class, attribute = "background") + boolean inBackground() default true; + + @AliasFor(annotation = CompoundIndex.class, attribute = "name") + String indexName() default "my_compound_index_name"; + + @AliasFor(annotation = CompoundIndex.class, attribute = "useGeneratedName") + boolean useGeneratedName() default false; + + @AliasFor(annotation = CompoundIndex.class, attribute = "unique") + boolean isUnique() default true; + + } } @@ -611,6 +773,18 @@ public void shouldPreferExplicitlyAnnotatedLanguageProperty() { List indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithOverlappingLanguageProps.class); assertThat(indexDefinitions.get(0).getIndexOptions().get("language_override"), is((Object) "lang")); } + + /** + * @see DATAMONGO-1373 + */ + @Test + public void shouldResolveComposedAnnotationCorrectly() { + + List indexDefinitions = prepareMappingContextAndResolveIndexForType(TextIndexedDocumentWithComposedAnnotation.class); + + DBObject weights = DBObjectTestUtils.getAsDBObject(indexDefinitions.get(0).getIndexOptions(), "weights"); + assertThat(weights, isBsonObject().containing("foo", 99f)); + } @Document static class TextIndexOnSinglePropertyInRoot { @@ -696,6 +870,22 @@ static class DocumentWithOverlappingLanguageProps { String language; @Language String lang; } + + @Document + static class TextIndexedDocumentWithComposedAnnotation { + + @ComposedTextIndexedAnnotation String foo; + String lang; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE }) + @TextIndexed + static @interface ComposedTextIndexedAnnotation { + + @AliasFor(annotation = TextIndexed.class, attribute = "weight") + float heavyweight() default 99f; + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntityUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntityUnitTests.java index a420c24d85..458b0fd4b6 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntityUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntityUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 by the original author(s). + * Copyright 2011-2016 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. @@ -29,6 +29,7 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.AliasFor; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.util.ClassTypeInformation; @@ -243,6 +244,18 @@ public void metaInformationShouldBeReadCorrectlyFromInheritedDocumentAnnotation( assertThat(entity.getCollection(), is("collection-1")); } + /** + * @see DATAMONGO-1373 + */ + @Test + public void metaInformationShouldBeReadCorrectlyFromComposedDocumentAnnotation() { + + BasicMongoPersistentEntity entity = new BasicMongoPersistentEntity( + ClassTypeInformation.from(DocumentWithComposedAnnotation.class)); + + assertThat(entity.getCollection(), is("custom-collection")); + } + @Document(collection = "contacts") class Contact { @@ -284,9 +297,23 @@ static class DocumentWithCustomAnnotation { } + @ComposedDocumentAnnotation + static class DocumentWithComposedAnnotation { + + } + @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE }) @Document(collection = "collection-1") static @interface CustomDocumentAnnotation { } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.TYPE }) + @Document + static @interface ComposedDocumentAnnotation { + + @AliasFor(annotation = Document.class, attribute = "collection") + String name() default "custom-collection"; + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentPropertyUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentPropertyUnitTests.java index 0dc781df1a..e2c64260c7 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentPropertyUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentPropertyUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 by the original author(s). + * Copyright 2011-2016 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. @@ -18,6 +18,10 @@ import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.lang.reflect.Field; import java.util.Locale; @@ -25,6 +29,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.core.annotation.AliasFor; import org.springframework.data.annotation.Id; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.model.FieldNamingStrategy; @@ -39,6 +44,7 @@ * * @author Oliver Gierke * @author Christoph Strobl + * @author Mark Paluch */ public class BasicMongoPersistentPropertyUnitTests { @@ -184,6 +190,29 @@ public void shouldConsiderPropertyAsIdWhenExplicitlyAnnotatedWithIdEvenWhenExpli "id"); assertThat(property.isIdProperty(), is(true)); } + + /** + * @see DATAMONGO-1373 + */ + @Test + public void shouldConsiderComposedAnnotationsForIdField() { + + MongoPersistentProperty property = getPropertyFor(DocumentWithComposedAnnotations.class, + "myId"); + assertThat(property.isIdProperty(), is(true)); + assertThat(property.getFieldName(), is("_id")); + } + + /** + * @see DATAMONGO-1373 + */ + @Test + public void shouldConsiderComposedAnnotationsForFields() { + + MongoPersistentProperty property = getPropertyFor(DocumentWithComposedAnnotations.class, + "myField"); + assertThat(property.getFieldName(), is("myField")); + } private MongoPersistentProperty getPropertyFor(Field field) { return getPropertyFor(entity, field); @@ -253,4 +282,25 @@ static class DocumentWithExplicitlyRenamedIdPropertyHavingIdAnnotation { @Id @org.springframework.data.mongodb.core.mapping.Field("id") String id; } + + static class DocumentWithComposedAnnotations { + + @ComposedIdAnnotation @ComposedFieldAnnotation String myId; + @ComposedFieldAnnotation(name = "myField") String myField; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @org.springframework.data.mongodb.core.mapping.Field + static @interface ComposedFieldAnnotation { + + @AliasFor(annotation = org.springframework.data.mongodb.core.mapping.Field.class, attribute = "value") + String name() default "_id"; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @Id + static @interface ComposedIdAnnotation { } + } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ComplexIdRepositoryIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ComplexIdRepositoryIntegrationTests.java index 17ab38b47e..011333c24a 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ComplexIdRepositoryIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ComplexIdRepositoryIntegrationTests.java @@ -18,6 +18,7 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -129,4 +130,27 @@ public void findAllShouldWorkWhenUsingComplexId() { assertThat(loaded, is(Matchers. iterableWithSize(1))); assertThat(loaded, contains(userWithId)); } + + /** + * @see DATAMONGO-1373 + */ + @Test + public void composedAnnotationFindQueryShouldWorkWhenUsingComplexId() { + + repo.save(userWithId); + + assertThat(repo.getUserUsingComposedAnnotationByComplexId(id), is(userWithId)); + } + + /** + * @see DATAMONGO-1373 + */ + @Test + public void composedAnnotationFindMetaShouldWorkWhenUsingComplexId() { + + repo.save(userWithId); + + assertThat(repo.findUsersUsingComposedMetaAnnotationByUserIds(Arrays.asList(id)), hasSize(0)); + } + } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/UserWithComplexIdRepository.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/UserWithComplexIdRepository.java index 880edd7a11..dca1abab19 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/UserWithComplexIdRepository.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/UserWithComplexIdRepository.java @@ -15,9 +15,15 @@ */ package org.springframework.data.mongodb.repository; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.util.Collection; import java.util.List; +import org.springframework.core.annotation.AliasFor; +import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.repository.CrudRepository; /** @@ -30,4 +36,31 @@ public interface UserWithComplexIdRepository extends CrudRepository findUsersUsingComposedMetaAnnotationByUserIds(Collection ids); + + + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.METHOD }) + @Document + @Query + @interface ComposedQueryAnnotation { + + @AliasFor(annotation = Query.class, attribute = "value") + String myQuery() default "{'_id': ?0}"; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.METHOD }) + @Meta + @interface ComposedMetaAnnotation { + + @AliasFor(annotation = Meta.class, attribute = "maxScanDocuments") + long scanDocuments() default 1; + } } diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index 0517b60d0e..e1d8c61dc5 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -1,6 +1,11 @@ [[new-features]] = New & Noteworthy +[[new-features.1-9-0]] +== What's new in Spring Data MongoDB 1.9 +* The following annotations have been enabled to build own, composed annotations: `@Document`, `@Id`, `@Field`, `@Indexed`, `@CompoundIndex`, `@GeoSpatialIndexed`, `@TextIndexed`, `@Query`, `@Meta`. + + [[new-features.1-8-0]] == What's new in Spring Data MongoDB 1.8