Skip to content

Commit 62dcda9

Browse files
committed
DATAMONGO-1798 - Polishing.
Introduce FieldType to express the desired field type to use for MongoDB Id conversion. Adapt Querydsl Id conversion so Id values are converted in the QueryMapper and no longer in SpringDataMongodbSerializer. Adapt tests. Move MongoId from o.s.d.mongodb to o.s.d.m.c.core. Javadoc, reference docs.
1 parent 74b9ea9 commit 62dcda9

File tree

18 files changed

+214
-168
lines changed

18 files changed

+214
-168
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ protected void writeInternal(@Nullable Object obj, Bson bson, @Nullable MongoPer
517517

518518
if (idProperty != null && !dbObjectAccessor.hasValue(idProperty)) {
519519

520-
Object value = idMapper.convertId(accessor.getProperty(idProperty), idProperty.getIdType());
520+
Object value = idMapper.convertId(accessor.getProperty(idProperty), idProperty.getFieldType());
521521

522522
if (value != null) {
523523
dbObjectAccessor.put(idProperty, value);
@@ -982,7 +982,8 @@ protected DBRef createDBRef(Object target, MongoPersistentProperty property) {
982982
throw new MappingException("Cannot create a reference to an object with a NULL id.");
983983
}
984984

985-
return dbRefResolver.createDbRef(property == null ? null : property.getDBRef(), entity, idMapper.convertId(id, idProperty != null ? idProperty.getIdType() : ObjectId.class));
985+
return dbRefResolver.createDbRef(property == null ? null : property.getDBRef(), entity,
986+
idMapper.convertId(id, idProperty != null ? idProperty.getFieldType() : ObjectId.class));
986987
}
987988

988989
throw new MappingException("No id property found on class " + entity.getType());

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverter.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ default <S, T> T mapValueToTargetType(S source, Class<T> targetType, DbRefResolv
8989
String collection = sourceDocument.getString("$ref");
9090

9191
MongoPersistentEntity<?> entity = getMappingContext().getPersistentEntity(targetType);
92-
if (entity.getIdType() != null) {
93-
id = convertId(id, entity.getIdType());
92+
if (entity != null && entity.hasIdProperty()) {
93+
id = convertId(id, entity.getIdProperty().getFieldType());
9494
}
9595

9696
DBRef ref = sourceDocument.containsKey("$db") ? new DBRef(sourceDocument.getString("$db"), collection, id)
@@ -120,6 +120,7 @@ default <S, T> T mapValueToTargetType(S source, Class<T> targetType, DbRefResolv
120120
* Converts the given raw id value into either {@link ObjectId} or {@link String}.
121121
*
122122
* @param id
123+
* @param targetType
123124
* @return {@literal null} if source {@literal id} is already {@literal null}.
124125
* @since 2.2
125126
*/
@@ -142,7 +143,8 @@ default Object convertId(@Nullable Object id, Class<?> targetType) {
142143

143144
try {
144145
return getConversionService().canConvert(id.getClass(), targetType)
145-
? getConversionService().convert(id, targetType) : convertToMongoType(id, null);
146+
? getConversionService().convert(id, targetType)
147+
: convertToMongoType(id, null);
146148
} catch (ConversionException o_O) {
147149
return convertToMongoType(id, null);
148150
}

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,16 @@ protected Entry<String, Object> getMappedObjectForField(Field field, Object rawV
244244
*/
245245
protected Field createPropertyField(@Nullable MongoPersistentEntity<?> entity, String key,
246246
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
247-
return entity == null ? new Field(key) : new MetadataBackedField(key, entity, mappingContext);
247+
248+
if (entity == null) {
249+
return new Field(key);
250+
}
251+
252+
if (Field.ID_KEY.equals(key)) {
253+
return new MetadataBackedField(key, entity, mappingContext, entity.getIdProperty());
254+
}
255+
256+
return new MetadataBackedField(key, entity, mappingContext);
248257
}
249258

250259
/**
@@ -372,7 +381,7 @@ private boolean isIdField(Field documentField) {
372381
}
373382

374383
private Class<?> getIdTypeForField(Field documentField) {
375-
return isIdField(documentField) ? documentField.getProperty().getIdType() : ObjectId.class;
384+
return isIdField(documentField) ? documentField.getProperty().getFieldType() : ObjectId.class;
376385
}
377386

378387
/**
@@ -477,7 +486,7 @@ protected Object convertAssociation(@Nullable Object source, @Nullable MongoPers
477486

478487
DBRef ref = (DBRef) source;
479488
Object id = convertId(ref.getId(),
480-
property != null && property.isIdProperty() ? property.getIdType() : ObjectId.class);
489+
property != null && property.isIdProperty() ? property.getFieldType() : ObjectId.class);
481490

482491
if (StringUtils.hasText(ref.getDatabaseName())) {
483492
return new DBRef(ref.getDatabaseName(), ref.getCollectionName(), id);
@@ -572,9 +581,10 @@ public Object convertId(@Nullable Object id) {
572581
}
573582

574583
/**
575-
* Converts the given raw id value into either {@link ObjectId} or {@literal targetType}.
584+
* Converts the given raw id value into either {@link ObjectId} or {@link Class targetType}.
576585
*
577586
* @param id can be {@literal null}.
587+
* @param targetType
578588
* @return the converted {@literal id} or {@literal null} if the source was already {@literal null}.
579589
* @since 2.2
580590
*/

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
6767
/**
6868
* Creates a new {@link BasicMongoPersistentProperty}.
6969
*
70-
* @param field
71-
* @param propertyDescriptor
70+
* @param property
7271
* @param owner
7372
* @param simpleTypeHolder
7473
* @param fieldNamingStrategy
@@ -144,6 +143,32 @@ public String getFieldName() {
144143
return fieldName;
145144
}
146145

146+
/*
147+
* (non-Javadoc)
148+
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#getFieldType()
149+
*/
150+
@Override
151+
public Class<?> getFieldType() {
152+
153+
if (!isIdProperty()) {
154+
return getType();
155+
}
156+
157+
MongoId idAnnotation = findAnnotation(MongoId.class);
158+
159+
if (idAnnotation == null) {
160+
return FieldType.OBJECT_ID.getJavaClass();
161+
}
162+
163+
FieldType fieldType = idAnnotation.targetType();
164+
165+
if (fieldType == FieldType.IMPLICIT) {
166+
return getType();
167+
}
168+
169+
return fieldType.getJavaClass();
170+
}
171+
147172
/**
148173
* @return true if {@link org.springframework.data.mongodb.core.mapping.Field} having non blank
149174
* {@link org.springframework.data.mongodb.core.mapping.Field#value()} present.

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public class CachingMongoPersistentProperty extends BasicMongoPersistentProperty
3333
private @Nullable boolean dbRefResolved;
3434
private @Nullable DBRef dbref;
3535
private @Nullable String fieldName;
36+
private @Nullable Class<?> fieldType;
3637
private @Nullable Boolean usePropertyAccess;
3738
private @Nullable Boolean isTransient;
3839

@@ -89,6 +90,20 @@ public String getFieldName() {
8990
return this.fieldName;
9091
}
9192

93+
/*
94+
* (non-Javadoc)
95+
* @see org.springframework.data.mongodb.core.mapping.BasicMongoPersistentProperty#getFieldType()
96+
*/
97+
@Override
98+
public Class<?> getFieldType() {
99+
100+
if (this.fieldType == null) {
101+
this.fieldType = super.getFieldType();
102+
}
103+
104+
return this.fieldType;
105+
}
106+
92107
/*
93108
* (non-Javadoc)
94109
* @see org.springframework.data.mapping.model.AnnotationBasedPersistentProperty#usePropertyAccess()
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.mongodb.core.mapping;
17+
18+
import org.bson.types.ObjectId;
19+
20+
/**
21+
* Enumeration of field value types that can be used to represent a {@link org.bson.Document} field value. This
22+
* enumeration contains a subset of {@link org.bson.BsonType} that is supported by the mapping and conversion
23+
* components.
24+
*
25+
* @author Mark Paluch
26+
* @since 2.2
27+
* @see org.bson.BsonType
28+
*/
29+
public enum FieldType {
30+
31+
/**
32+
* Implicit type that is derived from the property value.
33+
*/
34+
IMPLICIT(-1, Object.class), STRING(2, String.class), OBJECT_ID(7, ObjectId.class);
35+
36+
private final int bsonType;
37+
private final Class<?> javaClass;
38+
39+
FieldType(int bsonType, Class<?> javaClass) {
40+
41+
this.bsonType = bsonType;
42+
this.javaClass = javaClass;
43+
}
44+
45+
/**
46+
* Returns the BSON type identifier.
47+
*
48+
* @return the BSON type identifier.
49+
*/
50+
public int getBsonType() {
51+
return bsonType;
52+
}
53+
54+
/**
55+
* Returns the Java class used to represent the type.
56+
*
57+
* @return the Java class used to represent the type.
58+
*/
59+
public Class<?> getJavaClass() {
60+
return javaClass;
61+
}
62+
}

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoId.java renamed to spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/MongoId.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package org.springframework.data.mongodb;
16+
package org.springframework.data.mongodb.core.mapping;
1717

1818
import java.lang.annotation.ElementType;
1919
import java.lang.annotation.Retention;
@@ -24,14 +24,16 @@
2424
import org.springframework.data.annotation.Id;
2525

2626
/**
27-
* {@link MongoId} represents a MongoDB specific {@link Id} annotation that allows tweaking {@literal id} conversion. By
28-
* default {@link Object Class&lt;Object&gt;} will be used as the {@literal id's} target type. This means that the
29-
* actual property value is used. No conversion attempts to any other type is made. <br />
27+
* {@link MongoId} represents a MongoDB specific {@link Id} annotation that allows customizing {@literal id} conversion.
28+
* Id properties use {@link org.springframework.data.mongodb.core.mapping.FieldType#IMPLICIT} as the default
29+
* {@literal id's} target type. This means that the actual property value is used. No conversion attempts to any other
30+
* type are made. <br />
3031
* In contrast to {@link Id &#64;Id}, {@link String} {@literal id's} are stored as the such even when the actual value
3132
* represents a valid {@link org.bson.types.ObjectId#isValid(String) ObjectId hex String}. To trigger {@link String} to
32-
* {@link org.bson.types.ObjectId} conversion use {@link MongoId#targetType() &#64;MongoId(ObjectId.class)}.
33+
* {@link org.bson.types.ObjectId} conversion use {@link MongoId#targetType() &#64;MongoId(FieldType.OBJECT_ID)}.
3334
*
3435
* @author Christoph Strobl
36+
* @author Mark Paluch
3537
* @since 2.2
3638
*/
3739
@Id
@@ -44,16 +46,16 @@
4446
* @see #targetType()
4547
*/
4648
@AliasFor("targetType")
47-
Class<?> value() default Object.class;
49+
FieldType value() default FieldType.IMPLICIT;
4850

4951
/**
50-
* Get the preferred {@literal _id} type to be used. Defaulted to {@link Object Class&lt;Object&gt;} which used the
51-
* property's type. If defined different, the given value is attempted to be converted into the desired target type
52-
* via {@link org.springframework.data.mongodb.core.convert.MongoConverter#convertId(Object, Class)}.
52+
* Get the preferred {@literal _id} type to be used. Defaults to {@link FieldType#IMPLICIT} which uses the property's
53+
* type. If defined different, the given value is attempted to be converted into the desired target type via
54+
* {@link org.springframework.data.mongodb.core.convert.MongoConverter#convertId(Object, Class)}.
5355
*
54-
* @return the preferred {@literal id} type. {@link Object Class&lt;Object&gt;} by default.
56+
* @return the preferred {@literal id} type. {@link FieldType#IMPLICIT} by default.
5557
*/
5658
@AliasFor("value")
57-
Class<?> targetType() default Object.class;
59+
FieldType targetType() default FieldType.IMPLICIT;
5860

5961
}

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

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,20 +59,4 @@ public interface MongoPersistentEntity<T> extends PersistentEntity<T, MongoPersi
5959
*/
6060
boolean hasTextScoreProperty();
6161

62-
/**
63-
* Returns the entities {@literal id} type of {@literal null} if the entity has no {@literal id} property.
64-
*
65-
* @return {@literal null} if the entity does not have an {@link #hasIdProperty() id property}.
66-
* @since 2.2
67-
*/
68-
@Nullable
69-
default Class<?> getIdType() {
70-
71-
if (!hasIdProperty()) {
72-
return null;
73-
}
74-
75-
return getIdProperty().getIdType();
76-
}
77-
7862
}

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

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@
1515
*/
1616
package org.springframework.data.mongodb.core.mapping;
1717

18-
import org.bson.types.ObjectId;
1918
import org.springframework.core.convert.converter.Converter;
2019
import org.springframework.data.annotation.Id;
2120
import org.springframework.data.mapping.PersistentEntity;
2221
import org.springframework.data.mapping.PersistentProperty;
23-
import org.springframework.data.mongodb.MongoId;
2422
import org.springframework.lang.Nullable;
2523

2624
/**
@@ -40,6 +38,15 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist
4038
*/
4139
String getFieldName();
4240

41+
/**
42+
* Returns the {@link Class Java FieldType} of the field a property is persisted to.
43+
*
44+
* @return
45+
* @since 2.2
46+
* @see FieldType
47+
*/
48+
Class<?> getFieldType();
49+
4350
/**
4451
* Returns the order of the field if defined. Will return -1 if undefined.
4552
*
@@ -63,33 +70,6 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist
6370
*/
6471
boolean isExplicitIdProperty();
6572

66-
/**
67-
* Get the target id type to be used when writing the actual id value.
68-
*
69-
* @return The properties actual type of {@link Object Class&lt;Object&gt;} for properties using the native property
70-
* type. <br />
71-
* {@link org.bson.types.ObjectId Class&lt;ObjectId&gt;} indicates the attempt to parse the given raw value as
72-
* {@link org.bson.types.ObjectId}.
73-
* @throws IllegalStateException if the property is not considered an id property. Please make sure to check
74-
* {@link #isIdProperty()}.
75-
* @since 2.2
76-
*/
77-
default Class<?> getIdType() {
78-
79-
if (!isIdProperty()) {
80-
81-
throw new IllegalStateException(String.format("Property '%s' is not considerd an 'id' property",
82-
getField() != null ? getField().getName() : getFieldName()));
83-
}
84-
85-
MongoId idAnnotation = findAnnotation(MongoId.class);
86-
if (idAnnotation == null) {
87-
return ObjectId.class;
88-
}
89-
90-
return Object.class.equals(idAnnotation.targetType()) ? getActualType() : idAnnotation.targetType();
91-
}
92-
9373
/**
9474
* Returns true whether the property indicates the documents language either by having a {@link #getFieldName()} equal
9575
* to {@literal language} or being annotated with {@link Language}.

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbSerializer.java

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -120,28 +120,9 @@ protected Document asDocument(@Nullable String key, @Nullable Object value) {
120120

121121
value = value instanceof Optional ? ((Optional) value).orElse(null) : value;
122122

123-
if (ID_KEY.equals(key) || (key != null && key.endsWith("." + ID_KEY))) {
124-
return convertId(key, value);
125-
}
126-
127123
return super.asDocument(key, value instanceof Pattern ? value : converter.convertToMongoType(value));
128124
}
129125

130-
/**
131-
* Convert a given, already known to be an {@literal id} or even a nested document id, value into the according id
132-
* representation following the conversion rules of {@link QueryMapper#convertId(Object)}.
133-
*
134-
* @param key the property path to the given value.
135-
* @param idValue the raw {@literal id} value.
136-
* @return the {@literal id} representation in the required format.
137-
*/
138-
private Document convertId(String key, Object idValue) {
139-
140-
Object convertedId = mapper.convertId(idValue);
141-
142-
return mapper.getMappedObject(super.asDocument(key, convertedId), Optional.empty());
143-
}
144-
145126
/*
146127
* (non-Javadoc)
147128
* @see com.querydsl.mongodb.MongodbSerializer#isReference(com.querydsl.core.types.Path)

0 commit comments

Comments
 (0)