Browse Source

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
pull/2574/head
Mark Paluch 4 years ago
parent
commit
9df8a32b85
No known key found for this signature in database
GPG Key ID: 4406B84C1661DCD1
  1. 50
      src/main/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilder.java

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

@ -32,9 +32,11 @@ import org.springframework.core.convert.TypeDescriptor; @@ -32,9 +32,11 @@ import org.springframework.core.convert.TypeDescriptor;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.util.ObjectUtils;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Path;
@ -81,8 +83,7 @@ public class QuerydslPredicateBuilder { @@ -81,8 +83,7 @@ public class QuerydslPredicateBuilder {
* @param bindings the {@link QuerydslBindings} for the predicate.
* @return the {@link Predicate}.
*/
public Predicate getPredicate(TypeInformation<?> type, MultiValueMap<String, String> values,
QuerydslBindings bindings) {
public Predicate getPredicate(TypeInformation<?> type, MultiValueMap<String, ?> values, QuerydslBindings bindings) {
Assert.notNull(bindings, "Context must not be null!");
@ -92,9 +93,9 @@ public class QuerydslPredicateBuilder { @@ -92,9 +93,9 @@ public class QuerydslPredicateBuilder {
return getPredicate(builder);
}
for (Entry<String, List<String>> entry : values.entrySet()) {
for (Entry<String, ? extends List<?>> entry : values.entrySet()) {
if (isSingleElementCollectionWithoutText(entry.getValue())) {
if (isSingleElementCollectionWithEmptyItem(entry.getValue())) {
continue;
}
@ -165,33 +166,44 @@ public class QuerydslPredicateBuilder { @@ -165,33 +166,44 @@ public class QuerydslPredicateBuilder {
/**
* Converts the given source values into a collection of elements that are of the given {@link PropertyPath}'s type.
* Considers a single element list with an empty {@link String} an empty collection because this basically indicates
* the property having been submitted but no value provided.
* Considers a single element list with an empty object an empty collection because this basically indicates the
* property having been submitted but no value provided.
*
* @param source must not be {@literal null}.
* @param path must not be {@literal null}.
* @return
*/
private Collection<Object> convertToPropertyPathSpecificType(List<String> source, PathInformation path) {
private Collection<Object> convertToPropertyPathSpecificType(List<?> source, PathInformation path) {
Class<?> targetType = path.getLeafType();
if (source.isEmpty() || isSingleElementCollectionWithoutText(source)) {
if (source.isEmpty() || isSingleElementCollectionWithEmptyItem(source)) {
return Collections.emptyList();
}
Collection<Object> target = new ArrayList<>(source.size());
for (String value : source) {
target.add(conversionService.canConvert(String.class, targetType)
? conversionService.convert(value, TypeDescriptor.forObject(value), getTargetTypeDescriptor(path))
: value);
for (Object value : source) {
target.add(getValue(path, targetType, value));
}
return target;
}
@Nullable
private Object getValue(PathInformation path, Class<?> targetType, Object value) {
if (ClassUtils.isAssignableValue(targetType, value)) {
return value;
}
if (conversionService.canConvert(value.getClass(), targetType)) {
return conversionService.convert(value, TypeDescriptor.forObject(value), getTargetTypeDescriptor(path));
}
return value;
}
/**
* Returns the target {@link TypeDescriptor} for the given {@link PathInformation} by either inspecting the field or
* property (the latter preferred) to pick up annotations potentially defined for formatting purposes.
@ -213,21 +225,21 @@ public class QuerydslPredicateBuilder { @@ -213,21 +225,21 @@ public class QuerydslPredicateBuilder {
.nested(new Property(owningType, descriptor.getReadMethod(), descriptor.getWriteMethod(), leafProperty), 0);
if (result == null) {
throw new IllegalStateException(String.format("Could not obtain TypeDesciptor for PathInformation %s!", path));
throw new IllegalStateException(String.format("Could not obtain TypeDescriptor for PathInformation %s!", path));
}
return result;
}
/**
* Returns whether the given collection has exactly one element that doesn't contain any text. This is basically an
* indicator that a request parameter has been submitted but no value for it.
* Returns whether the given collection has exactly one element that is empty (i.e. doesn't contain text). This is
* basically an indicator that a request parameter has been submitted but no value for it.
*
* @param source must not be {@literal null}.
* @return
*/
private static boolean isSingleElementCollectionWithoutText(List<String> source) {
return source.size() == 1 && !StringUtils.hasLength(source.get(0));
private static boolean isSingleElementCollectionWithEmptyItem(List<?> source) {
return source.size() == 1 && ObjectUtils.isEmpty(source.get(0));
}
/**

Loading…
Cancel
Save