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