Skip to content

Commit 05c2045

Browse files
committed
DATAMONGO-347 - Derived repository queries now correctly resolve referenced DBRef properties.
Added toDBRef(…) method to MongoWriter to be able to create a DBRef representation of an object. Polished DBRef creation implementation inside MappingMongoConverter. Removed collection and id attributes from @DBREF annotation as they have neither been documented nor used so far. Refactored MongoQueryCreator to be aware of the property and convert the given value into a DBRef if necessary.
1 parent d359819 commit 05c2045

File tree

12 files changed

+223
-59
lines changed

12 files changed

+223
-59
lines changed

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

+30-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2011 by the original author(s).
2+
* Copyright 2011-2012 by the original author(s).
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -265,6 +265,22 @@ public void doWithAssociation(Association<MongoPersistentProperty> association)
265265
return result;
266266
}
267267

268+
/*
269+
* (non-Javadoc)
270+
* @see org.springframework.data.mongodb.core.convert.MongoWriter#toDBRef(java.lang.Object, org.springframework.data.mongodb.core.mapping.MongoPersistentProperty)
271+
*/
272+
public DBRef toDBRef(Object object, MongoPersistentProperty referingProperty) {
273+
274+
org.springframework.data.mongodb.core.mapping.DBRef annotation = null;
275+
276+
if (referingProperty != null) {
277+
annotation = referingProperty.getDBRef();
278+
Assert.isTrue(annotation != null, "The referenced property has to be mapped with @DBRef!");
279+
}
280+
281+
return createDBRef(object, annotation);
282+
}
283+
268284
/**
269285
* Root entry method into write conversion. Adds a type discriminator to the {@link DBObject}. Shouldn't be called for
270286
* nested conversions.
@@ -658,28 +674,31 @@ private Object getPotentiallyConvertedSimpleRead(Object value, Class<?> target)
658674

659675
protected DBRef createDBRef(Object target, org.springframework.data.mongodb.core.mapping.DBRef dbref) {
660676

677+
Assert.notNull(target);
678+
661679
MongoPersistentEntity<?> targetEntity = mappingContext.getPersistentEntity(target.getClass());
662-
if (null == targetEntity || null == targetEntity.getIdProperty()) {
663-
return null;
680+
681+
if (null == targetEntity) {
682+
throw new MappingException("No mapping metadata found for " + target.getClass());
664683
}
665684

666685
MongoPersistentProperty idProperty = targetEntity.getIdProperty();
686+
687+
if (idProperty == null) {
688+
throw new MappingException("No id property found on class " + targetEntity.getType());
689+
}
690+
667691
BeanWrapper<MongoPersistentEntity<Object>, Object> wrapper = BeanWrapper.create(target, conversionService);
668692
Object id = wrapper.getProperty(idProperty, Object.class, useFieldAccessOnly);
669693

670694
if (null == id) {
671695
throw new MappingException("Cannot create a reference to an object with a NULL id.");
672696
}
673697

674-
String collection = dbref.collection();
675-
if ("".equals(collection)) {
676-
collection = targetEntity.getCollection();
677-
}
678-
679-
String dbname = dbref.db();
680-
DB db = StringUtils.hasText(dbname) ? mongoDbFactory.getDb(dbname) : mongoDbFactory.getDb();
698+
DB db = mongoDbFactory.getDb();
699+
db = dbref != null && StringUtils.hasText(dbref.db()) ? mongoDbFactory.getDb(dbref.db()) : db;
681700

682-
return new DBRef(db, collection, idMapper.convertId(id));
701+
return new DBRef(db, targetEntity.getCollection(), idMapper.convertId(id));
683702
}
684703

685704
protected Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, SpELExpressionEvaluator eval,

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

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2010-2011 the original author or authors.
2+
* Copyright 2010-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,8 +16,10 @@
1616
package org.springframework.data.mongodb.core.convert;
1717

1818
import org.springframework.data.convert.EntityWriter;
19+
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
1920

2021
import com.mongodb.DBObject;
22+
import com.mongodb.DBRef;
2123

2224
/**
2325
* A MongoWriter is responsible for converting an object of type T to the native MongoDB representation DBObject.
@@ -37,4 +39,14 @@ public interface MongoWriter<T> extends EntityWriter<T, DBObject> {
3739
* @return
3840
*/
3941
Object convertToMongoType(Object obj);
42+
43+
/**
44+
* Creates a {@link DBRef} to refer to the given object.
45+
*
46+
* @param object the object to create a {@link DBRef} to link to. The object's type has to carry an id attribute.
47+
* @param referingProperty the client-side property referring to the object which might carry additional metadata for
48+
* the {@link DBRef} object to create. Can be {@literal null}.
49+
* @return will never be {@literal null}.
50+
*/
51+
DBRef toDBRef(Object object, MongoPersistentProperty referingProperty);
4052
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011 by the original author(s).
2+
* Copyright 2011-2012 by the original author(s).
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -13,9 +13,9 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
1716
package org.springframework.data.mongodb.core.mapping;
1817

