diff --git a/pom.xml b/pom.xml index 75745189ed..50eee8ac02 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 1.7.0.BUILD-SNAPSHOT + 1.7.0.DATAMONGO-1050-SNAPSHOT pom Spring Data MongoDB diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index 40e8a0f253..f39ae4f5a7 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.7.0.BUILD-SNAPSHOT + 1.7.0.DATAMONGO-1050-SNAPSHOT ../pom.xml @@ -48,7 +48,7 @@ org.springframework.data spring-data-mongodb - 1.7.0.BUILD-SNAPSHOT + 1.7.0.DATAMONGO-1050-SNAPSHOT diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml index 13110137b6..ff00d2742c 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.7.0.BUILD-SNAPSHOT + 1.7.0.DATAMONGO-1050-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb-log4j/pom.xml b/spring-data-mongodb-log4j/pom.xml index 6ff09e4577..7d1af7a511 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.7.0.BUILD-SNAPSHOT + 1.7.0.DATAMONGO-1050-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index bfcacd66eb..ec09fec9df 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.7.0.BUILD-SNAPSHOT + 1.7.0.DATAMONGO-1050-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java index bde3c63bde..4680791d1f 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java @@ -100,7 +100,8 @@ public boolean isIdProperty() { } // 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(getName()); + // but still we need to check if there happens to be an explicit name set + return SUPPORTED_ID_PROPERTY_NAMES.contains(getName()) && !hasExplicitFieldName(); } /* @@ -134,10 +135,8 @@ public String getFieldName() { } } - org.springframework.data.mongodb.core.mapping.Field annotation = findAnnotation(org.springframework.data.mongodb.core.mapping.Field.class); - - if (annotation != null && StringUtils.hasText(annotation.value())) { - return annotation.value(); + if (hasExplicitFieldName()) { + return getAnnotatedFieldName(); } String fieldName = fieldNamingStrategy.getFieldName(this); @@ -150,6 +149,26 @@ public String getFieldName() { return fieldName; } + /** + * @return true if {@link org.springframework.data.mongodb.core.mapping.Field} having non blank + * {@link org.springframework.data.mongodb.core.mapping.Field#value()} present. + * @since 1.7 + */ + protected boolean hasExplicitFieldName() { + return StringUtils.hasText(getAnnotatedFieldName()); + } + + private String getAnnotatedFieldName() { + + org.springframework.data.mongodb.core.mapping.Field annotation = findAnnotation(org.springframework.data.mongodb.core.mapping.Field.class); + + if (annotation != null && StringUtils.hasText(annotation.value())) { + return annotation.value(); + } + + return null; + } + /* * (non-Javadoc) * @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#getFieldOrder() diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java index 0cdb405ade..26ce313497 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java @@ -15,10 +15,26 @@ */ package org.springframework.data.mongodb.core.convert; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; -import static org.springframework.data.mongodb.core.DBObjectTestUtils.*; +import static org.hamcrest.Matchers.arrayWithSize; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.data.mongodb.core.DBObjectTestUtils.getAsDBObject; +import static org.springframework.data.mongodb.core.DBObjectTestUtils.getTypedValue; import java.math.BigDecimal; import java.math.BigInteger; @@ -83,6 +99,7 @@ import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; +import com.mongodb.BasicDBObjectBuilder; import com.mongodb.DB; import com.mongodb.DBObject; import com.mongodb.DBRef; @@ -1869,6 +1886,81 @@ public void readShouldRespectExplicitFieldNameForDbRef() { Mockito.any(DbRefResolverCallback.class), Mockito.any(DbRefProxyHandler.class)); } + /** + * @see DATAMONGO-1050 + */ + @Test + public void writeShouldUseExplicitFieldnameForIdPropertyWhenAnnotated() { + + RootForClassWithExplicitlyRenamedIdField source = new RootForClassWithExplicitlyRenamedIdField(); + source.id = "rootId"; + source.nested = new ClassWithExplicitlyRenamedField(); + source.nested.id = "nestedId"; + + DBObject sink = new BasicDBObject(); + converter.write(source, sink); + + assertThat((String) sink.get("_id"), is("rootId")); + assertThat((DBObject) sink.get("nested"), is(new BasicDBObjectBuilder().add("id", "nestedId").get())); + } + + /** + * @see DATAMONGO-1050 + */ + @Test + public void readShouldUseExplicitFieldnameForIdPropertyWhenAnnotated() { + + DBObject source = new BasicDBObjectBuilder().add("_id", "rootId") + .add("nested", new BasicDBObject("id", "nestedId")).get(); + + RootForClassWithExplicitlyRenamedIdField sink = converter.read(RootForClassWithExplicitlyRenamedIdField.class, + source); + + assertThat(sink.id, is("rootId")); + assertThat(sink.nested, notNullValue()); + assertThat(sink.nested.id, is("nestedId")); + } + + /** + * @see DATAMONGO-1050 + */ + @Test + public void namedIdFieldShouldExtractValueFromUnderscoreIdField() { + + DBObject dbo = new BasicDBObjectBuilder().add("_id", "A").add("id", "B").get(); + + ClassWithNamedIdField withNamedIdField = converter.read(ClassWithNamedIdField.class, dbo); + + assertThat(withNamedIdField.id, is("A")); + } + + /** + * @see DATAMONGO-1050 + */ + @Test + public void explicitlyRenamedIfFieldShouldExtractValueFromIdField() { + + DBObject dbo = new BasicDBObjectBuilder().add("_id", "A").add("id", "B").get(); + + ClassWithExplicitlyRenamedField withExplicitlyRenamedField = converter.read(ClassWithExplicitlyRenamedField.class, + dbo); + + assertThat(withExplicitlyRenamedField.id, is("B")); + } + + /** + * @see DATAMONGO-1050 + */ + @Test + public void annotatedIdFieldShouldExtractValueFromUnderscoreIdField() { + + DBObject dbo = new BasicDBObjectBuilder().add("_id", "A").add("id", "B").get(); + + ClassWithAnnotatedIdField withAnnotatedIdField = converter.read(ClassWithAnnotatedIdField.class, dbo); + + assertThat(withAnnotatedIdField.key, is("A")); + } + static class GenericType { T content; } @@ -2128,6 +2220,32 @@ class ClassWithExplicitlyNamedDBRefProperty { public ClassWithIntId getDbRefProperty() { return dbRefProperty; } + } + + static class RootForClassWithExplicitlyRenamedIdField { + + @Id String id; + ClassWithExplicitlyRenamedField nested; + } + + static class ClassWithExplicitlyRenamedField { + + @Field("id") String id; + } + + static class RootForClassWithNamedIdField { + + String id; + ClassWithNamedIdField nested; + } + + static class ClassWithNamedIdField { + + String id; + } + + static class ClassWithAnnotatedIdField { + @Id String 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 1fa54024eb..5de72b45f9 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 @@ -659,6 +659,7 @@ public void getMappedSortIgnoresTextScoreWhenNotSortedByScore() { } /** +<<<<<<< HEAD * @see DATAMONGO-1070 */ @Test @@ -673,6 +674,34 @@ public void mapsIdReferenceToDBRefCorrectly() { com.mongodb.DBRef reference = getTypedValue(result, "reference", com.mongodb.DBRef.class); assertThat(reference.getId(), is(instanceOf(ObjectId.class))); } + + /** + * @see DATAMONGO-1050 + */ + @Test + public void shouldUseExplicitlySetFieldnameForIdPropertyCandidates() { + + Query query = query(where("nested.id").is("bar")); + + DBObject dbo = mapper.getMappedObject(query.getQueryObject(), + context.getPersistentEntity(RootForClassWithExplicitlyRenamedIdField.class)); + + assertThat(dbo, equalTo(new BasicDBObjectBuilder().add("nested.id", "bar").get())); + } + + /** + * @see DATAMONGO-1050 + */ + @Test + public void shouldUseExplicitlySetFieldnameForIdPropertyCandidatesUsedInSortClause() { + + Query query = new Query().with(new Sort("nested.id")); + + DBObject dbo = mapper.getMappedSort(query.getSortObject(), + context.getPersistentEntity(RootForClassWithExplicitlyRenamedIdField.class)); + + assertThat(dbo, equalTo(new BasicDBObjectBuilder().add("nested.id", 1).get())); + } @Document public class Foo { @@ -755,4 +784,15 @@ class WithTextScoreProperty { @Id String id; @TextScore @Field("score") Float textScore; } + + static class RootForClassWithExplicitlyRenamedIdField { + + @Id String id; + ClassWithExplicitlyRenamedField nested; + } + + static class ClassWithExplicitlyRenamedField { + + @Field("id") String id; + } } 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 104791b37b..0dc781df1a 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 @@ -130,10 +130,7 @@ public void rejectsInvalidValueReturnedByFieldNamingStrategy() { @Test public void shouldDetectAnnotatedLanguagePropertyCorrectly() { - BasicMongoPersistentEntity persistentEntity = new BasicMongoPersistentEntity( - ClassTypeInformation.from(DocumentWithLanguageProperty.class)); - - MongoPersistentProperty property = getPropertyFor(persistentEntity, "lang"); + MongoPersistentProperty property = getPropertyFor(DocumentWithLanguageProperty.class, "lang"); assertThat(property.isLanguageProperty(), is(true)); } @@ -143,10 +140,7 @@ public void shouldDetectAnnotatedLanguagePropertyCorrectly() { @Test public void shouldDetectIplicitLanguagePropertyCorrectly() { - BasicMongoPersistentEntity persistentEntity = new BasicMongoPersistentEntity( - ClassTypeInformation.from(DocumentWithImplicitLanguageProperty.class)); - - MongoPersistentProperty property = getPropertyFor(persistentEntity, "language"); + MongoPersistentProperty property = getPropertyFor(DocumentWithImplicitLanguageProperty.class, "language"); assertThat(property.isLanguageProperty(), is(true)); } @@ -156,10 +150,7 @@ public void shouldDetectIplicitLanguagePropertyCorrectly() { @Test public void shouldDetectTextScorePropertyCorrectly() { - BasicMongoPersistentEntity persistentEntity = new BasicMongoPersistentEntity( - ClassTypeInformation.from(DocumentWithTextScoreProperty.class)); - - MongoPersistentProperty property = getPropertyFor(persistentEntity, "score"); + MongoPersistentProperty property = getPropertyFor(DocumentWithTextScoreProperty.class, "score"); assertThat(property.isTextScoreProperty(), is(true)); } @@ -169,17 +160,39 @@ public void shouldDetectTextScorePropertyCorrectly() { @Test public void shouldDetectTextScoreAsReadOnlyProperty() { - BasicMongoPersistentEntity persistentEntity = new BasicMongoPersistentEntity( - ClassTypeInformation.from(DocumentWithTextScoreProperty.class)); - - MongoPersistentProperty property = getPropertyFor(persistentEntity, "score"); + MongoPersistentProperty property = getPropertyFor(DocumentWithTextScoreProperty.class, "score"); assertThat(property.isWritable(), is(false)); } + /** + * @see DATAMONGO-1050 + */ + @Test + public void shouldNotConsiderExplicitlyNameFieldAsIdProperty() { + + MongoPersistentProperty property = getPropertyFor(DocumentWithExplicitlyRenamedIdProperty.class, "id"); + assertThat(property.isIdProperty(), is(false)); + } + + /** + * @see DATAMONGO-1050 + */ + @Test + public void shouldConsiderPropertyAsIdWhenExplicitlyAnnotatedWithIdEvenWhenExplicitlyNamePresent() { + + MongoPersistentProperty property = getPropertyFor(DocumentWithExplicitlyRenamedIdPropertyHavingIdAnnotation.class, + "id"); + assertThat(property.isIdProperty(), is(true)); + } + private MongoPersistentProperty getPropertyFor(Field field) { return getPropertyFor(entity, field); } + private MongoPersistentProperty getPropertyFor(Class type, String fieldname) { + return getPropertyFor(new BasicMongoPersistentEntity(ClassTypeInformation.from(type)), fieldname); + } + private MongoPersistentProperty getPropertyFor(MongoPersistentEntity persistentEntity, String fieldname) { return getPropertyFor(persistentEntity, ReflectionUtils.findField(persistentEntity.getType(), fieldname)); } @@ -230,4 +243,14 @@ static class DocumentWithImplicitLanguageProperty { static class DocumentWithTextScoreProperty { @TextScore Float score; } + + static class DocumentWithExplicitlyRenamedIdProperty { + + @org.springframework.data.mongodb.core.mapping.Field("id") String id; + } + + static class DocumentWithExplicitlyRenamedIdPropertyHavingIdAnnotation { + + @Id @org.springframework.data.mongodb.core.mapping.Field("id") String id; + } }