Skip to content

Commit 0dd51fb

Browse files
christophstroblThomas Darimont
authored andcommitted
DATAMONGO-1050 - Explicitly annotated Field should not be considered Id.
We changed the id resolution to skip properties having an explicit name set via @field unless they are marked with @id. This means that @field(“id”) String id; will be stored as “id” within mongodb. Prior to this change the fieldname would have been changed to “_id”.
1 parent e1f3476 commit 0dd51fb

File tree

4 files changed

+168
-25
lines changed

4 files changed

+168
-25
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentProperty.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ public boolean isIdProperty() {
100100
}
101101

102102
// We need to support a wider range of ID types than just the ones that can be converted to an ObjectId
103-
return SUPPORTED_ID_PROPERTY_NAMES.contains(getName());
103+
// but still we need to check if there happens to be an explicit name set
104+
return SUPPORTED_ID_PROPERTY_NAMES.contains(getName()) && !hasExplicitFieldName();
104105
}
105106

106107
/*
@@ -134,10 +135,8 @@ public String getFieldName() {
134135
}
135136
}
136137

137-
org.springframework.data.mongodb.core.mapping.Field annotation = findAnnotation(org.springframework.data.mongodb.core.mapping.Field.class);
138-
139-
if (annotation != null && StringUtils.hasText(annotation.value())) {
140-
return annotation.value();
138+
if (hasExplicitFieldName()) {
139+
return getAnnotatedFieldName();
141140
}
142141

143142
String fieldName = fieldNamingStrategy.getFieldName(this);
@@ -150,6 +149,26 @@ public String getFieldName() {
150149
return fieldName;
151150
}
152151

152+
/**
153+
* @return true if {@link org.springframework.data.mongodb.core.mapping.Field} having non blank
154+
* {@link org.springframework.data.mongodb.core.mapping.Field#value()} present.
155+
* @since 1.7
156+
*/
157+
protected boolean hasExplicitFieldName() {
158+
return StringUtils.hasText(getAnnotatedFieldName());
159+
}
160+
161+
private String getAnnotatedFieldName() {
162+
163+
org.springframework.data.mongodb.core.mapping.Field annotation = findAnnotation(org.springframework.data.mongodb.core.mapping.Field.class);
164+
165+
if (annotation != null && StringUtils.hasText(annotation.value())) {
166+
return annotation.value();
167+
}
168+
169+
return null;
170+
}
171+
153172
/*
154173
* (non-Javadoc)
155174
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#getFieldOrder()

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,26 @@
1515
*/
1616
package org.springframework.data.mongodb.core.convert;
1717

18-
import static org.hamcrest.Matchers.*;
19-
import static org.junit.Assert.*;
20-
import static org.mockito.Mockito.*;
21-
import static org.springframework.data.mongodb.core.DBObjectTestUtils.*;
18+
import static org.hamcrest.Matchers.arrayWithSize;
19+
import static org.hamcrest.Matchers.equalTo;
20+
import static org.hamcrest.Matchers.hasItem;
21+
import static org.hamcrest.Matchers.hasItems;
22+
import static org.hamcrest.Matchers.hasSize;
23+
import static org.hamcrest.Matchers.instanceOf;
24+
import static org.hamcrest.Matchers.is;
25+
import static org.hamcrest.Matchers.not;
26+
import static org.hamcrest.Matchers.notNullValue;
27+
import static org.hamcrest.Matchers.nullValue;
28+
import static org.junit.Assert.assertEquals;
29+
import static org.junit.Assert.assertThat;
30+
import static org.junit.Assert.assertTrue;
31+
import static org.junit.Assert.fail;
32+
import static org.mockito.Mockito.mock;
33+
import static org.mockito.Mockito.times;
34+
import static org.mockito.Mockito.verify;
35+
import static org.mockito.Mockito.when;
36+
import static org.springframework.data.mongodb.core.DBObjectTestUtils.getAsDBObject;
37+
import static org.springframework.data.mongodb.core.DBObjectTestUtils.getTypedValue;
2238

2339
import java.math.BigDecimal;
2440
import java.math.BigInteger;
@@ -83,6 +99,7 @@
8399