18+
import java.lang.annotation.Documented;
1919
import java.lang.annotation.ElementType;
2020
import java.lang.annotation.Retention;
2121
import java.lang.annotation.RetentionPolicy;
@@ -24,19 +24,21 @@
2424
import org.springframework.data.annotation.Reference;
2525

2626
/**
27-
* An annotation that indicates the annotated field is to be stored using a com.mongodb.DBRef
27+
* An annotation that indicates the annotated field is to be stored using a {@link com.mongodb.DBRef}.
2828
*
29-
* @author Jon Brisbin <jbrisbin@vmware.com>
29+
* @author Jon Brisbin
30+
* @authot Oliver Gierke
3031
*/
32+
@Documented
3133
@Retention(RetentionPolicy.RUNTIME)
3234
@Target({ ElementType.FIELD })
3335
@Reference
3436
public @interface DBRef {
3537

36-
String collection() default "";
37-
38-
String id() default "";
39-
38+
/**
39+
* The database the referred entity resides in.
40+
*
41+
* @return
42+
*/
4043
String db() default "";
41-
4244
}

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ConvertingParameterAccessor.java

+15-18
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.springframework.data.mongodb.core.convert.MongoWriter;
2323
import org.springframework.data.mongodb.core.geo.Distance;
2424
import org.springframework.data.mongodb.core.geo.Point;
25+
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
2526
import org.springframework.data.repository.query.ParameterAccessor;
2627
import org.springframework.util.Assert;
2728

@@ -137,37 +138,33 @@ public ConvertingIterator(Iterator<Object> delegate) {
137138
}
138139

139140
/*
140-
* (non-Javadoc)
141-
*
142-
* @see java.util.Iterator#hasNext()
143-
*/
141+
* (non-Javadoc)
142+
* @see java.util.Iterator#hasNext()
143+
*/
144144
public boolean hasNext() {
145145
return delegate.hasNext();
146146
}
147147

148148
/*
149-
* (non-Javadoc)
150-
*
151-
* @see java.util.Iterator#next()
152-
*/
149+
* (non-Javadoc)
150+
* @see java.util.Iterator#next()
151+
*/
153152
public Object next() {
154-
155153
return delegate.next();
156154
}
157155

158-
/* (non-Javadoc)
156+
/*
157+
* (non-Javadoc)
159158
* @see org.springframework.data.mongodb.repository.ConvertingParameterAccessor.PotentiallConvertingIterator#nextConverted()
160159
*/
161-
public Object nextConverted() {
162-
163-
return getConvertedValue(next());
160+
public Object nextConverted(MongoPersistentProperty property) {
161+
return property.isAssociation() ? writer.toDBRef(next(), property) : getConvertedValue(next());
164162
}
165163

166164
/*
167-
* (non-Javadoc)
168-
*
169-
* @see java.util.Iterator#remove()
170-
*/
165+
* (non-Javadoc)
166+
* @see java.util.Iterator#remove()
167+
*/
171168
public void remove() {
172169
delegate.remove();
173170
}
@@ -185,6 +182,6 @@ public interface PotentiallyConvertingIterator extends Iterator<Object> {
185182
*
186183
* @return
187184
*/
188-
Object nextConverted();
185+
Object nextConverted(MongoPersistentProperty property);
189186
}
190187
}

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java

+22-18
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ protected Criteria create(Part part, Iterator<Object> iterator) {
9898
}
9999

100100
PersistentPropertyPath<MongoPersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
101-
Criteria criteria = from(part.getType(),
101+
MongoPersistentProperty property = path.getLeafProperty();
102+
Criteria criteria = from(part.getType(), property,
102103
where(path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE)),
103104
(PotentiallyConvertingIterator) iterator);
104105

@@ -116,10 +117,11 @@ protected Criteria and(Part part, Criteria base, Iterator<Object> iterator) {
116117
return create(part, iterator);
117118
}
118119

