Skip to content

Commit f10e5a1

Browse files
committed
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.
1 parent 90a4a63 commit f10e5a1

File tree

10 files changed

+601
-382
lines changed

10 files changed

+601
-382
lines changed

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

Lines changed: 53 additions & 327 deletions
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright 2015-2016 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.repository.query;
17+
18+
import org.springframework.core.convert.converter.Converter;
19+
import org.springframework.data.convert.EntityInstantiator;
20+
import org.springframework.data.convert.EntityInstantiators;
21+
import org.springframework.data.mapping.PersistentEntity;
22+
import org.springframework.data.mapping.PersistentProperty;
23+
import org.springframework.data.mapping.PersistentPropertyAccessor;
24+
import org.springframework.data.mapping.PreferredConstructor;
25+
import org.springframework.data.mapping.PreferredConstructor.Parameter;
26+
import org.springframework.data.mapping.SimplePropertyHandler;
27+
import org.springframework.data.mapping.context.MappingContext;
28+
import org.springframework.data.mapping.model.ParameterValueProvider;
29+
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
30+
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
31+
import org.springframework.util.Assert;
32+
33+
/**
34+
* {@link Converter} to instantiate DTOs from fully equipped domain objects.
35+
*
36+
* @author Oliver Gierke
37+
*/
38+
class DtoInstantiatingConverter implements Converter<Object, Object> {
39+
40+
private final Class<?> targetType;
41+
private final MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context;
42+
private final EntityInstantiator instantiator;
43+
44+
/**
45+
* Creates a new {@link Converter} to instantiate DTOs.
46+
*
47+
* @param dtoType must not be {@literal null}.
48+
* @param context must not be {@literal null}.
49+
* @param instantiators must not be {@literal null}.
50+
*/
51+
public DtoInstantiatingConverter(Class<?> dtoType,
52+
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> context,
53+
EntityInstantiators instantiator) {
54+
55+
Assert.notNull(dtoType, "DTO type must not be null!");
56+
Assert.notNull(context, "MappingContext must not be null!");
57+
Assert.notNull(instantiator, "EntityInstantiators must not be null!");
58+
59+
this.targetType = dtoType;
60+
this.context = context;
61+
this.instantiator = instantiator.getInstantiatorFor(context.getPersistentEntity(dtoType));
62+
}
63+
64+
/*
65+
* (non-Javadoc)
66+
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
67+
*/
68+
@Override
69+
public Object convert(Object source) {
70+
71+
if (targetType.isInterface()) {
72+
return source;
73+
}
74+
75+
final PersistentEntity<?, ?> sourceEntity = context.getPersistentEntity(source.getClass());
76+
final PersistentPropertyAccessor sourceAccessor = sourceEntity.getPropertyAccessor(source);
77+
final PersistentEntity<?, ?> targetEntity = context.getPersistentEntity(targetType);
78+
final PreferredConstructor<?, ? extends PersistentProperty<?>> constructor = targetEntity
79+
.getPersistenceConstructor();
80+
81+
@SuppressWarnings({ "rawtypes", "unchecked" })
82+
Object dto = instantiator.createInstance(targetEntity, new ParameterValueProvider() {
83+
84+
@Override
85+
public Object getParameterValue(Parameter parameter) {
86+
return sourceAccessor.getProperty(sourceEntity.getPersistentProperty(parameter.getName()));
87+
}
88+
});
89+
90+
final PersistentPropertyAccessor dtoAccessor = targetEntity.getPropertyAccessor(dto);
91+
92+
targetEntity.doWithProperties(new SimplePropertyHandler() {
93+
94+
@Override
95+
public void doWithPersistentProperty(PersistentProperty<?> property) {
96+
97+
if (constructor.isConstructorParameter(property)) {
98+
return;
99+
}
100+
101+
dtoAccessor.setProperty(property,
102+
sourceAccessor.getProperty(sourceEntity.getPersistentProperty(property.getName())));
103+
}
104+
});
105+
106+
return dto;
107+
}
108+
}

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

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -169,32 +169,31 @@ protected Query complete(Criteria criteria, Sort sort) {
169169
* @param parameters
170170
* @return
171171
*/
172-
private Criteria from(Part part, MongoPersistentProperty property, Criteria criteria,
173-
PotentiallyConvertingIterator parameters) {
172+
private Criteria from(Part part, MongoPersistentProperty property, Criteria criteria, Iterator<Object> parameters) {
174173

175174
Type type = part.getType();
176175

177176
switch (type) {
178177
case AFTER:
179178
case GREATER_THAN:
180-
return criteria.gt(parameters.nextConverted(property));
179+
return criteria.gt(parameters.next());
181180
case GREATER_THAN_EQUAL:
182-
return criteria.gte(parameters.nextConverted(property));
181+
return criteria.gte(parameters.next());
183182
case BEFORE:
184183
case LESS_THAN:
185-
return criteria.lt(parameters.nextConverted(property));
184+
return criteria.lt(parameters.next());
186185
case LESS_THAN_EQUAL:
187-
return criteria.lte(parameters.nextConverted(property));
186+
return criteria.lte(parameters.next());
188187
case BETWEEN:
189-
return criteria.gt(parameters.nextConverted(property)).lt(parameters.nextConverted(property));
188+
return criteria.gt(parameters.next()).lt(parameters.next());
190189
case IS_NOT_NULL:
191190
return criteria.ne(null);
192191
case IS_NULL:
193192
return criteria.is(null);
194193
case NOT_IN:
195-
return criteria.nin(nextAsArray(parameters, property));
194+
return criteria.nin(nextAsArray(parameters));
196195
case IN:
197-
return criteria.in(nextAsArray(parameters, property));
196+
return criteria.in(nextAsArray(parameters));
198197
case LIKE:
199198
case STARTING_WITH:
200199
case ENDING_WITH:
@@ -241,12 +240,12 @@ private Criteria from(Part part, MongoPersistentProperty property, Criteria crit
241240
return criteria.within((Shape) parameter);
242241
case SIMPLE_PROPERTY:
243242

244-
return isSimpleComparisionPossible(part) ? criteria.is(parameters.nextConverted(property))
243+
return isSimpleComparisionPossible(part) ? criteria.is(parameters.next())
245244
: createLikeRegexCriteriaOrThrow(part, property, criteria, parameters, false);
246245

247246
case NEGATING_SIMPLE_PROPERTY:
248247

249-
return isSimpleComparisionPossible(part) ? criteria.ne(parameters.nextConverted(property))
248+
return isSimpleComparisionPossible(part) ? criteria.ne(parameters.next())
250249
: createLikeRegexCriteriaOrThrow(part, property, criteria, parameters, true);
251250
default:
252251
throw new IllegalArgumentException("Unsupported keyword!");
@@ -278,7 +277,7 @@ private boolean isSimpleComparisionPossible(Part part) {
278277
* @return the criteria extended with the like-regex.
279278
*/
280279
private Criteria createLikeRegexCriteriaOrThrow(Part part, MongoPersistentProperty property, Criteria criteria,
281-
PotentiallyConvertingIterator parameters, boolean shouldNegateExpression) {
280+
Iterator<Object> parameters, boolean shouldNegateExpression) {
282281

283282
PropertyPath path = part.getProperty().getLeafProperty();
284283

@@ -297,7 +296,7 @@ private Criteria createLikeRegexCriteriaOrThrow(Part part, MongoPersistentProper
297296
criteria = criteria.not();
298297
}
299298

300-
return addAppropriateLikeRegexTo(criteria, part, parameters.nextConverted(property).toString());
299+
return addAppropriateLikeRegexTo(criteria, part, parameters.next().toString());
301300

302301
case NEVER:
303302
// intentional no-op
@@ -319,10 +318,10 @@ private Criteria createLikeRegexCriteriaOrThrow(Part part, MongoPersistentProper
319318
* @return
320319
*/
321320
private Criteria createContainingCriteria(Part part, MongoPersistentProperty property, Criteria criteria,
322-
PotentiallyConvertingIterator parameters) {
321+
Iterator<Object> parameters) {
323322

324323
if (property.isCollectionLike()) {
325-
return criteria.in(nextAsArray(parameters, property));
324+
return criteria.in(nextAsArray(parameters));
326325
}
327326

328327
return addAppropriateLikeRegexTo(criteria, part, parameters.next().toString());
@@ -377,8 +376,9 @@ private <T> T nextAs(Iterator<Object> iterator, Class<T> type) {
377376
String.format("Expected parameter type of %s but got %s!", type, parameter.getClass()));
378377
}
379378

380-
private Object[] nextAsArray(PotentiallyConvertingIterator iterator, MongoPersistentProperty property) {
381-
Object next = iterator.nextConverted(property);
379+
private Object[] nextAsArray(Iterator<Object> iterator) {
380+
381+
Object next = iterator.next();
382382

383383
if (next instanceof Collection) {
384384
return ((Collection<?>) next).toArray();

0 commit comments

Comments
 (0)