84100
import com.mongodb.BasicDBList;
85101
import com.mongodb.BasicDBObject;
102+
import com.mongodb.BasicDBObjectBuilder;
86103
import com.mongodb.DB;
87104
import com.mongodb.DBObject;
88105
import com.mongodb.DBRef;
@@ -1868,6 +1885,41 @@ public void readShouldRespectExplicitFieldNameForDbRef() {
18681885
verify(resolver, times(1)).resolveDbRef(Mockito.any(MongoPersistentProperty.class), Mockito.any(DBRef.class),
18691886
Mockito.any(DbRefResolverCallback.class), Mockito.any(DbRefProxyHandler.class));
18701887
}
1888+
1889+
/**
1890+
* @see DATAMONGO-1050
1891+
*/
1892+
@Test
1893+
public void writeShouldUseExplicitFieldnameForIdPropertyWhenAnnotated() {
1894+
1895+
RootForClassWithExplicitlyRenamedIdField source = new RootForClassWithExplicitlyRenamedIdField();
1896+
source.id = "root";
1897+
source.nested = new ClassWithExplicitlyRenamedField();
1898+
source.nested.id = "nested";
1899+
1900+
DBObject sink = new BasicDBObject();
1901+
converter.write(source, sink);
1902+
1903+
assertThat((String) sink.get("_id"), is("root"));
1904+
assertThat((DBObject) sink.get("nested"), is(new BasicDBObjectBuilder().add("id", "nested").get()));
1905+
}
1906+
1907+
/**
1908+
* @see DATAMONGO-1050
1909+
*/
1910+
@Test
1911+
public void readShouldUseExplicitFieldnameForIdPropertyWhenAnnotated() {
1912+
1913+
DBObject source = new BasicDBObjectBuilder().add("_id", "root").add("nested", new BasicDBObject("id", "nested"))
1914+
.get();
1915+
1916+
RootForClassWithExplicitlyRenamedIdField sink = converter.read(RootForClassWithExplicitlyRenamedIdField.class,
1917+
source);
1918+
1919+
assertThat(sink.id, is("root"));
1920+
assertThat(sink.nested, notNullValue());
1921+
assertThat(sink.nested.id, is("nested"));
1922+
}
18711923