119-
PersistentPropertyPath<MongoPersistentProperty> path2 = context.getPersistentPropertyPath(part.getProperty());
120+
PersistentPropertyPath<MongoPersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
121+
MongoPersistentProperty property = path.getLeafProperty();
120122

121-
Criteria criteria = from(part.getType(),
122-
where(path2.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE)),
123+
Criteria criteria = from(part.getType(), property,
124+
where(path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE)),
123125
(PotentiallyConvertingIterator) iterator);
124126

125127
return criteria.andOperator(criteria);
@@ -164,34 +166,36 @@ protected Query complete(Criteria criteria, Sort sort) {
164166
}
165167

166168
/**
167-
* Populates the given {@link CriteriaDefinition} depending on the {@link Type} given.
169+
* Populates the given {@link CriteriaDefinition} depending on the {@link Part} given.
168170
*
169-
* @param type
171+
* @param part
172+
* @param property
170173
* @param criteria
171174
* @param parameters
172175
* @return
173176
*/
174-
private Criteria from(Type type, Criteria criteria, PotentiallyConvertingIterator parameters) {
177+
private Criteria from(Type type, MongoPersistentProperty property, Criteria criteria,
178+
PotentiallyConvertingIterator parameters) {
175179

176180
switch (type) {
177181
case GREATER_THAN:
178-
return criteria.gt(parameters.nextConverted());
182+
return criteria.gt(parameters.nextConverted(property));
179183
case GREATER_THAN_EQUAL:
180-
return criteria.gte(parameters.nextConverted());
184+
return criteria.gte(parameters.nextConverted(property));
181185
case LESS_THAN:
182-
return criteria.lt(parameters.nextConverted());
186+
return criteria.lt(parameters.nextConverted(property));
183187
case LESS_THAN_EQUAL:
184-
return criteria.lte(parameters.nextConverted());
188+
return criteria.lte(parameters.nextConverted(property));
185189
case BETWEEN:
186-
return criteria.gt(parameters.nextConverted()).lt(parameters.nextConverted());
190+
return criteria.gt(parameters.nextConverted(property)).lt(parameters.nextConverted(property));
187191
case IS_NOT_NULL:
188192
return criteria.ne(null);
189193
case IS_NULL:
190194
return criteria.is(null);
191195
case NOT_IN:
192-
return criteria.nin(nextAsArray(parameters));
196+
return criteria.nin(nextAsArray(parameters, property));
193197
case IN:
194-
return criteria.in(nextAsArray(parameters));
198+
return criteria.in(nextAsArray(parameters, property));
195199
case LIKE:
196200
String value = parameters.next().toString();
197201
return criteria.regex(toLikeRegex(value));
@@ -225,9 +229,9 @@ private Criteria from(Type type, Criteria criteria, PotentiallyConvertingIterato
225229
Object parameter = parameters.next();
226230
return criteria.within((Shape) parameter);
227231
case SIMPLE_PROPERTY:
228-
return criteria.is(parameters.nextConverted());
232+
return criteria.is(parameters.nextConverted(property));
229233
case NEGATING_SIMPLE_PROPERTY:
230-
return criteria.not().is(parameters.nextConverted());
234+
return criteria.not().is(parameters.nextConverted(property));
231235
}
232236

233237
throw new IllegalArgumentException("Unsupported keyword!");
@@ -253,8 +257,8 @@ private <T> T nextAs(Iterator<Object> iterator, Class<T> type) {
253257
parameter.getClass()));
254258
}
255259

256-
private Object[] nextAsArray(PotentiallyConvertingIterator iterator) {
257-
Object next = iterator.nextConverted();
260+
private Object[] nextAsArray(PotentiallyConvertingIterator iterator, MongoPersistentProperty property) {
261+
Object next = iterator.nextConverted(property);
258262

259263
if (next instanceof Collection) {
260264
return ((Collection<?>) next).toArray();

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

+5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
import com.mongodb.BasicDBObject;
3939
import com.mongodb.DBObject;
40+
import com.mongodb.DBRef;
4041

4142
/**
4243
* Abstract base class for unit tests to specify behaviour we expect from {@link MongoOperations}. Subclasses return
@@ -80,6 +81,10 @@ public MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentPropert
8081
public Object convertToMongoType(Object obj) {
8182
return null;
8283
}
84+
85+
public DBRef toDBRef(Object object, MongoPersistentProperty referingProperty) {
86+
return null;
87+
}
8388
};
8489
}
8590

0 commit comments

Comments
 (0)