Browse Source

DATAMONGO-1345 - Finalized application of projections in query methods.

Refactored the query execution out of AbstractMongoQuery into MongoQueryExecution. Made sure the streaming execution lazily applies the projections, too.

Added a DtoInstantiatingConverter to be able to copy data from created entities into DTOs as we cannot hand the DTO type into the MongoTemplate execution in the first place as it's going to be used for the query mapping currently.
pull/344/head
Oliver Gierke 10 years ago
parent
commit
f10e5a19c5
  1. 380
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java
  2. 108
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/DtoInstantiatingConverter.java
  3. 34
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java
  4. 381
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryExecution.java
  5. 3
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java
  6. 6
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/PartTreeMongoQuery.java
  7. 24
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactory.java
  8. 41
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryCreatorUnitTests.java
  9. 4
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/PartTreeMongoQueryUnitTests.java
  10. 2
      spring-data-mongodb/template.mf

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 the original author or authors.
* Copyright 2010-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -15,31 +15,25 @@ @@ -15,31 +15,25 @@
*/
package org.springframework.data.mongodb.repository.query;
import java.util.Collections;
import java.util.List;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Range;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoPage;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.EntityInstantiators;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.CollectionExecution;
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.DeleteExecution;
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.GeoNearExecution;
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.PagedExecution;
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.PagingGeoNearExecution;
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.ResultProcessingConverter;
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.ResultProcessingExecution;
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.SingleEntityExecution;
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.SlicedExecution;
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.StreamExecution;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.util.CloseableIterator;
import org.springframework.data.util.StreamUtils;
import org.springframework.data.util.TypeInformation;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.util.Assert;
import com.mongodb.WriteResult;
/**
* Base class for {@link RepositoryQuery} implementations for Mongo.
*
@ -51,6 +45,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery { @@ -51,6 +45,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
private final MongoQueryMethod method;
private final MongoOperations operations;
private final EntityInstantiators instantiators;
/**
* Creates a new {@link AbstractMongoQuery} from the given {@link MongoQueryMethod} and {@link MongoOperations}.
@ -65,6 +60,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery { @@ -65,6 +60,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
this.method = method;
this.operations = operations;
this.instantiators = new EntityInstantiators();
}
/*
@ -86,30 +82,53 @@ public abstract class AbstractMongoQuery implements RepositoryQuery { @@ -86,30 +82,53 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
applyQueryMetaAttributesWhenPresent(query);
ResultProcessor processor = method.getResultProcessor().withDynamicProjection(accessor);
String collection = method.getEntityInformation().getCollectionName();
MongoQueryExecution execution = getExecution(query, accessor,
new ResultProcessingConverter(processor, operations, instantiators));
return execution.execute(query, processor.getReturnedType().getDomainType(), collection);
}
/**
* Returns the execution instance to use.
*
* @param query must not be {@literal null}.
* @param parameters must not be {@literal null}.
* @param accessor must not be {@literal null}.
* @return
*/
private MongoQueryExecution getExecution(Query query, MongoParameterAccessor accessor,
Converter<Object, Object> resultProcessing) {
if (method.isStreamQuery()) {
return new StreamExecution().execute(query);
} else if (isDeleteQuery()) {
return new DeleteExecution().execute(query);
} else if (method.isGeoNearQuery() && method.isPageQuery()) {
return new StreamExecution(operations, resultProcessing);
}
return new ResultProcessingExecution(getExecutionToWrap(query, accessor), resultProcessing);
}
MongoParameterAccessor countAccessor = new MongoParametersParameterAccessor(method, parameters);
Query countQuery = createCountQuery(new ConvertingParameterAccessor(operations.getConverter(), countAccessor));
private MongoQueryExecution getExecutionToWrap(Query query, MongoParameterAccessor accessor) {
return new GeoNearExecution(accessor).execute(query, countQuery);
if (isDeleteQuery()) {
return new DeleteExecution(operations, method);
} else if (method.isGeoNearQuery() && method.isPageQuery()) {
return new PagingGeoNearExecution(operations, accessor, method.getReturnType(), this);
} else if (method.isGeoNearQuery()) {
return new GeoNearExecution(accessor).execute(query);
return new GeoNearExecution(operations, accessor, method.getReturnType());
} else if (method.isSliceQuery()) {
return new SlicedExecution(accessor.getPageable()).execute(query);
return new SlicedExecution(operations, accessor.getPageable());
} else if (method.isCollectionQuery()) {
return new CollectionExecution(accessor.getPageable()).execute(query);
return new CollectionExecution(operations, accessor.getPageable());
} else if (method.isPageQuery()) {
return new PagedExecution(accessor.getPageable()).execute(query);
return new PagedExecution(operations, accessor.getPageable());
} else {
return new SingleEntityExecution(isCountQuery()).execute(query);
return new SingleEntityExecution(operations, isCountQuery());
}
}
private Query applyQueryMetaAttributesWhenPresent(Query query) {
Query applyQueryMetaAttributesWhenPresent(Query query) {
if (method.hasQueryMetaAttributes()) {
query.setMeta(method.getQueryMetaAttributes());
@ -127,12 +146,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery { @@ -127,12 +146,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
* @return
*/
protected Query createCountQuery(ConvertingParameterAccessor accessor) {
Query query = createQuery(accessor);
applyQueryMetaAttributesWhenPresent(query);
return query;
return applyQueryMetaAttributesWhenPresent(createQuery(accessor));
}
/**
@ -157,292 +171,4 @@ public abstract class AbstractMongoQuery implements RepositoryQuery { @@ -157,292 +171,4 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
* @since 1.5
*/
protected abstract boolean isDeleteQuery();
private abstract class Execution {
abstract Object execute(Query query);
protected List<?> readCollection(Query query) {
MongoEntityMetadata<?> metadata = method.getEntityInformation();
String collectionName = metadata.getCollectionName();
return operations.find(query, metadata.getJavaType(), collectionName);
}
}
/**
* {@link Execution} for collection returning queries.
*
* @author Oliver Gierke
*/
final class CollectionExecution extends Execution {
private final Pageable pageable;
CollectionExecution(Pageable pageable) {
this.pageable = pageable;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query)
*/
@Override
public Object execute(Query query) {
return readCollection(query.with(pageable));
}
}
/**
* {@link Execution} for {@link Slice} query methods.
*
* @author Oliver Gierke
* @author Christoph Strobl
* @since 1.5
*/
final class SlicedExecution extends Execution {
private final Pageable pageable;
SlicedExecution(Pageable pageable) {
this.pageable = pageable;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query)
*/
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
Object execute(Query query) {
MongoEntityMetadata<?> metadata = method.getEntityInformation();
int pageSize = pageable.getPageSize();
// Apply Pageable but tweak limit to peek into next page
Query modifiedQuery = query.with(pageable).limit(pageSize + 1);
List result = operations.find(modifiedQuery, metadata.getJavaType(), metadata.getCollectionName());
boolean hasNext = result.size() > pageSize;
return new SliceImpl<Object>(hasNext ? result.subList(0, pageSize) : result, pageable, hasNext);
}
}
/**
* {@link Execution} for pagination queries.
*
* @author Oliver Gierke
*/
final class PagedExecution extends Execution {
private final Pageable pageable;
/**
* Creates a new {@link PagedExecution}.
*
* @param pageable
*/
public PagedExecution(Pageable pageable) {
Assert.notNull(pageable);
this.pageable = pageable;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query)
*/
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
Object execute(Query query) {
MongoEntityMetadata<?> metadata = method.getEntityInformation();
String collectionName = metadata.getCollectionName();
Class<?> type = metadata.getJavaType();
int overallLimit = query.getLimit();
long count = operations.count(query, type, collectionName);
count = overallLimit != 0 ? Math.min(count, query.getLimit()) : count;
boolean pageableOutOfScope = pageable.getOffset() > count;
if (pageableOutOfScope) {
return new PageImpl<Object>(Collections.emptyList(), pageable, count);
}
// Apply raw pagination
query = query.with(pageable);
// Adjust limit if page would exceed the overall limit
if (overallLimit != 0 && pageable.getOffset() + pageable.getPageSize() > overallLimit) {
query.limit(overallLimit - pageable.getOffset());
}
List<?> result = operations.find(query, type, collectionName);
return new PageImpl(result, pageable, count);
}
}
/**
* {@link Execution} to return a single entity.
*
* @author Oliver Gierke
*/
final class SingleEntityExecution extends Execution {
private final boolean countProjection;
private SingleEntityExecution(boolean countProjection) {
this.countProjection = countProjection;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.core.query.Query)
*/
@Override
Object execute(Query query) {
MongoEntityMetadata<?> metadata = method.getEntityInformation();
return countProjection ? operations.count(query, metadata.getJavaType())
: operations.findOne(query, metadata.getJavaType(), metadata.getCollectionName());
}
}
/**
* {@link Execution} to execute geo-near queries.
*
* @author Oliver Gierke
*/
final class GeoNearExecution extends Execution {
private final MongoParameterAccessor accessor;
public GeoNearExecution(MongoParameterAccessor accessor) {
this.accessor = accessor;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query)
*/
@Override
Object execute(Query query) {
GeoResults<?> results = doExecuteQuery(query);
return isListOfGeoResult() ? results.getContent() : results;
}
/**
* Executes the given {@link Query} to return a page.
*
* @param query must not be {@literal null}.
* @param countQuery must not be {@literal null}.
* @return
*/
Object execute(Query query, Query countQuery) {
MongoEntityMetadata<?> metadata = method.getEntityInformation();
long count = operations.count(countQuery, metadata.getCollectionName());
return new GeoPage<Object>(doExecuteQuery(query), accessor.getPageable(), count);
}
@SuppressWarnings("unchecked")
private GeoResults<Object> doExecuteQuery(Query query) {
Point nearLocation = accessor.getGeoNearLocation();
NearQuery nearQuery = NearQuery.near(nearLocation);
if (query != null) {
nearQuery.query(query);
}
Range<Distance> distances = accessor.getDistanceRange();
Distance maxDistance = distances.getUpperBound();
if (maxDistance != null) {
nearQuery.maxDistance(maxDistance).in(maxDistance.getMetric());
}
Distance minDistance = distances.getLowerBound();
if (minDistance != null) {
nearQuery.minDistance(minDistance).in(minDistance.getMetric());
}
Pageable pageable = accessor.getPageable();
if (pageable != null) {
nearQuery.with(pageable);
}
MongoEntityMetadata<?> metadata = method.getEntityInformation();
return (GeoResults<Object>) operations.geoNear(nearQuery, metadata.getJavaType(), metadata.getCollectionName());
}
private boolean isListOfGeoResult() {
TypeInformation<?> returnType = method.getReturnType();
if (!returnType.getType().equals(List.class)) {
return false;
}
TypeInformation<?> componentType = returnType.getComponentType();
return componentType == null ? false : GeoResult.class.equals(componentType.getType());
}
}
/**
* {@link Execution} removing documents matching the query.
*
* @since 1.5
*/
final class DeleteExecution extends Execution {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query)
*/
@Override
Object execute(Query query) {
MongoEntityMetadata<?> metadata = method.getEntityInformation();
return deleteAndConvertResult(query, metadata);
}
private Object deleteAndConvertResult(Query query, MongoEntityMetadata<?> metadata) {
if (method.isCollectionQuery()) {
return operations.findAllAndRemove(query, metadata.getJavaType(), metadata.getCollectionName());
}
WriteResult writeResult = operations.remove(query, metadata.getJavaType(), metadata.getCollectionName());
return writeResult != null ? writeResult.getN() : 0L;
}
}
/**
* @author Thomas Darimont
* @since 1.7
*/
final class StreamExecution extends Execution {
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query)
*/
@Override
@SuppressWarnings("unchecked")
Object execute(Query query) {
Class<?> entityType = getQueryMethod().getEntityInformation().getJavaType();
return StreamUtils.createStreamFromIterator((CloseableIterator<Object>) operations.stream(query, entityType));
}
}
}

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

@ -0,0 +1,108 @@ @@ -0,0 +1,108 @@
/*
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.repository.query;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.EntityInstantiator;
import org.springframework.data.convert.EntityInstantiators;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.PreferredConstructor;
import org.springframework.data.mapping.PreferredConstructor.Parameter;
import org.springframework.data.mapping.SimplePropertyHandler;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.ParameterValueProvider;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.util.Assert;
/**
* {@link Converter} to instantiate DTOs from fully equipped domain objects.
*
* @author Oliver Gierke
*/
class DtoInstantiatingConverter implements Converter<Object, Object> {
private final Class<?> targetType;
private final MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context;
private final EntityInstantiator instantiator;
/**
* Creates a new {@link Converter} to instantiate DTOs.
*
* @param dtoType must not be {@literal null}.
* @param context must not be {@literal null}.
* @param instantiators must not be {@literal null}.
*/
public DtoInstantiatingConverter(Class<?> dtoType,
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> context,
EntityInstantiators instantiator) {
Assert.notNull(dtoType, "DTO type must not be null!");
Assert.notNull(context, "MappingContext must not be null!");
Assert.notNull(instantiator, "EntityInstantiators must not be null!");
this.targetType = dtoType;
this.context = context;
this.instantiator = instantiator.getInstantiatorFor(context.getPersistentEntity(dtoType));
}
/*
* (non-Javadoc)
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public Object convert(Object source) {
if (targetType.isInterface()) {
return source;
}
final PersistentEntity<?, ?> sourceEntity = context.getPersistentEntity(source.getClass());
final PersistentPropertyAccessor sourceAccessor = sourceEntity.getPropertyAccessor(source);
final PersistentEntity<?, ?> targetEntity = context.getPersistentEntity(targetType);
final PreferredConstructor<?, ? extends PersistentProperty<?>> constructor = targetEntity
.getPersistenceConstructor();
@SuppressWarnings({ "rawtypes", "unchecked" })
Object dto = instantiator.createInstance(targetEntity, new ParameterValueProvider() {
@Override
public Object getParameterValue(Parameter parameter) {
return sourceAccessor.getProperty(sourceEntity.getPersistentProperty(parameter.getName()));
}
});
final PersistentPropertyAccessor dtoAccessor = targetEntity.getPropertyAccessor(dto);
targetEntity.doWithProperties(new SimplePropertyHandler() {
@Override
public void doWithPersistentProperty(PersistentProperty<?> property) {
if (constructor.isConstructorParameter(property)) {
return;
}
dtoAccessor.setProperty(property,
sourceAccessor.getProperty(sourceEntity.getPersistentProperty(property.getName())));
}
});
return dto;
}
}

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

@ -169,32 +169,31 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> { @@ -169,32 +169,31 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
* @param parameters
* @return
*/
private Criteria from(Part part, MongoPersistentProperty property, Criteria criteria,
PotentiallyConvertingIterator parameters) {
private Criteria from(Part part, MongoPersistentProperty property, Criteria criteria, Iterator<Object> parameters) {
Type type = part.getType();
switch (type) {
case AFTER:
case GREATER_THAN:
return criteria.gt(parameters.nextConverted(property));
return criteria.gt(parameters.next());
case GREATER_THAN_EQUAL:
return criteria.gte(parameters.nextConverted(property));
return criteria.gte(parameters.next());
case BEFORE:
case LESS_THAN:
return criteria.lt(parameters.nextConverted(property));
return criteria.lt(parameters.next());
case LESS_THAN_EQUAL:
return criteria.lte(parameters.nextConverted(property));
return criteria.lte(parameters.next());
case BETWEEN:
return criteria.gt(parameters.nextConverted(property)).lt(parameters.nextConverted(property));
return criteria.gt(parameters.next()).lt(parameters.next());
case IS_NOT_NULL:
return criteria.ne(null);
case IS_NULL:
return criteria.is(null);
case NOT_IN:
return criteria.nin(nextAsArray(parameters, property));
return criteria.nin(nextAsArray(parameters));
case IN:
return criteria.in(nextAsArray(parameters, property));
return criteria.in(nextAsArray(parameters));
case LIKE:
case STARTING_WITH:
case ENDING_WITH:
@ -241,12 +240,12 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> { @@ -241,12 +240,12 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
return criteria.within((Shape) parameter);
case SIMPLE_PROPERTY:
return isSimpleComparisionPossible(part) ? criteria.is(parameters.nextConverted(property))
return isSimpleComparisionPossible(part) ? criteria.is(parameters.next())
: createLikeRegexCriteriaOrThrow(part, property, criteria, parameters, false);
case NEGATING_SIMPLE_PROPERTY:
return isSimpleComparisionPossible(part) ? criteria.ne(parameters.nextConverted(property))
return isSimpleComparisionPossible(part) ? criteria.ne(parameters.next())
: createLikeRegexCriteriaOrThrow(part, property, criteria, parameters, true);
default:
throw new IllegalArgumentException("Unsupported keyword!");
@ -278,7 +277,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> { @@ -278,7 +277,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
* @return the criteria extended with the like-regex.
*/
private Criteria createLikeRegexCriteriaOrThrow(Part part, MongoPersistentProperty property, Criteria criteria,
PotentiallyConvertingIterator parameters, boolean shouldNegateExpression) {
Iterator<Object> parameters, boolean shouldNegateExpression) {
PropertyPath path = part.getProperty().getLeafProperty();
@ -297,7 +296,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> { @@ -297,7 +296,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
criteria = criteria.not();
}
return addAppropriateLikeRegexTo(criteria, part, parameters.nextConverted(property).toString());
return addAppropriateLikeRegexTo(criteria, part, parameters.next().toString());
case NEVER:
// intentional no-op
@ -319,10 +318,10 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> { @@ -319,10 +318,10 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
* @return
*/
private Criteria createContainingCriteria(Part part, MongoPersistentProperty property, Criteria criteria,
PotentiallyConvertingIterator parameters) {
Iterator<Object> parameters) {
if (property.isCollectionLike()) {
return criteria.in(nextAsArray(parameters, property));
return criteria.in(nextAsArray(parameters));
}
return addAppropriateLikeRegexTo(criteria, part, parameters.next().toString());
@ -377,8 +376,9 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> { @@ -377,8 +376,9 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
String.format("Expected parameter type of %s but got %s!", type, parameter.getClass()));
}
private Object[] nextAsArray(PotentiallyConvertingIterator iterator, MongoPersistentProperty property) {
Object next = iterator.nextConverted(property);
private Object[] nextAsArray(Iterator<Object> iterator) {
Object next = iterator.next();
if (next instanceof Collection) {
return ((Collection<?>) next).toArray();

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

@ -0,0 +1,381 @@ @@ -0,0 +1,381 @@
/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.repository.query;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.EntityInstantiators;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Range;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoPage;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.util.CloseableIterator;
import org.springframework.data.util.StreamUtils;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.ClassUtils;
import com.mongodb.WriteResult;
interface MongoQueryExecution {
Object execute(Query query, Class<?> type, String collection);
/**
* {@link MongoQueryExecution} for collection returning queries.
*
* @author Oliver Gierke
*/
@RequiredArgsConstructor
static final class CollectionExecution implements MongoQueryExecution {
private final @NonNull MongoOperations operations;
private final Pageable pageable;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
*/
@Override
public Object execute(Query query, Class<?> type, String collection) {
return operations.find(query.with(pageable), type, collection);
}
}
/**
* {@link MongoQueryExecution} for {@link Slice} query methods.
*
* @author Oliver Gierke
* @author Christoph Strobl
* @since 1.5
*/
@RequiredArgsConstructor
static final class SlicedExecution implements MongoQueryExecution {
private final @NonNull MongoOperations operations;
private final @NonNull Pageable pageable;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
*/
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public Object execute(Query query, Class<?> type, String collection) {
int pageSize = pageable.getPageSize();
// Apply Pageable but tweak limit to peek into next page
Query modifiedQuery = query.with(pageable).limit(pageSize + 1);
List result = operations.find(modifiedQuery, type, collection);
boolean hasNext = result.size() > pageSize;
return new SliceImpl<Object>(hasNext ? result.subList(0, pageSize) : result, pageable, hasNext);
}
}
/**
* {@link MongoQueryExecution} for pagination queries.
*
* @author Oliver Gierke
*/
@RequiredArgsConstructor
static final class PagedExecution implements MongoQueryExecution {
private final @NonNull MongoOperations operations;
private final @NonNull Pageable pageable;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
*/
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public Object execute(Query query, Class<?> type, String collection) {
int overallLimit = query.getLimit();
long count = operations.count(query, type, collection);
count = overallLimit != 0 ? Math.min(count, query.getLimit()) : count;
boolean pageableOutOfScope = pageable.getOffset() > count;
if (pageableOutOfScope) {
return new PageImpl<Object>(Collections.emptyList(), pageable, count);
}
// Apply raw pagination
query = query.with(pageable);
// Adjust limit if page would exceed the overall limit
if (overallLimit != 0 && pageable.getOffset() + pageable.getPageSize() > overallLimit) {
query.limit(overallLimit - pageable.getOffset());
}
List<?> result = operations.find(query, type, collection);
return new PageImpl(result, pageable, count);
}
}
/**
* {@link MongoQueryExecution} to return a single entity.
*
* @author Oliver Gierke
*/
@RequiredArgsConstructor
static final class SingleEntityExecution implements MongoQueryExecution {
private final MongoOperations operations;
private final boolean countProjection;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
*/
@Override
public Object execute(Query query, Class<?> type, String collection) {
return countProjection ? operations.count(query, type, collection) : operations.findOne(query, type, collection);
}
}
/**
* {@link MongoQueryExecution} to execute geo-near queries.
*
* @author Oliver Gierke
*/
@RequiredArgsConstructor
static class GeoNearExecution implements MongoQueryExecution {
private final MongoOperations operations;
private final MongoParameterAccessor accessor;
private final TypeInformation<?> returnType;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
*/
@Override
public Object execute(Query query, Class<?> type, String collection) {
GeoResults<?> results = doExecuteQuery(query, type, collection);
return isListOfGeoResult() ? results.getContent() : results;
}
@SuppressWarnings("unchecked")
protected GeoResults<Object> doExecuteQuery(Query query, Class<?> type, String collection) {
Point nearLocation = accessor.getGeoNearLocation();
NearQuery nearQuery = NearQuery.near(nearLocation);
if (query != null) {
nearQuery.query(query);
}
Range<Distance> distances = accessor.getDistanceRange();
Distance maxDistance = distances.getUpperBound();
if (maxDistance != null) {
nearQuery.maxDistance(maxDistance).in(maxDistance.getMetric());
}
Distance minDistance = distances.getLowerBound();
if (minDistance != null) {
nearQuery.minDistance(minDistance).in(minDistance.getMetric());
}
Pageable pageable = accessor.getPageable();
if (pageable != null) {
nearQuery.with(pageable);
}
return (GeoResults<Object>) operations.geoNear(nearQuery, type, collection);
}
private boolean isListOfGeoResult() {
if (!returnType.getType().equals(List.class)) {
return false;
}
TypeInformation<?> componentType = returnType.getComponentType();
return componentType == null ? false : GeoResult.class.equals(componentType.getType());
}
}
static final class PagingGeoNearExecution extends GeoNearExecution {
private final MongoOperations operations;
private final MongoParameterAccessor accessor;
private final AbstractMongoQuery mongoQuery;
public PagingGeoNearExecution(MongoOperations operations, MongoParameterAccessor accessor,
TypeInformation<?> returnType, AbstractMongoQuery query) {
super(operations, accessor, returnType);
this.accessor = accessor;
this.operations = operations;
this.mongoQuery = query;
}
/**
* Executes the given {@link Query} to return a page.
*
* @param query must not be {@literal null}.
* @param countQuery must not be {@literal null}.
* @return
*/
@Override
public Object execute(Query query, Class<?> type, String collection) {
ConvertingParameterAccessor parameterAccessor = new ConvertingParameterAccessor(operations.getConverter(),
accessor);
Query countQuery = mongoQuery.applyQueryMetaAttributesWhenPresent(mongoQuery.createCountQuery(parameterAccessor));
long count = operations.count(countQuery, collection);
return new GeoPage<Object>(doExecuteQuery(query, type, collection), accessor.getPageable(), count);
}
}
/**
* {@link MongoQueryExecution} removing documents matching the query.
*
* @since 1.5
*/
@RequiredArgsConstructor
static final class DeleteExecution implements MongoQueryExecution {
private final MongoOperations operations;
private final MongoQueryMethod method;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
*/
@Override
public Object execute(Query query, Class<?> type, String collection) {
if (method.isCollectionQuery()) {
return operations.findAllAndRemove(query, type, collection);
}
WriteResult writeResult = operations.remove(query, type, collection);
return writeResult != null ? writeResult.getN() : 0L;
}
}
/**
* @author Thomas Darimont
* @since 1.7
*/
@RequiredArgsConstructor
static final class StreamExecution implements MongoQueryExecution {
private final @NonNull MongoOperations operations;
private final @NonNull Converter<Object, Object> resultProcessing;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
*/
@Override
@SuppressWarnings("unchecked")
public Object execute(Query query, Class<?> type, String collection) {
return StreamUtils.createStreamFromIterator((CloseableIterator<Object>) operations.stream(query, type))
.map(new Function<Object, Object>() {
@Override
public Object apply(Object t) {
return resultProcessing.convert(t);
}
});
}
}
/**
* An {@link MongoQueryExecution} that wraps the results of the given delegate with the given result processing.
*
* @author Oliver Gierke
* @since 1.9
*/
@RequiredArgsConstructor
static final class ResultProcessingExecution implements MongoQueryExecution {
private final @NonNull MongoQueryExecution delegate;
private final @NonNull Converter<Object, Object> converter;
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
*/
@Override
public Object execute(Query query, Class<?> type, String collection) {
return converter.convert(delegate.execute(query, type, collection));
}
}
/**
* A {@link Converter} to post-process all source objects using the given {@link ResultProcessor}.
*
* @author Oliver Gierke
* @since 1.9
*/
@RequiredArgsConstructor
static final class ResultProcessingConverter implements Converter<Object, Object> {
private final @NonNull ResultProcessor processor;
private final @NonNull MongoOperations operations;
private final @NonNull EntityInstantiators instantiators;
/*
* (non-Javadoc)
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public Object convert(Object source) {
ReturnedType returnedType = processor.getReturnedType();
if (ClassUtils.isPrimitiveOrWrapper(returnedType.getReturnedType())) {
return source;
}
Converter<Object, Object> converter = new DtoInstantiatingConverter(returnedType.getReturnedType(),
operations.getConverter().getMappingContext(), instantiators);
return processor.processResult(source, converter);
}
}
}

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

@ -136,7 +136,8 @@ public class MongoQueryMethod extends QueryMethod { @@ -136,7 +136,8 @@ public class MongoQueryMethod extends QueryMethod {
MongoPersistentEntity<?> returnedEntity = mappingContext.getPersistentEntity(returnedObjectType);
MongoPersistentEntity<?> managedEntity = mappingContext.getPersistentEntity(domainClass);
returnedEntity = returnedEntity == null ? managedEntity : returnedEntity;
returnedEntity = returnedEntity == null || returnedEntity.getType().isInterface() ? managedEntity
: returnedEntity;
MongoPersistentEntity<?> collectionEntity = domainClass.isAssignableFrom(returnedObjectType) ? returnedEntity
: managedEntity;

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

@ -44,6 +44,7 @@ public class PartTreeMongoQuery extends AbstractMongoQuery { @@ -44,6 +44,7 @@ public class PartTreeMongoQuery extends AbstractMongoQuery {
private final PartTree tree;
private final boolean isGeoNearQuery;
private final MappingContext<?, MongoPersistentProperty> context;
private final ResultProcessor processor;
/**
* Creates a new {@link PartTreeMongoQuery} from the given {@link QueryMethod} and {@link MongoTemplate}.
@ -54,7 +55,9 @@ public class PartTreeMongoQuery extends AbstractMongoQuery { @@ -54,7 +55,9 @@ public class PartTreeMongoQuery extends AbstractMongoQuery {
public PartTreeMongoQuery(MongoQueryMethod method, MongoOperations mongoOperations) {
super(method, mongoOperations);
this.tree = new PartTree(method.getName(), method.getEntityInformation().getJavaType());
this.processor = method.getResultProcessor();
this.tree = new PartTree(method.getName(), processor.getReturnedType().getDomainType());
this.isGeoNearQuery = method.isGeoNearQuery();
this.context = mongoOperations.getConverter().getMappingContext();
}
@ -91,7 +94,6 @@ public class PartTreeMongoQuery extends AbstractMongoQuery { @@ -91,7 +94,6 @@ public class PartTreeMongoQuery extends AbstractMongoQuery {
if (!StringUtils.hasText(fieldSpec)) {
ResultProcessor processor = getQueryMethod().getResultProcessor();
ReturnedType returnedType = processor.withDynamicProjection(accessor).getReturnedType();
if (returnedType.isProjecting()) {

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

@ -54,7 +54,7 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport { @@ -54,7 +54,7 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
private static final SpelExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
private final MongoOperations mongoOperations;
private final MongoOperations operations;
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
/**
@ -66,7 +66,7 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport { @@ -66,7 +66,7 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
Assert.notNull(mongoOperations);
this.mongoOperations = mongoOperations;
this.operations = mongoOperations;
this.mappingContext = mongoOperations.getConverter().getMappingContext();
}
@ -92,7 +92,7 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport { @@ -92,7 +92,7 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
MongoEntityInformation<?, Serializable> entityInformation = getEntityInformation(information.getDomainType(),
information);
return getTargetRepositoryViaReflection(information, entityInformation, mongoOperations);
return getTargetRepositoryViaReflection(information, entityInformation, operations);
}
/*
@ -101,7 +101,7 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport { @@ -101,7 +101,7 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
*/
@Override
protected QueryLookupStrategy getQueryLookupStrategy(Key key, EvaluationContextProvider evaluationContextProvider) {
return new MongoQueryLookupStrategy(evaluationContextProvider);
return new MongoQueryLookupStrategy(operations, evaluationContextProvider, mappingContext);
}
/*
@ -133,12 +133,18 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport { @@ -133,12 +133,18 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
* @author Oliver Gierke
* @author Thomas Darimont
*/
private class MongoQueryLookupStrategy implements QueryLookupStrategy {
private static class MongoQueryLookupStrategy implements QueryLookupStrategy {
private final MongoOperations operations;
private final EvaluationContextProvider evaluationContextProvider;
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
public MongoQueryLookupStrategy(EvaluationContextProvider evaluationContextProvider) {
public MongoQueryLookupStrategy(MongoOperations operations, EvaluationContextProvider evaluationContextProvider,
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
this.operations = operations;
this.evaluationContextProvider = evaluationContextProvider;
this.mappingContext = mappingContext;
}
/*
@ -154,12 +160,12 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport { @@ -154,12 +160,12 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
if (namedQueries.hasQuery(namedQueryName)) {
String namedQuery = namedQueries.getQuery(namedQueryName);
return new StringBasedMongoQuery(namedQuery, queryMethod, mongoOperations, EXPRESSION_PARSER,
return new StringBasedMongoQuery(namedQuery, queryMethod, operations, EXPRESSION_PARSER,
evaluationContextProvider);
} else if (queryMethod.hasAnnotatedQuery()) {
return new StringBasedMongoQuery(queryMethod, mongoOperations, EXPRESSION_PARSER, evaluationContextProvider);
return new StringBasedMongoQuery(queryMethod, operations, EXPRESSION_PARSER, evaluationContextProvider);
} else {
return new PartTreeMongoQuery(queryMethod, mongoOperations);
return new PartTreeMongoQuery(queryMethod, operations);
}
}
}

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

@ -17,8 +17,6 @@ package org.springframework.data.mongodb.repository.query; @@ -17,8 +17,6 @@ package org.springframework.data.mongodb.repository.query;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.Query.*;
@ -27,16 +25,11 @@ import static org.springframework.data.mongodb.repository.query.StubParameterAcc @@ -27,16 +25,11 @@ import static org.springframework.data.mongodb.repository.query.StubParameterAcc
import java.lang.reflect.Method;
import java.util.List;
import org.bson.types.ObjectId;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.data.domain.Range;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics;
@ -44,14 +37,19 @@ import org.springframework.data.geo.Point; @@ -44,14 +37,19 @@ import org.springframework.data.geo.Point;
import org.springframework.data.geo.Polygon;
import org.springframework.data.geo.Shape;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.Person;
import org.springframework.data.mongodb.core.Venue;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
@ -59,7 +57,8 @@ import org.springframework.data.projection.SpelAwareProxyProjectionFactory; @@ -59,7 +57,8 @@ import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.data.util.TypeInformation;
import com.mongodb.DBObject;
/**
* Unit test for {@link MongoQueryCreator}.
@ -68,14 +67,12 @@ import org.springframework.data.util.TypeInformation; @@ -68,14 +67,12 @@ import org.springframework.data.util.TypeInformation;
* @author Thomas Darimont
* @author Christoph Strobl
*/
@RunWith(MockitoJUnitRunner.class)
public class MongoQueryCreatorUnitTests {
Method findByFirstname, findByFirstnameAndFriend, findByFirstnameNotNull;
@Mock MongoConverter converter;
MappingContext<?, MongoPersistentProperty> context;
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> context;
MongoConverter converter;
@Rule public ExpectedException expection = ExpectedException.none();
@ -84,11 +81,8 @@ public class MongoQueryCreatorUnitTests { @@ -84,11 +81,8 @@ public class MongoQueryCreatorUnitTests {
context = new MongoMappingContext();
doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
return invocation.getArguments()[0];
}
}).when(converter).convertToMongoType(any(), Mockito.any(TypeInformation.class));
DbRefResolver resolver = new DefaultDbRefResolver(mock(MongoDbFactory.class));
converter = new MappingMongoConverter(resolver, context);
}
@Test
@ -243,14 +237,13 @@ public class MongoQueryCreatorUnitTests { @@ -243,14 +237,13 @@ public class MongoQueryCreatorUnitTests {
public void createsQueryReferencingADBRefCorrectly() {
User user = new User();
com.mongodb.DBRef dbref = new com.mongodb.DBRef("user", "id");
when(converter.toDBRef(eq(user), Mockito.any(MongoPersistentProperty.class))).thenReturn(dbref);
user.id = new ObjectId();
PartTree tree = new PartTree("findByCreator", User.class);
MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, user), context);
Query query = creator.createQuery();
DBObject queryObject = creator.createQuery().getQueryObject();
assertThat(query, is(query(where("creator").is(dbref))));
assertThat(queryObject.get("creator"), is((Object) user));
}
/**
@ -294,8 +287,6 @@ public class MongoQueryCreatorUnitTests { @@ -294,8 +287,6 @@ public class MongoQueryCreatorUnitTests {
private void assertBindsDistanceToQuery(Point point, Distance distance, Query reference) throws Exception {
when(converter.convertToMongoType("Dave")).thenReturn("Dave");
PartTree tree = new PartTree("findByLocationNearAndFirstname",
org.springframework.data.mongodb.repository.Person.class);
Method method = PersonRepository.class.getMethod("findByLocationNearAndFirstname", Point.class, Distance.class,
@ -684,6 +675,8 @@ public class MongoQueryCreatorUnitTests { @@ -684,6 +675,8 @@ public class MongoQueryCreatorUnitTests {
class User {
ObjectId id;
@Field("foo") String username;
@DBRef User creator;

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

@ -173,7 +173,7 @@ public class PartTreeMongoQueryUnitTests { @@ -173,7 +173,7 @@ public class PartTreeMongoQueryUnitTests {
@Test
public void restrictsQueryToFieldsRequiredForDto() {
DBObject fieldsObject = deriveQueryFromMethod("findPersonDtoBy", new Object[0]).getFieldsObject();
DBObject fieldsObject = deriveQueryFromMethod("findPersonDtoByAge", new Object[] { 42 }).getFieldsObject();
assertThat(fieldsObject.get("firstname"), is((Object) 1));
assertThat(fieldsObject.get("lastname"), is((Object) 1));
@ -246,7 +246,7 @@ public class PartTreeMongoQueryUnitTests { @@ -246,7 +246,7 @@ public class PartTreeMongoQueryUnitTests {
PersonProjection findPersonProjectedBy();
PersonDto findPersonDtoBy();
PersonDto findPersonDtoByAge(Integer age);
<T> T findDynamicallyProjectedBy(Class<T> type);
}

2
spring-data-mongodb/template.mf

@ -2,6 +2,8 @@ Bundle-SymbolicName: org.springframework.data.mongodb @@ -2,6 +2,8 @@ Bundle-SymbolicName: org.springframework.data.mongodb
Bundle-Name: Spring Data MongoDB Support
Bundle-Vendor: Pivotal Software, Inc.
Bundle-ManifestVersion: 2
Excluded-Imports:
lombok.*
Import-Package:
sun.reflect;version="0";resolution:=optional
Export-Template:

Loading…
Cancel
Save