18721924
static class GenericType<T> {
18731925
T content;
@@ -2128,6 +2180,16 @@ class ClassWithExplicitlyNamedDBRefProperty {
21282180
public ClassWithIntId getDbRefProperty() {
21292181
return dbRefProperty;
21302182
}
2183+
}
2184+
2185+
static class RootForClassWithExplicitlyRenamedIdField {
2186+
2187+
@Id String id;
2188+
ClassWithExplicitlyRenamedField nested;
2189+
}
2190+
2191+
static class ClassWithExplicitlyRenamedField {
21312192

2193+
@Field("id") String id;
21322194
}
21332195
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,34 @@ public void getMappedSortIgnoresTextScoreWhenNotSortedByScore() {
658658
assertThat(dbo, equalTo(new BasicDBObjectBuilder().add("_id", 1).get()));
659659
}
660660

661+
/**
662+
* @see DATAMONGO-1050
663+
*/
664+
@Test
665+
public void shouldUseExplicitlySetFieldnameForIdPropertyCandidates() {
666+
667+
Query query = query(where("nested.id").is("bar"));
668+
669+
DBObject dbo = mapper.getMappedObject(query.getQueryObject(),
670+
context.getPersistentEntity(RootForClassWithExplicitlyRenamedIdField.class));
671+
672+
assertThat(dbo, equalTo(new BasicDBObjectBuilder().add("nested.id", "bar").get()));
673+
}
674+
675+
/**
676+
* @see DATAMONGO-1050
677+
*/
678+
@Test
679+
public void shouldUseExplicitlySetFieldnameForIdPropertyCandidatesUsedInSortClause() {
680+
681+
Query query = new Query().with(new Sort("nested.id"));
682+
683+
DBObject dbo = mapper.getMappedSort(query.getSortObject(),
684+
context.getPersistentEntity(RootForClassWithExplicitlyRenamedIdField.class));
685+
686+
assertThat(dbo, equalTo(new BasicDBObjectBuilder().add("nested.id", 1).get()));
687+
}
688+
661689
@Document
662690
public class Foo {
663691
@Id private ObjectId id;
@@ -739,4 +767,15 @@ class WithTextScoreProperty {
739767
@Id String id;
740768
@TextScore @Field("score") Float textScore;
741769
}
770+
771+
static class RootForClassWithExplicitlyRenamedIdField {
772+
773+
@Id String id;
774+
ClassWithExplicitlyRenamedField nested;
775+
}
776+
777+
static class ClassWithExplicitlyRenamedField {
778+
779+
@Field("id") String id;
780+
}
742781
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentPropertyUnitTests.java

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,7 @@ public void rejectsInvalidValueReturnedByFieldNamingStrategy() {
130130
@Test
131131
public void shouldDetectAnnotatedLanguagePropertyCorrectly() {
132132

133-
BasicMongoPersistentEntity<DocumentWithLanguageProperty> persistentEntity = new BasicMongoPersistentEntity<DocumentWithLanguageProperty>(
134-
ClassTypeInformation.from(DocumentWithLanguageProperty.class));
135-
136-
MongoPersistentProperty property = getPropertyFor(persistentEntity, "lang");
133+
MongoPersistentProperty property = getPropertyFor(DocumentWithLanguageProperty.class, "lang");
137134
assertThat(property.isLanguageProperty(), is(true));
138135
}
139136

@@ -143,10 +140,7 @@ public void shouldDetectAnnotatedLanguagePropertyCorrectly() {
143140
@Test
144141
public void shouldDetectIplicitLanguagePropertyCorrectly() {
145142

146-
BasicMongoPersistentEntity<DocumentWithImplicitLanguageProperty> persistentEntity = new BasicMongoPersistentEntity<DocumentWithImplicitLanguageProperty>(
147-
ClassTypeInformation.from(DocumentWithImplicitLanguageProperty.class));
148-
149-
MongoPersistentProperty property = getPropertyFor(persistentEntity, "language");
143+
MongoPersistentProperty property = getPropertyFor(DocumentWithImplicitLanguageProperty.class, "language");
150144
assertThat(property.isLanguageProperty(), is(true));
151145
}
152146

@@ -156,10 +150,7 @@ public void shouldDetectIplicitLanguagePropertyCorrectly() {
156150
@Test
157151
public void shouldDetectTextScorePropertyCorrectly() {
158152

159-
BasicMongoPersistentEntity<DocumentWithTextScoreProperty> persistentEntity = new BasicMongoPersistentEntity<DocumentWithTextScoreProperty>(
160-
ClassTypeInformation.from(DocumentWithTextScoreProperty.class));
161-
162-
MongoPersistentProperty property = getPropertyFor(persistentEntity, "score");
153+
MongoPersistentProperty property = getPropertyFor(DocumentWithTextScoreProperty.class, "score");
163154
assertThat(property.isTextScoreProperty(), is(true));
164155
}
165156

@@ -169,17 +160,39 @@ public void shouldDetectTextScorePropertyCorrectly() {
169160
@Test
170161
public void shouldDetectTextScoreAsReadOnlyProperty() {
171162

172-
BasicMongoPersistentEntity<DocumentWithTextScoreProperty> persistentEntity = new BasicMongoPersistentEntity<DocumentWithTextScoreProperty>(
173-
ClassTypeInformation.from(DocumentWithTextScoreProperty.class));
174-
175-
MongoPersistentProperty property = getPropertyFor(persistentEntity, "score");
163+
MongoPersistentProperty property = getPropertyFor(DocumentWithTextScoreProperty.class, "score");
176164
assertThat(property.isWritable(), is(false));
177165
}
178166

167+
/**
168+
* @see DATAMONGO-1050
169+
*/
170+
@Test
171+
public void shouldNotConsiderExplicitlyNameFieldAsIdProperty() {
172+
173+
MongoPersistentProperty property = getPropertyFor(DocumentWithExplicitlyRenamedIdProperty.class, "id");
174+
assertThat(property.isIdProperty(), is(false));
175+
}
176+
177+
/**
178+
* @see DATAMONGO-1050
179+
*/
180+
@Test
181+
public void shouldConsiderPropertyAsIdWhenExplicitlyAnnotatedWithIdEvenWhenExplicitlyNamePresent() {
182+
183+
MongoPersistentProperty property = getPropertyFor(DocumentWithExplicitlyRenamedIdPropertyHavingIdAnnotation.class,
184+
"id");
185+
assertThat(property.isIdProperty(), is(true));
186+
}
187+
179188
private MongoPersistentProperty getPropertyFor(Field field) {
180189
return getPropertyFor(entity, field);
181190
}
182191

192+
private <T> MongoPersistentProperty getPropertyFor(Class<T> type, String fieldname) {
193+
return getPropertyFor(new BasicMongoPersistentEntity<T>(ClassTypeInformation.from(type)), fieldname);
194+
}
195+
183196
private MongoPersistentProperty getPropertyFor(MongoPersistentEntity<?> persistentEntity, String fieldname) {
184197
return getPropertyFor(persistentEntity, ReflectionUtils.findField(persistentEntity.getType(), fieldname));
185198
}
@@ -230,4 +243,14 @@ static class DocumentWithImplicitLanguageProperty {
230243
static class DocumentWithTextScoreProperty {
231244
@TextScore Float score;
232245
}
246+
247+
static class DocumentWithExplicitlyRenamedIdProperty {
248+
249+
@org.springframework.data.mongodb.core.mapping.Field("id") String id;
250+
}
251+
252+
static class DocumentWithExplicitlyRenamedIdPropertyHavingIdAnnotation {
253+
254+
@Id @org.springframework.data.mongodb.core.mapping.Field("id") String id;
255+
}
233256
}

0 commit comments

Comments
 (0)