Skip to content

Commit 9a3a38d

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 8b3e4d4 commit 9a3a38d

File tree

1 file changed

+29
-17
lines changed

1 file changed

+29
-17
lines changed

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

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@
3030
import org.springframework.data.mapping.PropertyPath;
3131
import org.springframework.data.querydsl.EntityPathResolver;
3232
import org.springframework.data.util.TypeInformation;
33+
import org.springframework.lang.Nullable;
3334
import org.springframework.util.Assert;
35+
import org.springframework.util.ClassUtils;
3436
import org.springframework.util.MultiValueMap;
35-
import org.springframework.util.StringUtils;
37+
import org.springframework.util.ObjectUtils;
3638

3739
import com.querydsl.core.BooleanBuilder;
3840
import com.querydsl.core.types.Path;
@@ -79,8 +81,7 @@ public QuerydslPredicateBuilder(ConversionService conversionService, EntityPathR
7981
* @param bindings the {@link QuerydslBindings} for the predicate.
8082
* @return the {@link Predicate}.
8183
*/
82-
public Predicate getPredicate(TypeInformation<?> type, MultiValueMap<String, String> values,
83-
QuerydslBindings bindings) {
84+
public Predicate getPredicate(TypeInformation<?> type, MultiValueMap<String, ?> values, QuerydslBindings bindings) {
8485

8586
Assert.notNull(bindings, "Context must not be null!");
8687

@@ -92,7 +93,7 @@ public Predicate getPredicate(TypeInformation<?> type, MultiValueMap<String, Str
9293

9394
for (var entry : values.entrySet()) {
9495

95-
if (isSingleElementCollectionWithoutText(entry.getValue())) {
96+
if (isSingleElementCollectionWithEmptyItem(entry.getValue())) {
9697
continue;
9798
}
9899

@@ -163,33 +164,44 @@ private Path<?> getPath(PathInformation path, QuerydslBindings bindings) {
163164

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

175176
var targetType = path.getLeafType();
176177

177-
if (source.isEmpty() || isSingleElementCollectionWithoutText(source)) {
178+
if (source.isEmpty() || isSingleElementCollectionWithEmptyItem(source)) {
178179
return Collections.emptyList();
179180
}
180181

181182
Collection<Object> target = new ArrayList<>(source.size());
182183

183184
for (var value : source) {
184-
185-
target.add(conversionService.canConvert(String.class, targetType)
186-
? conversionService.convert(value, TypeDescriptor.forObject(value), getTargetTypeDescriptor(path))
187-
: value);
185+
target.add(getValue(path, targetType, value));
188186
}
189187

190188
return target;
191189
}
192190

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

213225
if (result == null) {
214-
throw new IllegalStateException(String.format("Could not obtain TypeDesciptor for PathInformation %s!", path));
226+
throw new IllegalStateException(String.format("Could not obtain TypeDescriptor for PathInformation %s!", path));
215227
}
216228

217229
return result;
218230
}
219231

220232
/**
221-
* Returns whether the given collection has exactly one element that doesn't contain any text. This is basically an
222-
* indicator that a request parameter has been submitted but no value for it.
233+
* Returns whether the given collection has exactly one element that is empty (i.e. doesn't contain text). This is
234+
* basically an indicator that a request parameter has been submitted but no value for it.
223235
*
224236
* @param source must not be {@literal null}.
225237
* @return
226238
*/
227-
private static boolean isSingleElementCollectionWithoutText(List<String> source) {
228-
return source.size() == 1 && !StringUtils.hasLength(source.get(0));
239+
private static boolean isSingleElementCollectionWithEmptyItem(List<?> source) {
240+
return source.size() == 1 && ObjectUtils.isEmpty(source.get(0));
229241
}
230242

231243
/**

0 commit comments

Comments
 (0)