Skip to content

Commit c3bc5ef

Browse files
christophstroblmp911de
authored andcommitted
DATAMONGO-2149 - Fix $slice in fields projection when pointing to array of DBRefs.
We now no longer try to convert the actual slice parameters into a DBRef. Original pull request: #623.
1 parent db9d282 commit c3bc5ef

File tree

4 files changed

+84
-1
lines changed

4 files changed

+84
-1
lines changed

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

+13-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.util.ArrayList;
1919
import java.util.Arrays;
2020
import java.util.Collections;
21+
import java.util.HashSet;
2122
import java.util.Iterator;
2223
import java.util.List;
2324
import java.util.Map.Entry;
@@ -270,7 +271,7 @@ protected DBObject getMappedKeyword(Keyword keyword, MongoPersistentEntity<?> en
270271
*/
271272
protected DBObject getMappedKeyword(Field property, Keyword keyword) {
272273

273-
boolean needsAssociationConversion = property.isAssociation() && !keyword.isExists();
274+
boolean needsAssociationConversion = property.isAssociation() && !keyword.isExists() && keyword.mayHoldDbRef();
274275
Object value = keyword.getValue();
275276

276277
Object convertedValue = needsAssociationConversion ? convertAssociation(value, property)
@@ -544,10 +545,12 @@ protected boolean isKeyword(String candidate) {
544545
static class Keyword {
545546

546547
private static final String N_OR_PATTERN = "\\$.*or";
548+
private static final Set<String> NON_DBREF_CONVERTING_KEYWORDS = new HashSet<String>(Arrays.asList("$", "$size", "$slice", "$gt", "$lt"));
547549

548550
private final String key;
549551
private final Object value;
550552

553+
551554
public Keyword(DBObject source, String key) {
552555
this.key = key;
553556
this.value = source.get(key);
@@ -607,6 +610,15 @@ public String getKey() {
607610
public <T> T getValue() {
608611
return (T) value;
609612
}
613+
614+
/**
615+
*
616+
* @return {@literal true} if key may hold a DbRef.
617+
* @since 2.0.13
618+
*/
619+
public boolean mayHoldDbRef() {
620+
return !NON_DBREF_CONVERTING_KEYWORDS.contains(key);
621+
}
610622
}
611623

612624
/**

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java

+47
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
import java.util.ArrayList;
2424
import java.util.Arrays;
2525
import java.util.HashSet;
26+
import java.util.LinkedHashSet;
2627
import java.util.List;
28+
import java.util.Set;
2729
import java.util.regex.Pattern;
2830
import java.util.stream.Collectors;
2931
import java.util.stream.Stream;
@@ -56,6 +58,7 @@
5658
import org.springframework.data.mongodb.core.MongoOperations;
5759
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
5860
import org.springframework.data.mongodb.core.query.BasicQuery;
61+
import org.springframework.data.mongodb.core.query.Query;
5962
import org.springframework.data.mongodb.repository.Person.Sex;
6063
import org.springframework.data.mongodb.repository.SampleEvaluationContextExtension.SampleSecurityContextHolder;
6164
import org.springframework.data.querydsl.QSort;
@@ -1181,4 +1184,48 @@ public void findByRegexWithPatternAndOptions() {
11811184
assertThat(repository.findByFirstnameRegex(Pattern.compile(fn)), hasSize(0));
11821185
assertThat(repository.findByFirstnameRegex(Pattern.compile(fn, Pattern.CASE_INSENSITIVE)), hasSize(1));
11831186
}
1187+
1188+
@Test // DATAMONGO-2149
1189+
public void annotatedQueryShouldAllowSliceInFieldsProjectionWithDbRef() {
1190+
1191+
operations.remove(new Query(), User.class);
1192+
1193+
List<User> users = new ArrayList<User>();
1194+
1195+
for (int i = 0; i < 10; i++) {
1196+
1197+
User user = new User();
1198+
user.id = "id" + i;
1199+
user.username = "user" + i;
1200+
1201+
users.add(user);
1202+
1203+
operations.save(user);
1204+
}
1205+
1206+
alicia.fans = new ArrayList<User>(users);
1207+
operations.save(alicia);
1208+
1209+
Person target = repository.findWithSliceInProjection(alicia.getId(), 0, 5);
1210+
assertThat(target.getFans(), hasSize(5));
1211+
}
1212+
1213+
@Test // DATAMONGO-2149
1214+
public void annotatedQueryShouldAllowPositionalParameterInFieldsProjection() {
1215+
1216+
Set<Address> addressList = new LinkedHashSet<Address>();
1217+
1218+
for (int i = 0; i < 10; i++) {
1219+
addressList.add(new Address("street-" + i, "zip", "lnz"));
1220+
}
1221+
1222+
alicia.setShippingAddresses(addressList);
1223+
operations.save(alicia);
1224+
1225+
Person target = repository.findWithArrayPositionInProjection(1);
1226+
1227+
assertThat(target, notNullValue());
1228+
assertThat(target.getShippingAddresses(), hasSize(1));
1229+
}
1230+
11841231
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java

+6
Original file line numberDiff line numberDiff line change
@@ -328,4 +328,10 @@ Page<Person> findByCustomQueryLastnameAndAddressStreetInList(String lastname, Li
328328
void deleteByThePersonsFirstname(String firstname);
329329

330330
List<Person> findByFirstnameRegex(Pattern pattern);
331+
332+
@Query(value = "{ 'id' : ?0 }", fields = "{ 'fans': { '$slice': [ ?1, ?2 ] } }")
333+
Person findWithSliceInProjection(String id, int skip, int limit);
334+
335+
@Query(value = "{ 'shippingAddresses' : { '$elemMatch' : { 'city' : { '$eq' : 'lnz' } } } }", fields = "{ 'shippingAddresses.$': ?0 }")
336+
Person findWithArrayPositionInProjection(int position);
331337
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/StringBasedMongoQueryUnitTests.java

+18
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,18 @@ public void findUsingSpelShouldRetainNullValues() throws Exception {
529529
assertThat(query.getQueryObject(), is((DBObject) new BasicDBObject().append("arg0", null)));
530530
}
531531

532+
@Test // DATAMONGO-2149
533+
public void shouldParseFieldsProjectionWithSliceCorrectly() throws Exception {
534+
535+
StringBasedMongoQuery mongoQuery = createQueryForMethod("findWithSliceInProjection", String.class, int.class,
536+
int.class);
537+
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter, "Bruce Banner", 0, 5);
538+
539+
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
540+
541+
assertThat(query.getFieldsObject(), is(equalTo(JSON.parse("{ \"fans\" : { \"$slice\" : [0, 5] } }"))));
542+
}
543+
532544
private StringBasedMongoQuery createQueryForMethod(String name, Class<?>... parameters) throws Exception {
533545

534546
Method method = SampleRepository.class.getMethod(name, parameters);
@@ -623,5 +635,11 @@ private interface SampleRepository extends Repository<Person, Long> {
623635

624636
@Query("{ arg0 : ?#{[0]} }")
625637
List<Person> findByUsingSpel(Object arg0);
638+
639+
@Query("{ 'lastname' : { '$regex' : ?#{[0].lastname} } }")
640+
Person findByPersonLastnameRegex(Person key);
641+
642+
@Query(value = "{ 'id' : ?0 }", fields = "{ 'fans': { '$slice': [ ?1, ?2 ] } }")
643+
Person findWithSliceInProjection(String id, int skip, int limit);
626644
}
627645
}

0 commit comments

Comments
 (0)