Skip to content

Commit 53d924c

Browse files
committed
Accept Object values in QuerydslPredicateBuilder.
We now accept Object-typed values to allow broader reuse of QuerydslPredicateBuilder. The conversion into the actual value considers the origin type and checks assignability before employing the ConversionService. Closes #2573
1 parent 302bcca commit 53d924c

File tree

1 file changed

+31
-19
lines changed

1 file changed

+31
-19
lines changed

src/main/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilder.java

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@
3232
import org.springframework.data.mapping.PropertyPath;
3333
import org.springframework.data.querydsl.EntityPathResolver;
3434
import org.springframework.data.util.TypeInformation;
35+
import org.springframework.lang.Nullable;
3536
import org.springframework.util.Assert;
37+
import org.springframework.util.ClassUtils;
3638
import org.springframework.util.MultiValueMap;
37-
import org.springframework.util.StringUtils;
39+
import org.springframework.util.ObjectUtils;
3840

3941
import com.querydsl.core.BooleanBuilder;
4042
import com.querydsl.core.types.Path;
@@ -81,8 +83,7 @@ public QuerydslPredicateBuilder(ConversionService conversionService, EntityPathR
8183
* @param bindings the {@link QuerydslBindings} for the predicate.
8284
* @return the {@link Predicate}.
8385
*/
84-
public Predicate getPredicate(TypeInformation<?> type, MultiValueMap<String, String> values,
85-
QuerydslBindings bindings) {
86+
public Predicate getPredicate(TypeInformation<?> type, MultiValueMap<String, ?> values, QuerydslBindings bindings) {
8687

8788
Assert.notNull(bindings, "Context must not be null!");
8889

@@ -92,9 +93,9 @@ public Predicate getPredicate(TypeInformation<?> type, MultiValueMap<String, Str
9293
return getPredicate(builder);
9394
}
9495

95-
for (Entry<String, List<String>> entry : values.entrySet()) {
96+
for (Entry<String, ? extends List<?>> entry : values.entrySet()) {
9697

97-
if (isSingleElementCollectionWithoutText(entry.getValue())) {
98+
if (isSingleElementCollectionWithEmptyItem(entry.getValue())) {
9899
continue;
99100
}
100101

@@ -165,33 +166,44 @@ private Path<?> getPath(PathInformation path, QuerydslBindings bindings) {
165166

166167
/**
167168
* Converts the given source values into a collection of elements that are of the given {@link PropertyPath}'s type.
168-
* Considers a single element list with an empty {@link String} an empty collection because this basically indicates
169-
* the property having been submitted but no value provided.
169+
* Considers a single element list with an empty object an empty collection because this basically indicates the
170+
* property having been submitted but no value provided.
170171
*
171172
* @param source must not be {@literal null}.
172173
* @param path must not be {@literal null}.
173174
* @return
174175
*/
175-
private Collection<Object> convertToPropertyPathSpecificType(List<String> source, PathInformation path) {
176+
private Collection<Object> convertToPropertyPathSpecificType(List<?> source, PathInformation path) {
176177

177178
Class<?> targetType = path.getLeafType();
178179

179-
if (source.isEmpty() || isSingleElementCollectionWithoutText(source)) {
180+
if (source.isEmpty() || isSingleElementCollectionWithEmptyItem(source)) {
180181
return Collections.emptyList();
181182
}
182183

183184
Collection<Object> target = new ArrayList<>(source.size());
184185

185-
for (String value : source) {
186-
187-
target.add(conversionService.canConvert(String.class, targetType)
188-
? conversionService.convert(value, TypeDescriptor.forObject(value), getTargetTypeDescriptor(path))
189-
: value);
186+
for (Object value : source) {
187+
target.add(getValue(path, targetType, value));
190188
}
191189

192190
return target;
193191
}
194192

193+
@Nullable
194+
private Object getValue(PathInformation path, Class<?> targetType, Object value) {
195+
196+
if (ClassUtils.isAssignableValue(targetType, value)) {
197+
return value;
198+
}
199+
200+
if (conversionService.canConvert(value.getClass(), targetType)) {
201+
return conversionService.convert(value, TypeDescriptor.forObject(value), getTargetTypeDescriptor(path));
202+
}
203+
204+
return value;
205+
}
206+
195207
/**
196208
* Returns the target {@link TypeDescriptor} for the given {@link PathInformation} by either inspecting the field or
197209
* property (the latter preferred) to pick up annotations potentially defined for formatting purposes.
@@ -213,21 +225,21 @@ private static TypeDescriptor getTargetTypeDescriptor(PathInformation path) {
213225
.nested(new Property(owningType, descriptor.getReadMethod(), descriptor.getWriteMethod(), leafProperty), 0);
214226

215227
if (result == null) {
216-
throw new IllegalStateException(String.format("Could not obtain TypeDesciptor for PathInformation %s!", path));
228+
throw new IllegalStateException(String.format("Could not obtain TypeDescriptor for PathInformation %s!", path));
217229
}
218230

219231
return result;
220232
}
221233

222234
/**
223-
* Returns whether the given collection has exactly one element that doesn't contain any text. This is basically an
224-
* indicator that a request parameter has been submitted but no value for it.
235+
* Returns whether the given collection has exactly one element that is empty (i.e. doesn't contain text). This is
236+
* basically an indicator that a request parameter has been submitted but no value for it.
225237
*
226238
* @param source must not be {@literal null}.
227239
* @return
228240
*/
229-
private static boolean isSingleElementCollectionWithoutText(List<String> source) {
230-
return source.size() == 1 && !StringUtils.hasLength(source.get(0));
241+
private static boolean isSingleElementCollectionWithEmptyItem(List<?> source) {
242+
return source.size() == 1 && ObjectUtils.isEmpty(source.get(0));
231243
}
232244

233245
/**

0 commit comments

Comments
 (0)