Skip to content

Fix string to objectId mapping error when using query method. #4511

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@

import static org.springframework.data.mongodb.core.query.Criteria.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.BsonRegularExpression;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.data.domain.Range;
import org.springframework.data.domain.Range.Bound;
import org.springframework.data.domain.Sort;
Expand Down Expand Up @@ -64,6 +68,7 @@
* @author Thomas Darimont
* @author Christoph Strobl
* @author Edward Prentice
* @author Gyungrai Wang
*/
class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {

Expand All @@ -72,6 +77,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
private final MongoParameterAccessor accessor;
private final MappingContext<?, MongoPersistentProperty> context;
private final boolean isGeoNearQuery;
private final ConversionService conversionService;

/**
* Creates a new {@link MongoQueryCreator} from the given {@link PartTree}, {@link ConvertingParameterAccessor} and
Expand All @@ -82,8 +88,8 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
* @param context
*/
public MongoQueryCreator(PartTree tree, ConvertingParameterAccessor accessor,
MappingContext<?, MongoPersistentProperty> context) {
this(tree, accessor, context, false);
MappingContext<?, MongoPersistentProperty> context, ConversionService conversionService) {
this(tree, accessor, context, false, conversionService);
}

/**
Expand All @@ -96,7 +102,7 @@ public MongoQueryCreator(PartTree tree, ConvertingParameterAccessor accessor,
* @param isGeoNearQuery
*/
public MongoQueryCreator(PartTree tree, ConvertingParameterAccessor accessor,
MappingContext<?, MongoPersistentProperty> context, boolean isGeoNearQuery) {
MappingContext<?, MongoPersistentProperty> context, boolean isGeoNearQuery, ConversionService conversionService) {

super(tree, accessor);

Expand All @@ -105,6 +111,7 @@ public MongoQueryCreator(PartTree tree, ConvertingParameterAccessor accessor,
this.accessor = accessor;
this.isGeoNearQuery = isGeoNearQuery;
this.context = context;
this.conversionService = conversionService;
}

@Override
Expand Down Expand Up @@ -168,24 +175,24 @@ private Criteria from(Part part, MongoPersistentProperty property, Criteria crit
switch (type) {
case AFTER:
case GREATER_THAN:
return criteria.gt(parameters.next());
return criteria.gt(next(parameters, property.getFieldType()));
case GREATER_THAN_EQUAL:
return criteria.gte(parameters.next());
return criteria.gte(next(parameters, property.getFieldType()));
case BEFORE:
case LESS_THAN:
return criteria.lt(parameters.next());
return criteria.lt(next(parameters, property.getFieldType()));
case LESS_THAN_EQUAL:
return criteria.lte(parameters.next());
return criteria.lte(next(parameters, property.getFieldType()));
case BETWEEN:
return computeBetweenPart(criteria, parameters);
return computeBetweenPart(criteria, parameters, property);
case IS_NOT_NULL:
return criteria.ne(null);
case IS_NULL:
return criteria.is(null);
case NOT_IN:
return criteria.nin(nextAsList(parameters, part));
return criteria.nin(nextAsList(parameters, part, property));
case IN:
return criteria.in(nextAsList(parameters, part));
return criteria.in(nextAsList(parameters, part, property));
case LIKE:
case STARTING_WITH:
case ENDING_WITH:
Expand All @@ -200,7 +207,7 @@ private Criteria from(Part part, MongoPersistentProperty property, Criteria crit
Object param = parameters.next();
return param instanceof Pattern pattern ? criteria.regex(pattern) : criteria.regex(param.toString());
case EXISTS:
return criteria.exists((Boolean) parameters.next());
return criteria.exists((Boolean) next(parameters, property.getFieldType()));
case TRUE:
return criteria.is(true);
case FALSE:
Expand All @@ -212,7 +219,7 @@ private Criteria from(Part part, MongoPersistentProperty property, Criteria crit
Optional<Distance> minDistance = range.getLowerBound().getValue();

Point point = accessor.getGeoNearLocation();
Point pointToUse = point == null ? nextAs(parameters, Point.class) : point;
Point pointToUse = point == null ? nextAs(parameters, Point.class, property) : point;

boolean isSpherical = isSpherical(property);

Expand All @@ -239,22 +246,48 @@ private Criteria from(Part part, MongoPersistentProperty property, Criteria crit

case WITHIN:

Object parameter = parameters.next();
Object parameter = next(parameters, property.getFieldType());
return criteria.within((Shape) parameter);
case SIMPLE_PROPERTY:

return isSimpleComparisionPossible(part) ? criteria.is(parameters.next())
return isSimpleComparisionPossible(part) ? criteria.is(next(parameters, property.getFieldType()))
: createLikeRegexCriteriaOrThrow(part, property, criteria, parameters, false);

case NEGATING_SIMPLE_PROPERTY:

return isSimpleComparisionPossible(part) ? criteria.ne(parameters.next())
return isSimpleComparisionPossible(part) ? criteria.ne(next(parameters, property.getFieldType()))
: createLikeRegexCriteriaOrThrow(part, property, criteria, parameters, true);
default:
throw new IllegalArgumentException("Unsupported keyword");
}
}

private Object nextAsList(Iterator<Object> parameters, Class<?> targetType) {
Object nextValue = parameters.next();

if(nextValue instanceof Iterable<?>) {
List<Object> convertedList = new ArrayList<>();
for(Object item : (Iterable<?>) nextValue) {
convertedList.add(convert(item, targetType));
}
return convertedList;
}

return nextValue;
}

private Object next(Iterator<Object> parameters, Class<?> targetType) {
return convert(parameters.next(), targetType);
}

private Object convert(Object value, Class<?> targetType) {
if(conversionService.canConvert(TypeDescriptor.forObject(value), TypeDescriptor.valueOf(targetType))) {
return conversionService.convert(value, targetType);
}
return value;
}


private boolean isSimpleComparisionPossible(Part part) {

switch (part.shouldIgnoreCase()) {
Expand Down Expand Up @@ -299,7 +332,7 @@ private Criteria createLikeRegexCriteriaOrThrow(Part part, MongoPersistentProper
criteria = criteria.not();
}

return addAppropriateLikeRegexTo(criteria, part, parameters.next());
return addAppropriateLikeRegexTo(criteria, part, next(parameters, property.getFieldType()));

case NEVER:
// intentional no-op
Expand All @@ -324,10 +357,10 @@ private Criteria createContainingCriteria(Part part, MongoPersistentProperty pro
Iterator<Object> parameters) {

if (property.isCollectionLike()) {
return criteria.in(nextAsList(parameters, part));
return criteria.in(nextAsList(parameters, part, property));
}

return addAppropriateLikeRegexTo(criteria, part, parameters.next());
return addAppropriateLikeRegexTo(criteria, part, next(parameters, property.getFieldType()));
}

/**
Expand Down Expand Up @@ -376,9 +409,9 @@ private String toRegexOptions(Part part) {
* @return
*/
@SuppressWarnings("unchecked")
private <T> T nextAs(Iterator<Object> iterator, Class<T> type) {
private <T> T nextAs(Iterator<Object> iterator, Class<T> type, MongoPersistentProperty property) {

Object parameter = iterator.next();
Object parameter = next(iterator, property.getFieldType());

if (ClassUtils.isAssignable(type, parameter.getClass())) {
return (T) parameter;
Expand All @@ -388,9 +421,9 @@ private <T> T nextAs(Iterator<Object> iterator, Class<T> type) {
String.format("Expected parameter type of %s but got %s", type, parameter.getClass()));
}

private java.util.List<?> nextAsList(Iterator<Object> iterator, Part part) {
private java.util.List<?> nextAsList(Iterator<Object> iterator, Part part, MongoPersistentProperty property) {

Streamable<?> streamable = asStreamable(iterator.next());
Streamable<?> streamable = asStreamable(nextAsList(iterator, property.getFieldType()));
if (!isSimpleComparisionPossible(part)) {

MatchMode matchMode = toMatchMode(part.getType());
Expand Down Expand Up @@ -446,11 +479,11 @@ private boolean isSpherical(MongoPersistentProperty property) {
* @return
* @since 2.2
*/
private static Criteria computeBetweenPart(Criteria criteria, Iterator<Object> parameters) {
private Criteria computeBetweenPart(Criteria criteria, Iterator<Object> parameters, MongoPersistentProperty property) {

Object value = parameters.next();
Object value = next(parameters, property.getFieldType());
if (!(value instanceof Range<?> range)) {
return criteria.gt(value).lt(parameters.next());
return criteria.gt(value).lt(next(parameters, property.getFieldType()));
}

Optional<?> min = range.getLowerBound().getValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.bson.Document;
import org.bson.json.JsonParseException;

import org.springframework.core.convert.ConversionService;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
Expand Down Expand Up @@ -49,6 +50,7 @@ public class PartTreeMongoQuery extends AbstractMongoQuery {
private final boolean isGeoNearQuery;
private final MappingContext<?, MongoPersistentProperty> context;
private final ResultProcessor processor;
private final ConversionService conversionService;

/**
* Creates a new {@link PartTreeMongoQuery} from the given {@link QueryMethod} and {@link MongoTemplate}.
Expand All @@ -67,6 +69,7 @@ public PartTreeMongoQuery(MongoQueryMethod method, MongoOperations mongoOperatio
this.tree = new PartTree(method.getName(), processor.getReturnedType().getDomainType());
this.isGeoNearQuery = method.isGeoNearQuery();
this.context = mongoOperations.getConverter().getMappingContext();
this.conversionService = mongoOperations.getConverter().getConversionService();
}

/**
Expand All @@ -81,7 +84,7 @@ public PartTree getTree() {
@Override
protected Query createQuery(ConvertingParameterAccessor accessor) {

MongoQueryCreator creator = new MongoQueryCreator(tree, accessor, context, isGeoNearQuery);
MongoQueryCreator creator = new MongoQueryCreator(tree, accessor, context, isGeoNearQuery, conversionService);
Query query = creator.createQuery();

if (tree.isLimiting()) {
Expand Down Expand Up @@ -126,7 +129,7 @@ protected Query createQuery(ConvertingParameterAccessor accessor) {

@Override
protected Query createCountQuery(ConvertingParameterAccessor accessor) {
return new MongoQueryCreator(tree, accessor, context, false).createQuery();
return new MongoQueryCreator(tree, accessor, context, false, conversionService).createQuery();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.springframework.data.mongodb.repository.query;

import org.springframework.core.convert.ConversionService;
import reactor.core.publisher.Mono;

import org.bson.Document;
Expand Down Expand Up @@ -49,6 +50,8 @@ public class ReactivePartTreeMongoQuery extends AbstractReactiveMongoQuery {
private final MappingContext<?, MongoPersistentProperty> context;
private final ResultProcessor processor;

private final ConversionService conversionService;

/**
* Creates a new {@link ReactivePartTreeMongoQuery} from the given {@link QueryMethod} and {@link MongoTemplate}.
*
Expand All @@ -66,6 +69,7 @@ public ReactivePartTreeMongoQuery(ReactiveMongoQueryMethod method, ReactiveMongo
this.tree = new PartTree(method.getName(), processor.getReturnedType().getDomainType());
this.isGeoNearQuery = method.isGeoNearQuery();
this.context = mongoOperations.getConverter().getMappingContext();
this.conversionService = mongoOperations.getConverter().getConversionService();
}

/**
Expand All @@ -89,7 +93,7 @@ protected Mono<Query> createCountQuery(ConvertingParameterAccessor accessor) {

private Query createQueryInternal(ConvertingParameterAccessor accessor, boolean isCountQuery) {

MongoQueryCreator creator = new MongoQueryCreator(tree, accessor, context, isCountQuery ? false : isGeoNearQuery);
MongoQueryCreator creator = new MongoQueryCreator(tree, accessor, context, isCountQuery ? false : isGeoNearQuery, conversionService);
Query query = creator.createQuery();

if (isCountQuery) {
Expand Down
Loading