segments = Arrays.asList(path.toDotPath().split("\\."));
@@ -134,6 +178,7 @@ public class QuerydslBindings {
if (!whiteList.isEmpty()) {
return whiteList.contains(path.toDotPath());
}
+
return false;
}
}
@@ -141,96 +186,179 @@ public class QuerydslBindings {
return true;
}
+ /**
+ * Returns the {@link SingleValueBinding} for the given {@link PropertyPath}. Prefers a path configured for the
+ * specific path but falls back to the builder registered for a given type.
+ *
+ * @param path must not be {@literal null}.
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ , T> MultiValueBinding getBindingForPath(PropertyPath path) {
+
+ Assert.notNull(path, "PropertyPath must not be null!");
+
+ PathAndBinding pathAndBinding = (PathAndBinding) pathSpecs.get(path.toDotPath());
+
+ if (pathAndBinding != null) {
+ return pathAndBinding.getBinding();
+ }
+
+ pathAndBinding = (PathAndBinding) typeSpecs.get(path.getLeafProperty().getType());
+
+ return pathAndBinding == null ? null : pathAndBinding.getBinding();
+ }
+
+ /**
+ * Returns a {@link Path} for the {@link PropertyPath} instance.
+ *
+ * @param path must not be {@literal null}.
+ * @return
+ */
+ Path> getExistingPath(PropertyPath path) {
+
+ PathAndBinding, ?> pathAndBuilder = pathSpecs.get(path.toDotPath());
+ return pathAndBuilder == null ? null : pathAndBuilder.getPath();
+ }
+
+ /**
+ * Returns whether the given path is visible, which means either on the white list or not on the black list if no
+ * white list configured.
+ *
+ * @param path must not be {@literal null}.
+ * @return
+ */
private boolean isPathVisible(String path) {
- if (whiteList.isEmpty() && blackList.isEmpty()) {
- return true;
- }
-
- if (!blackList.isEmpty()) {
-
- if (blackList.contains(path)) {
-
- if (!whiteList.isEmpty() && whiteList.contains(path)) {
- return true;
- }
- return false;
- }
-
- return true;
- }
-
if (!whiteList.isEmpty()) {
if (whiteList.contains(path)) {
return true;
}
+
return false;
}
- return true;
+ return excludeUnlistedProperties ? false : !blackList.contains(path);
}
/**
- * Returns the {@link QuerydslBinding} for the given {@link PropertyPath}. Prefers a path configured for the specific
- * path but falls back to the builder registered for a given type.
+ * Returns the property path for the given {@link Path}.
*
- * @param path must not be {@literal null}.
+ * @param path can be {@literal null}.
* @return
*/
- public QuerydslBinding extends Path>> getBindingForPath(PropertyPath path) {
-
- Assert.notNull(path, "PropertyPath must not be null!");
-
- PathAndBinding pathAndBinding = pathSpecs.get(path.toDotPath());
-
- if (pathAndBinding != null) {
- return pathAndBinding.getBinding();
- }
-
- pathAndBinding = typeSpecs.get(path.getLeafProperty().getType());
-
- return pathAndBinding == null ? null : pathAndBinding.getBinding();
- }
-
- Path> getPath(PropertyPath path) {
- return getPathForStringPath(path.toDotPath());
- }
-
- private Path> getPathForStringPath(String path) {
-
- PathAndBinding pathAndBuilder = pathSpecs.get(path);
- if (pathAndBuilder == null) {
- return null;
- }
-
- return pathAndBuilder.getPath();
- }
-
- private String extractPropertyPath(Path> path) {
+ private String toDotPath(Path> path) {
if (path == null) {
return "";
}
- if (path.getMetadata().getParent() != null && !path.getMetadata().getParent().getMetadata().isRoot()) {
- return extractPropertyPath(path.getMetadata().getParent()) + "." + path.getMetadata().getName();
+ PathMetadata> metadata = path.getMetadata();
+
+ return path.toString().substring(metadata.getRoot().getMetadata().getName().length() + 1);
+ }
+
+ /**
+ * A binder for {@link Path}s.
+ *
+ * @author Oliver Gierke
+ */
+ protected final class PathBinder , T> {
+
+ private final List
paths;
+
+ /**
+ * Creates a new {@link PathBinder} for the given {@link Path}s.
+ *
+ * @param paths must not be {@literal null} or empty.
+ */
+ public PathBinder(P... paths) {
+
+ Assert.notEmpty(paths, "At least one path has to be provided!");
+ this.paths = Arrays.asList(paths);
}
- return path.getMetadata().getName();
+ /**
+ * Defines the given {@link SingleValueBinding} to be used for the paths,
+ *
+ * @param binding must not be {@literal null}.
+ * @return
+ */
+ public void single(SingleValueBinding
binding) {
+ Assert.notNull(binding, "Binding must not be null!");
+
+ multi(new MultiValueBindingAdapter
(binding));
+ }
+
+ public void multi(MultiValueBinding
binding) {
+
+ Assert.notNull(binding, "Binding must not be null!");
+
+ for (P path : paths) {
+ QuerydslBindings.this.pathSpecs.put(toDotPath(path), new PathAndBinding
(path, binding));
+ }
+ }
+ }
+
+ protected final class TypeBinder {
+
+ private final Class type;
+
+ public TypeBinder(Class type) {
+ this.type = type;
+ }
+
+ public > void single(SingleValueBinding
binding) {
+
+ Assert.notNull(binding, "Binding must not be null!");
+ multi(new MultiValueBindingAdapter
(binding));
+ }
+
+ public
> void multi(MultiValueBinding
binding) {
+
+ Assert.notNull(binding, "Binding must not be null!");
+ QuerydslBindings.this.typeSpecs.put(type, new PathAndBinding
(null, binding));
+ }
+ }
+
+ protected final class PropertyBinder {
+
+ private final List paths;
+
+ private PropertyBinder(List paths) {
+ this.paths = paths;
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public void using(SingleValueBinding, ?> binding) {
+
+ Assert.notNull(binding, "Binding must not be null!");
+ using(new MultiValueBindingAdapter(binding));
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public void using(MultiValueBinding, ?> binding) {
+
+ Assert.notNull(binding, "Binding must not be null!");
+
+ for (String path : paths) {
+ QuerydslBindings.this.pathSpecs.put(path, new PathAndBinding(null, binding));
+ }
+ }
}
/**
* @author Christoph Strobl
* @since 1.11
*/
- private static class PathAndBinding {
+ private static class PathAndBinding, T> {
private final Path> path;
- private final QuerydslBinding extends Path>> binding;
+ private final MultiValueBinding binding;
- public PathAndBinding(Path> path, QuerydslBinding extends Path>> binding) {
+ public PathAndBinding(S path, MultiValueBinding binding) {
this.path = path;
this.binding = binding;
@@ -240,9 +368,32 @@ public class QuerydslBindings {
return path;
}
- public QuerydslBinding extends Path>> getBinding() {
+ public MultiValueBinding getBinding() {
return binding;
}
+ }
+ /**
+ * @author Oliver Gierke
+ */
+ static class MultiValueBindingAdapter, S> implements MultiValueBinding {
+
+ private final SingleValueBinding delegate;
+
+ /**
+ * @param delegate
+ */
+ public MultiValueBindingAdapter(SingleValueBinding delegate) {
+ this.delegate = delegate;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.web.querydsl.MultiValueBinding#bind(com.mysema.query.types.Path, java.util.Collection)
+ */
+ @Override
+ public Predicate bind(T path, Collection extends S> value) {
+ return delegate.bind(path, value.iterator().next());
+ }
}
}
diff --git a/src/main/java/org/springframework/data/web/querydsl/QuerydslDefaultBinding.java b/src/main/java/org/springframework/data/web/querydsl/QuerydslDefaultBinding.java
index 631f7a219..31e05f2d0 100644
--- a/src/main/java/org/springframework/data/web/querydsl/QuerydslDefaultBinding.java
+++ b/src/main/java/org/springframework/data/web/querydsl/QuerydslDefaultBinding.java
@@ -23,7 +23,8 @@ import com.mysema.query.types.expr.SimpleExpression;
import com.mysema.query.types.path.CollectionPathBase;
/**
- * Default implementation of {@link QuerydslBinding} creating {@link Predicate} based on the {@link Path}s type. Binds:
+ * Default implementation of {@link MultiValueBinding} creating {@link Predicate} based on the {@link Path}s type.
+ * Binds:
*
* {@literal null} as {@link SimpleExpression#isNull()}.
* {@link java.lang.Object} as {@link SimpleExpression#eq()} on simple properties.
@@ -32,9 +33,10 @@ import com.mysema.query.types.path.CollectionPathBase;
*
*
* @author Christoph Strobl
+ * @author Oliver Gierke
* @since 1.11
*/
-class QuerydslDefaultBinding implements QuerydslBinding> {
+class QuerydslDefaultBinding implements MultiValueBinding, Object> {
/*
* (non-Javadoc)
@@ -42,27 +44,28 @@ class QuerydslDefaultBinding implements QuerydslBinding> {
*/
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
- public Predicate bind(Path> path, Object source) {
+ public Predicate bind(Path> path, Collection extends Object> source) {
- if (source == null && path instanceof SimpleExpression) {
+ if ((source == null || source.isEmpty())) {
return ((SimpleExpression) path).isNull();
}
+ Object firstValue = source.iterator().next();
+
if (path instanceof CollectionPathBase) {
- return ((CollectionPathBase) path).contains(source);
+ return ((CollectionPathBase) path).contains(firstValue);
}
if (path instanceof SimpleExpression) {
- if (source instanceof Collection) {
- return ((SimpleExpression) path).in((Collection) source);
+ if (source.size() > 1) {
+ return ((SimpleExpression) path).in(source);
}
- return ((SimpleExpression) path).eq(source);
+ return ((SimpleExpression) path).eq(firstValue);
}
- throw new IllegalArgumentException(String.format("Cannot create predicate for path '%s' with type '%s'.", path,
- path.getMetadata().getPathType()));
+ throw new IllegalArgumentException(
+ String.format("Cannot create predicate for path '%s' with type '%s'.", path, path.getMetadata().getPathType()));
}
-
}
diff --git a/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolver.java b/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolver.java
index ac28b0b3f..caa2ba55c 100644
--- a/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolver.java
+++ b/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolver.java
@@ -16,7 +16,11 @@
package org.springframework.data.web.querydsl;
import org.springframework.beans.BeanUtils;
+import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
@@ -34,20 +38,32 @@ import com.mysema.query.types.Predicate;
* controller methods.
*
* @author Christoph Strobl
+ * @author Oliver Gierke
* @since 1.11
*/
-public class QuerydslPredicateArgumentResolver implements HandlerMethodArgumentResolver {
+public class QuerydslPredicateArgumentResolver implements HandlerMethodArgumentResolver, ApplicationContextAware {
private final QuerydslPredicateBuilder predicateBuilder;
- private final ConversionService conversionService;
+
+ private AutowireCapableBeanFactory beanFactory;
/**
- * @param conversionService Defaulted to {@link DefaultConversionService} if {@literal null}.
+ * Creates a new {@link QuerydslPredicateArgumentResolver} using the given {@link ConversionService}.
+ *
+ * @param conversionService defaults to {@link DefaultConversionService} if {@literal null}.
*/
public QuerydslPredicateArgumentResolver(ConversionService conversionService) {
+ this.predicateBuilder = new QuerydslPredicateBuilder(
+ conversionService == null ? new DefaultConversionService() : conversionService);
+ }
- this.conversionService = conversionService == null ? new DefaultConversionService() : conversionService;
- this.predicateBuilder = new QuerydslPredicateBuilder();
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
+ */
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ this.beanFactory = applicationContext.getAutowireCapableBeanFactory();
}
/*
@@ -62,9 +78,8 @@ public class QuerydslPredicateArgumentResolver implements HandlerMethodArgumentR
}
if (parameter.hasParameterAnnotation(QuerydslPredicate.class)) {
- throw new IllegalArgumentException(String.format(
- "Parameter at position %s must be of type Predicate but was %s.", parameter.getParameterIndex(),
- parameter.getParameterType()));
+ throw new IllegalArgumentException(String.format("Parameter at position %s must be of type Predicate but was %s.",
+ parameter.getParameterIndex(), parameter.getParameterType()));
}
return false;
@@ -75,29 +90,27 @@ public class QuerydslPredicateArgumentResolver implements HandlerMethodArgumentR
* @see org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory)
*/
@Override
- public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
+ public Predicate resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return predicateBuilder.getPredicate(new MutablePropertyValues(webRequest.getParameterMap()),
- createBindingContext(parameter));
- }
-
- private QuerydslBindingContext createBindingContext(MethodParameter parameter) throws InstantiationException,
- IllegalAccessException {
- return new QuerydslBindingContext(extractTypeInfo(parameter), extractBindings(parameter), conversionService);
+ createBindings(parameter), extractTypeInfo(parameter).getActualType());
}
private TypeInformation> extractTypeInfo(MethodParameter parameter) {
Class> type = parameter.getParameterAnnotation(QuerydslPredicate.class).root();
- return type == Object.class ? ClassTypeInformation.fromReturnTypeOf(parameter.getMethod()) : ClassTypeInformation
- .from(type);
+ return type == Object.class ? ClassTypeInformation.fromReturnTypeOf(parameter.getMethod())
+ : ClassTypeInformation.from(type);
}
- private QuerydslBindings extractBindings(MethodParameter parameter) throws InstantiationException,
- IllegalAccessException {
+ private QuerydslBindings createBindings(MethodParameter parameter)
+ throws InstantiationException, IllegalAccessException {
- return BeanUtils.instantiateClass(parameter.getParameterAnnotation(QuerydslPredicate.class).bindings());
+ Class extends QuerydslBindings> bindingsType = parameter.getParameterAnnotation(QuerydslPredicate.class)
+ .bindings();
+
+ return beanFactory != null ? beanFactory.createBean(bindingsType) : BeanUtils.instantiateClass(bindingsType);
}
}
diff --git a/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateBuilder.java b/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateBuilder.java
index 93507738f..a8dd4c226 100644
--- a/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateBuilder.java
+++ b/src/main/java/org/springframework/data/web/querydsl/QuerydslPredicateBuilder.java
@@ -15,42 +15,49 @@
*/
package org.springframework.data.web.querydsl;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
+import org.springframework.core.convert.ConversionService;
import org.springframework.data.mapping.PropertyPath;
+import org.springframework.data.querydsl.SimpleEntityPathResolver;
+import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
-import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
+import org.springframework.util.ReflectionUtils;
import com.mysema.query.BooleanBuilder;
+import com.mysema.query.types.EntityPath;
import com.mysema.query.types.Path;
-import com.mysema.query.types.PathMetadata;
-import com.mysema.query.types.PathMetadataFactory;
import com.mysema.query.types.Predicate;
-import com.mysema.query.types.path.CollectionPath;
-import com.mysema.query.types.path.NumberPath;
-import com.mysema.query.types.path.PathBuilder;
-import com.mysema.query.types.path.PathBuilderFactory;
-import com.mysema.query.types.path.SimplePath;
-import com.mysema.query.types.path.StringPath;
/**
* Builder assembling {@link Predicate} out of {@link PropertyValues}.
*
* @author Christoph Strobl
+ * @author Oliver Gierke
* @since 1.11
*/
class QuerydslPredicateBuilder {
- private final QuerydslBinding> defaultBinding;
+ private final ConversionService conversionService;
+ private final MultiValueBinding, ?> defaultBinding;
+ private final Map> paths;
+
+ public QuerydslPredicateBuilder(ConversionService conversionService) {
+
+ Assert.notNull(conversionService, "ConversionService must not be null!");
- public QuerydslPredicateBuilder() {
this.defaultBinding = new QuerydslDefaultBinding();
+ this.conversionService = conversionService;
+ this.paths = new HashMap>();
}
/**
@@ -58,10 +65,10 @@ class QuerydslPredicateBuilder {
* @param context
* @return
*/
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public Predicate getPredicate(PropertyValues values, QuerydslBindingContext context) {
- Assert.notNull(context, "Context must not be null!");
+ public Predicate getPredicate(PropertyValues values, QuerydslBindings bindings, TypeInformation> type) {
+
+ Assert.notNull(bindings, "Context must not be null!");
if (values.isEmpty()) {
return new BooleanBuilder();
@@ -71,109 +78,98 @@ class QuerydslPredicateBuilder {
for (PropertyValue propertyValue : values.getPropertyValues()) {
- PropertyPath propertyPath = PropertyPath.from(propertyValue.getName(), context.getTargetType());
+ PropertyPath propertyPath = PropertyPath.from(propertyValue.getName(), type);
- if (context.isPathVisible(propertyPath)) {
+ if (bindings.isPathVisible(propertyPath)) {
- Object value = convertToPropertyPathSpecificType(propertyValue.getValue(), propertyPath, context);
- QuerydslBinding binding = getPredicateBuilderForPath(propertyPath, context);
-
- builder.and(binding.bind(getPath(propertyPath, context), value));
+ Collection value = convertToPropertyPathSpecificType(propertyValue.getValue(), propertyPath);
+ builder.and(invokeBinding(propertyPath, bindings, value));
}
}
return builder.getValue();
}
- private QuerydslBinding extends Path>> getPredicateBuilderForPath(PropertyPath dotPath,
- QuerydslBindingContext context) {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private Predicate invokeBinding(PropertyPath dotPath, QuerydslBindings bindings, Collection value) {
- QuerydslBinding extends Path>> binding = context.getBindingForPath(dotPath);
- return binding == null ? defaultBinding : binding;
+ Path> path = getPath(dotPath, bindings);
+
+ MultiValueBinding binding = bindings.getBindingForPath(dotPath);
+ binding = binding == null ? defaultBinding : binding;
+
+ return binding.bind(path, value);
}
- private Path> getPath(PropertyPath propertyPath, QuerydslBindingContext context) {
+ private Path> getPath(PropertyPath path, QuerydslBindings bindings) {
- Path> path = context.getPathForPropertyPath(propertyPath);
- if (path != null) {
- return path;
+ Path> resolvedPath = bindings.getExistingPath(path);
+
+ if (resolvedPath != null) {
+ return resolvedPath;
}
- return new PropertyPathPathBuilder(context.getTargetType()).forProperty(propertyPath);
+ resolvedPath = paths.get(resolvedPath);
+
+ if (resolvedPath != null) {
+ return resolvedPath;
+ }
+
+ resolvedPath = reifyPath(path, null);
+ paths.put(path, resolvedPath);
+
+ return resolvedPath;
}
- private Object convertToPropertyPathSpecificType(Object source, PropertyPath path, QuerydslBindingContext context) {
+ private static Path> reifyPath(PropertyPath path, EntityPath> base) {
+
+ EntityPath> entityPath = base != null ? base
+ : SimpleEntityPathResolver.INSTANCE.createPath(path.getOwningType().getType());
+
+ Field field = ReflectionUtils.findField(entityPath.getClass(), path.getSegment());
+ Object value = ReflectionUtils.getField(field, entityPath);
+
+ if (path.hasNext() && value instanceof EntityPath) {
+ return reifyPath(path.next(), (EntityPath>) value);
+ }
+
+ return (Path>) value;
+ }
+
+ private Collection convertToPropertyPathSpecificType(Object source, PropertyPath path) {
+
+ Class> targetType = path.getLeafProperty().getType();
+
+ if (targetType.isInstance(source)) {
+ return Collections.singleton(source);
+ }
Object value = source;
if (ObjectUtils.isArray(value)) {
-
- List> list = CollectionUtils.arrayToList(value);
- if (!list.isEmpty() && list.size() == 1) {
- value = list.get(0);
- } else {
- value = list;
- }
+ value = CollectionUtils.arrayToList(value);
}
if (value instanceof Collection) {
- return potentiallyConvertCollectionValues((Collection>) value, path.getType(), context);
+ return potentiallyConvertCollectionValues((Collection>) value, targetType);
}
- return potentiallyConvertValue(value, path.getType(), context);
+ return Collections.singleton(potentiallyConvertValue(value, targetType));
}
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private Collection> potentiallyConvertCollectionValues(Collection> source, Class> targetType,
- QuerydslBindingContext context) {
+ private Collection potentiallyConvertCollectionValues(Collection> source, Class> elementType) {
+
+ Collection target = new ArrayList(source.size());
- Collection target = new ArrayList(source.size());
for (Object value : source) {
- target.add(potentiallyConvertValue(value, targetType, context));
+ target.add(potentiallyConvertValue(value, elementType));
}
return target;
}
- private Object potentiallyConvertValue(Object source, Class> targetType, QuerydslBindingContext context) {
-
- return context.getConversionService().canConvert(source.getClass(), targetType)
- ? context.getConversionService().convert(source, targetType) : source;
+ private Object potentiallyConvertValue(Object source, Class> targetType) {
+ return conversionService.canConvert(source.getClass(), targetType) ? conversionService.convert(source, targetType)
+ : source;
}
-
- /**
- * {@link PropertyPathPathBuilder} creates a typed {@link Path} based on type information contained in
- * {@link PropertyPath}.
- *
- * @author Christoph Strobl
- */
- @SuppressWarnings("rawtypes")
- static class PropertyPathPathBuilder {
-
- final PathBuilder> pathBuilder;
-
- public PropertyPathPathBuilder(Class> type) {
- pathBuilder = new PathBuilderFactory().create(type);
- }
-
- @SuppressWarnings({ "unchecked" })
- public Path> forProperty(PropertyPath source) {
-
- PathMetadata> metadata = PathMetadataFactory.forVariable(source.toDotPath());
-
- Path> path = null;
- if (source.isCollection()) {
- path = pathBuilder.get(new CollectionPath(Collection.class, source.getType(), metadata));
- } else if (ClassUtils.isAssignable(String.class, source.getType())) {
- path = pathBuilder.get(new StringPath(metadata));
- } else if (ClassUtils.isAssignable(Number.class, source.getType())) {
- path = pathBuilder.get(new NumberPath(source.getType(), metadata));
- } else {
- path = pathBuilder.get(new SimplePath(source.getType(), metadata));
- }
-
- return path;
- }
- }
-
}
diff --git a/src/main/java/org/springframework/data/web/querydsl/SingleValueBinding.java b/src/main/java/org/springframework/data/web/querydsl/SingleValueBinding.java
new file mode 100644
index 000000000..4fda5551b
--- /dev/null
+++ b/src/main/java/org/springframework/data/web/querydsl/SingleValueBinding.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.web.querydsl;
+
+import com.mysema.query.types.Path;
+import com.mysema.query.types.Predicate;
+
+/**
+ * {@link SingleValueBinding} creates a {@link Predicate} out of given {@link Path} and value. Used for specific parameter
+ * treatment in {@link QuerydslBindings}.
+ *
+ * @author Christoph Strobl
+ * @author Oliver Gierke
+ * @since 1.11
+ */
+@FunctionalInterface
+public interface SingleValueBinding, S> {
+
+ /**
+ * Returns the predicate to be applied to the given {@link Path} for the given value.
+ *
+ * @param path {@link Path} to the property. Must not be {@literal null}.
+ * @param value the value that should be bound. Can be {@literal null}.
+ * @return must not be {@literal null}.
+ */
+ Predicate bind(T path, S value);
+}
diff --git a/src/test/java/org/springframework/data/querydsl/Address.java b/src/test/java/org/springframework/data/querydsl/Address.java
index 38bb0a604..703bfabcf 100644
--- a/src/test/java/org/springframework/data/querydsl/Address.java
+++ b/src/test/java/org/springframework/data/querydsl/Address.java
@@ -22,6 +22,11 @@ import com.mysema.query.annotations.QueryEntity;
*/
@QueryEntity
public class Address {
- String street;
- String city;
+
+ public String street, city;
+
+ public Address(String street, String city) {
+ this.street = street;
+ this.city = city;
+ }
}
diff --git a/src/test/java/org/springframework/data/querydsl/User.java b/src/test/java/org/springframework/data/querydsl/User.java
index ba7b52a83..567def2b8 100644
--- a/src/test/java/org/springframework/data/querydsl/User.java
+++ b/src/test/java/org/springframework/data/querydsl/User.java
@@ -28,11 +28,16 @@ import com.mysema.query.annotations.QueryEntity;
@QueryEntity
public class User {
- String firstname;
- String lastname;
- Date dateOfBirth;
+ public String firstname, lastname;
+ public Date dateOfBirth;
+ public Address address;
+ public List nickNames;
+ public Long inceptionYear;
- Address address;
- List nickNames;
- Long inceptionYear;
+ public User(String firstname, String lastname, Address address) {
+
+ this.firstname = firstname;
+ this.lastname = lastname;
+ this.address = address;
+ }
}
diff --git a/src/test/java/org/springframework/data/querydsl/Users.java b/src/test/java/org/springframework/data/querydsl/Users.java
new file mode 100644
index 000000000..56c1a9f2c
--- /dev/null
+++ b/src/test/java/org/springframework/data/querydsl/Users.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.querydsl;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Oliver Gierke
+ */
+public class Users {
+
+ public static final User OLIVER, CHRISTOPH;
+
+ public static final List USERS;
+
+ static {
+
+ OLIVER = new User("Oliver", "Gierke", new Address("Somewhere", "Dresden"));
+ CHRISTOPH = new User("Christoph", "Strobl", new Address("Somewhere", "Linz"));
+
+ USERS = Arrays.asList(OLIVER, CHRISTOPH);
+ }
+}
diff --git a/src/test/java/org/springframework/data/web/querydsl/QuerydslBindingsUnitTests.java b/src/test/java/org/springframework/data/web/querydsl/QuerydslBindingsUnitTests.java
index ba0bdcc76..02f999451 100644
--- a/src/test/java/org/springframework/data/web/querydsl/QuerydslBindingsUnitTests.java
+++ b/src/test/java/org/springframework/data/web/querydsl/QuerydslBindingsUnitTests.java
@@ -15,21 +15,18 @@
*/
package org.springframework.data.web.querydsl;
-import static org.hamcrest.core.Is.*;
-import static org.hamcrest.core.IsNull.*;
+import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
-import java.util.Collections;
-
import org.junit.Before;
import org.junit.Test;
-import org.springframework.beans.MutablePropertyValues;
+import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.mapping.PropertyPath;
-import org.springframework.data.querydsl.Address;
-import org.springframework.data.querydsl.QAddress;
+import org.springframework.data.querydsl.QUser;
import org.springframework.data.querydsl.User;
-import org.springframework.data.util.ClassTypeInformation;
+import org.springframework.test.util.ReflectionTestUtils;
+import com.mysema.query.types.Path;
import com.mysema.query.types.Predicate;
import com.mysema.query.types.path.StringPath;
@@ -41,69 +38,50 @@ import com.mysema.query.types.path.StringPath;
*/
public class QuerydslBindingsUnitTests {
- private QuerydslPredicateBuilder builder;
- private QuerydslBindings typeBasedBindings;
- private QuerydslBindings pathBasedBindings;
+ QuerydslPredicateBuilder builder;
+ QuerydslBindings bindings;
+
+ static final SingleValueBinding CONTAINS_BINDING = new SingleValueBinding() {
+
+ @Override
+ public Predicate bind(StringPath path, String value) {
+ return path.contains(value);
+ }
+ };
@Before
public void setUp() {
- builder = new QuerydslPredicateBuilder();
- typeBasedBindings = new QuerydslBindings() {
- {
- bind(String.class, new QuerydslBinding() {
-
- @Override
- public Predicate bind(StringPath path, Object value) {
- return path.contains(value.toString());
- }
- });
- }
- };
-
- pathBasedBindings = new QuerydslBindings() {
- {
- bind("address.street", new QuerydslBinding() {
-
- @Override
- public Predicate bind(StringPath path, Object value) {
- return path.contains(value.toString());
- }
- });
-
- bind("firstname", new QuerydslBinding() {
-
- @Override
- public Predicate bind(StringPath path, Object value) {
- return path.contains(value.toString());
- }
- });
- }
- };
+ this.builder = new QuerydslPredicateBuilder(new DefaultConversionService());
+ this.bindings = new QuerydslBindings();
}
/**
* @see DATACMNS-669
*/
@Test(expected = IllegalArgumentException.class)
- public void getBindingForPathShouldThrowErrorWhenPathIsNull() {
- pathBasedBindings.getBindingForPath(null);
+ public void rejectsNullPath() {
+ bindings.getBindingForPath(null);
}
/**
* @see DATACMNS-669
*/
@Test
- public void getBindingForPathShouldReturnNullWhenNoSpecifcBindingAvailable() {
- assertThat(pathBasedBindings.getBindingForPath(PropertyPath.from("lastname", User.class)), nullValue());
+ public void returnsNullIfNoBindingRegisteredForPath() {
+ assertThat(bindings.getBindingForPath(PropertyPath.from("lastname", User.class)), nullValue());
}
/**
* @see DATACMNS-669
*/
@Test
- public void getBindingForPathShouldReturnSpeficicBindingWhenAvailable() {
- assertThat(pathBasedBindings.getBindingForPath(PropertyPath.from("firstname", User.class)), notNullValue());
+ public void returnsRegisteredBindingForSimplePath() {
+
+ bindings.bind("firstname").using(CONTAINS_BINDING);
+
+ assertAdapterWithTargetBinding(bindings.getBindingForPath(PropertyPath.from("firstname", User.class)),
+ CONTAINS_BINDING);
}
/**
@@ -111,7 +89,11 @@ public class QuerydslBindingsUnitTests {
*/
@Test
public void getBindingForPathShouldReturnSpeficicBindingForNestedElementsWhenAvailable() {
- assertThat(pathBasedBindings.getBindingForPath(PropertyPath.from("address.street", User.class)), notNullValue());
+
+ bindings.bind("address.street").using(CONTAINS_BINDING);
+
+ assertAdapterWithTargetBinding(bindings.getBindingForPath(PropertyPath.from("address.street", User.class)),
+ CONTAINS_BINDING);
}
/**
@@ -119,100 +101,112 @@ public class QuerydslBindingsUnitTests {
*/
@Test
public void getBindingForPathShouldReturnSpeficicBindingForTypes() {
- assertThat(typeBasedBindings.getBindingForPath(PropertyPath.from("address.street", User.class)), notNullValue());
+
+ bindings.bind(String.class).single(CONTAINS_BINDING);
+
+ assertAdapterWithTargetBinding(bindings.getBindingForPath(PropertyPath.from("address.street", User.class)),
+ CONTAINS_BINDING);
}
/**
* @see DATACMNS-669
*/
@Test
- public void getBindingForPathShouldIgnoreSpeficicBindingForTypesWhenTypesDoNotMatch() {
- assertThat(typeBasedBindings.getBindingForPath(PropertyPath.from("inceptionYear", User.class)), nullValue());
+ public void propertyNotExplicitlyIncludedAndWithoutTypeBindingIsInvisible() {
+
+ bindings.bind(String.class).single(CONTAINS_BINDING);
+
+ assertThat(bindings.getBindingForPath(PropertyPath.from("inceptionYear", User.class)), nullValue());
}
/**
* @see DATACMNS-669
*/
@Test
- public void isPathVisibleShouldReturnTrueWhenNoRestrictionDefined() {
- assertThat(typeBasedBindings.isPathVisible(PropertyPath.from("inceptionYear", User.class)), is(true));
+ public void pathIsVisibleIfTypeBasedBindingWasRegistered() {
+
+ bindings.bind(String.class).single(CONTAINS_BINDING);
+
+ assertThat(bindings.isPathVisible(PropertyPath.from("inceptionYear", User.class)), is(true));
}
/**
* @see DATACMNS-669
*/
@Test
- public void isPathVisibleShouldReturnTrueWhenPathContainedInIncluding() {
+ public void explicitlyIncludedPathIsVisible() {
- assertThat(
- new QuerydslBindings().including("inceptionYear").isPathVisible(PropertyPath.from("inceptionYear", User.class)),
- is(true));
+ bindings.including("inceptionYear");
+
+ assertThat(bindings.isPathVisible(PropertyPath.from("inceptionYear", User.class)), is(true));
}
/**
* @see DATACMNS-669
*/
@Test
- public void isPathVisibleShouldReturnFalseWhenPathNotContainedInIncluding() {
+ public void notExplicitlyIncludedPathIsInvisible() {
- assertThat(
- new QuerydslBindings().including("inceptionYear").isPathVisible(PropertyPath.from("firstname", User.class)),
- is(false));
+ bindings.including("inceptionYear");
+
+ assertThat(bindings.isPathVisible(PropertyPath.from("firstname", User.class)), is(false));
}
/**
* @see DATACMNS-669
*/
@Test
- public void isPathVisibleShouldReturnFalseWhenPathContainedInExcluding() {
+ public void excludedPathIsInvisible() {
- assertThat(
- new QuerydslBindings().excluding("inceptionYear").isPathVisible(PropertyPath.from("inceptionYear", User.class)),
- is(false));
+ bindings.excluding("inceptionYear");
+
+ assertThat(bindings.isPathVisible(PropertyPath.from("inceptionYear", User.class)), is(false));
}
/**
* @see DATACMNS-669
*/
@Test
- public void isPathVisibleShouldReturnTrueWhenPathNotContainedInExcluding() {
+ public void pathIsVisibleIfNotExplicitlyExcluded() {
- assertThat(
- new QuerydslBindings().excluding("inceptionYear").isPathVisible(PropertyPath.from("firstname", User.class)),
- is(true));
+ bindings.excluding("inceptionYear");
+
+ assertThat(bindings.isPathVisible(PropertyPath.from("firstname", User.class)), is(true));
}
/**
* @see DATACMNS-669
*/
@Test
- public void isPathVisibleShouldReturnTrueWhenPathContainedInExcludingAndIncluding() {
+ public void pathIsVisibleIfItsBothBlackAndWhitelisted() {
- assertThat(
- new QuerydslBindings().excluding("inceptionYear").isPathVisible(PropertyPath.from("firstname", User.class)),
- is(true));
+ bindings.excluding("firstname");
+ bindings.including("firstname");
+
+ assertThat(bindings.isPathVisible(PropertyPath.from("firstname", User.class)), is(true));
}
/**
* @see DATACMNS-669
*/
@Test
- public void isPathVisibleShouldReturnFalseWhenPartialPathContainedInExcluding() {
+ public void nestedPathIsInvisibleIfAParanetPathWasExcluded() {
- assertThat(
- new QuerydslBindings().excluding("address").isPathVisible(PropertyPath.from("address.city", User.class)),
- is(false));
+ bindings.excluding("address");
+
+ assertThat(bindings.isPathVisible(PropertyPath.from("address.city", User.class)), is(false));
}
/**
* @see DATACMNS-669
*/
@Test
- public void isPathVisibleShouldReturnTrueWhenPartialPathContainedInExcludingButConcretePathIsIncluded() {
+ public void pathIsVisibleIfConcretePathIsVisibleButParentExcluded() {
- assertThat(
- new QuerydslBindings().excluding("address").including("address.city")
- .isPathVisible(PropertyPath.from("address.city", User.class)), is(true));
+ bindings.excluding("address");
+ bindings.including("address.city");
+
+ assertThat(bindings.isPathVisible(PropertyPath.from("address.city", User.class)), is(true));
}
/**
@@ -221,22 +215,32 @@ public class QuerydslBindingsUnitTests {
@Test
public void isPathVisibleShouldReturnFalseWhenPartialPathContainedInExcludingAndConcretePathToDifferentPropertyIsIncluded() {
- assertThat(
- new QuerydslBindings().excluding("address").including("address.city")
- .isPathVisible(PropertyPath.from("address.street", User.class)), is(false));
+ bindings.excluding("address");
+ bindings.including("address.city");
+
+ assertThat(bindings.isPathVisible(PropertyPath.from("address.street", User.class)), is(false));
}
- /**
- * @see DATACMNS-669
- */
@Test
- public void usesTypeBasedBindingIfConfigured() {
+ public void testname() {
- MutablePropertyValues values = new MutablePropertyValues(Collections.singletonMap("city", "Dresden"));
+ PropertyPath firstname = PropertyPath.from("firstname", User.class);
+ PropertyPath lastname = PropertyPath.from("lastname", User.class);
+ PropertyPath city = PropertyPath.from("address.city", User.class);
+ PropertyPath street = PropertyPath.from("address.street", User.class);
- QuerydslBindingContext context = new QuerydslBindingContext(ClassTypeInformation.from(Address.class),
- this.typeBasedBindings, null);
+ bindings.including(QUser.user.firstname, QUser.user.address.street);
- assertThat(builder.getPredicate(values, context), is((Predicate) QAddress.address.city.contains("Dresden")));
+ assertThat(bindings.isPathVisible(firstname), is(true));
+ assertThat(bindings.isPathVisible(street), is(true));
+ assertThat(bindings.isPathVisible(lastname), is(false));
+ assertThat(bindings.isPathVisible(city), is(false));
+ }
+
+ private static , S> void assertAdapterWithTargetBinding(MultiValueBinding
binding,
+ SingleValueBinding extends Path>, ?> expected) {
+
+ assertThat(binding, is(instanceOf(QuerydslBindings.MultiValueBindingAdapter.class)));
+ assertThat(ReflectionTestUtils.getField(binding, "delegate"), is((Object) expected));
}
}
diff --git a/src/test/java/org/springframework/data/web/querydsl/QuerydslDefaultBindingUnitTests.java b/src/test/java/org/springframework/data/web/querydsl/QuerydslDefaultBindingUnitTests.java
index c2473bb77..30d6cb7fa 100644
--- a/src/test/java/org/springframework/data/web/querydsl/QuerydslDefaultBindingUnitTests.java
+++ b/src/test/java/org/springframework/data/web/querydsl/QuerydslDefaultBindingUnitTests.java
@@ -18,6 +18,7 @@ package org.springframework.data.web.querydsl;
import static org.hamcrest.core.Is.*;
import java.util.Arrays;
+import java.util.Collections;
import org.hamcrest.Matcher;
import org.hamcrest.core.Is;
@@ -47,7 +48,7 @@ public class QuerydslDefaultBindingUnitTests {
@Test
public void shouldCreatePredicateCorrectlyWhenPropertyIsInRoot() {
- Predicate predicate = builder.bind(QUser.user.firstname, "tam");
+ Predicate predicate = builder.bind(QUser.user.firstname, Collections.singleton("tam"));
assertThat(predicate, is(QUser.user.firstname.eq("tam")));
}
@@ -58,7 +59,7 @@ public class QuerydslDefaultBindingUnitTests {
@Test
public void shouldCreatePredicateCorrectlyWhenPropertyIsInNestedElement() {
- Predicate predicate = builder.bind(QUser.user.address.city, "two rivers");
+ Predicate predicate = builder.bind(QUser.user.address.city, Collections.singleton("two rivers"));
Assert.assertThat(predicate.toString(), is(QUser.user.address.city.eq("two rivers").toString()));
}
@@ -69,7 +70,7 @@ public class QuerydslDefaultBindingUnitTests {
@Test
public void shouldCreatePredicateCorrectlyWhenValueIsNull() {
- Predicate predicate = builder.bind(QUser.user.firstname, null);
+ Predicate predicate = builder.bind(QUser.user.firstname, Collections.emptySet());
assertThat(predicate, is(QUser.user.firstname.isNull()));
}
@@ -80,7 +81,7 @@ public class QuerydslDefaultBindingUnitTests {
@Test
public void shouldCreatePredicateWithContainingWhenPropertyIsCollectionLikeAndValueIsObject() {
- Predicate predicate = builder.bind(QUser.user.nickNames, "dragon reborn");
+ Predicate predicate = builder.bind(QUser.user.nickNames, Collections.singleton("dragon reborn"));
assertThat(predicate, is(QUser.user.nickNames.contains("dragon reborn")));
}
diff --git a/src/test/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolverUnitTests.java
index 5cbb9a0e0..ae9b18d55 100644
--- a/src/test/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolverUnitTests.java
+++ b/src/test/java/org/springframework/data/web/querydsl/QuerydslPredicateArgumentResolverUnitTests.java
@@ -18,7 +18,6 @@ package org.springframework.data.web.querydsl;
import static org.hamcrest.core.Is.*;
import static org.junit.Assert.*;
-import org.hamcrest.core.Is;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.MethodParameter;
@@ -34,7 +33,10 @@ import com.mysema.query.types.expr.BooleanExpression;
import com.mysema.query.types.path.StringPath;
/**
+ * Unit tests for {@link QuerydslPredicateArgumentResolver}.
+ *
* @author Christoph Strobl
+ * @author Oliver Gierke
*/
public class QuerydslPredicateArgumentResolverUnitTests {
@@ -90,10 +92,10 @@ public class QuerydslPredicateArgumentResolverUnitTests {
request.addParameter("firstname", "rand");
- Object predicate = (BooleanExpression) resolver.resolveArgument(
+ Predicate predicate = (BooleanExpression) resolver.resolveArgument(
getMethodParameterFor("simpleFind", Predicate.class), null, new ServletWebRequest(request), null);
- assertThat(predicate, Is. is(QUser.user.firstname.eq("rand")));
+ assertThat(predicate, is((Predicate) QUser.user.firstname.eq("rand")));
}
/**
@@ -105,10 +107,10 @@ public class QuerydslPredicateArgumentResolverUnitTests {
request.addParameter("firstname", "rand");
request.addParameter("lastname", "al'thor");
- Object predicate = resolver.resolveArgument(getMethodParameterFor("simpleFind", Predicate.class), null,
+ Predicate predicate = resolver.resolveArgument(getMethodParameterFor("simpleFind", Predicate.class), null,
new ServletWebRequest(request), null);
- assertThat(predicate, Is. is(QUser.user.firstname.eq("rand").and(QUser.user.lastname.eq("al'thor"))));
+ assertThat(predicate, is((Predicate) QUser.user.firstname.eq("rand").and(QUser.user.lastname.eq("al'thor"))));
}
/**
@@ -119,10 +121,12 @@ public class QuerydslPredicateArgumentResolverUnitTests {
request.addParameter("address.city", "two rivers");
- Object predicate = resolver.resolveArgument(getMethodParameterFor("simpleFind", Predicate.class), null,
+ Predicate predicate = resolver.resolveArgument(getMethodParameterFor("simpleFind", Predicate.class), null,
new ServletWebRequest(request), null);
- assertThat(predicate.toString(), is(QUser.user.address.city.eq("two rivers").toString()));
+ BooleanExpression eq = QUser.user.address.city.eq("two rivers");
+
+ assertThat(predicate, is((Predicate) eq));
}
/**
@@ -133,10 +137,10 @@ public class QuerydslPredicateArgumentResolverUnitTests {
request.addParameter("address.city", "tar valon");
- Object predicate = resolver.resolveArgument(getMethodParameterFor("pagedFind", Predicate.class, Pageable.class),
+ Predicate predicate = resolver.resolveArgument(getMethodParameterFor("pagedFind", Predicate.class, Pageable.class),
null, new ServletWebRequest(request), null);
- assertThat(predicate.toString(), is(QUser.user.address.city.eq("tar valon").toString()));
+ assertThat(predicate, is((Predicate) QUser.user.address.city.eq("tar valon")));
}
/**
@@ -148,12 +152,11 @@ public class QuerydslPredicateArgumentResolverUnitTests {
request.addParameter("firstname", "egwene");
request.addParameter("lastname", "al'vere");
- Object predicate = resolver.resolveArgument(getMethodParameterFor("specificFind", Predicate.class), null,
+ Predicate predicate = resolver.resolveArgument(getMethodParameterFor("specificFind", Predicate.class), null,
new ServletWebRequest(request), null);
- assertThat(predicate.toString(),
- is(QUser.user.firstname.eq("egwene".toUpperCase()).and(QUser.user.lastname.toLowerCase().eq("al'vere"))
- .toString()));
+ assertThat(predicate, is((Predicate) QUser.user.firstname.eq("egwene".toUpperCase())
+ .and(QUser.user.lastname.toLowerCase().eq("al'vere"))));
}
/**
@@ -164,10 +167,10 @@ public class QuerydslPredicateArgumentResolverUnitTests {
request.addParameter("inceptionYear", "978");
- Object predicate = (BooleanExpression) resolver.resolveArgument(
+ Predicate predicate = (BooleanExpression) resolver.resolveArgument(
getMethodParameterFor("specificFind", Predicate.class), null, new ServletWebRequest(request), null);
- assertThat(predicate, Is. is(QUser.user.inceptionYear.eq(978L)));
+ assertThat(predicate, is((Predicate) QUser.user.inceptionYear.eq(978L)));
}
/**
@@ -178,10 +181,10 @@ public class QuerydslPredicateArgumentResolverUnitTests {
request.addParameter("inceptionYear", new String[] { "978", "998" });
- Object predicate = (BooleanExpression) resolver.resolveArgument(
+ Predicate predicate = (BooleanExpression) resolver.resolveArgument(
getMethodParameterFor("specificFind", Predicate.class), null, new ServletWebRequest(request), null);
- assertThat(predicate, Is. is(QUser.user.inceptionYear.in(978L, 998L)));
+ assertThat(predicate, is((Predicate) QUser.user.inceptionYear.in(978L, 998L)));
}
/**
@@ -199,7 +202,7 @@ public class QuerydslPredicateArgumentResolverUnitTests {
assertThat(predicate.toString(), is(QUser.user.inceptionYear.eq(973L).toString()));
}
- private MethodParameter getMethodParameterFor(String methodName, Class>... args) throws RuntimeException {
+ private static MethodParameter getMethodParameterFor(String methodName, Class>... args) throws RuntimeException {
try {
return new MethodParameter(Sample.class.getMethod(methodName, args), 0);
@@ -212,19 +215,19 @@ public class QuerydslPredicateArgumentResolverUnitTests {
public SpecificBinding() {
- bind("firstname", new QuerydslBinding() {
+ bind("firstname").using(new SingleValueBinding() {
@Override
- public Predicate bind(StringPath path, Object value) {
- return path.eq(value.toString().toUpperCase());
+ public Predicate bind(StringPath path, String value) {
+ return path.eq(value.toUpperCase());
}
});
- bind(QUser.user.lastname, new QuerydslBinding() {
+ bind(QUser.user.lastname).single(new SingleValueBinding() {
@Override
- public Predicate bind(StringPath path, Object value) {
- return path.toLowerCase().eq(value.toString());
+ public Predicate bind(StringPath path, String value) {
+ return path.toLowerCase().eq(value);
}
});
diff --git a/src/test/java/org/springframework/data/web/querydsl/QuerydslPredicateBuilderUnitTests.java b/src/test/java/org/springframework/data/web/querydsl/QuerydslPredicateBuilderUnitTests.java
index 19ef24907..96b9475a8 100644
--- a/src/test/java/org/springframework/data/web/querydsl/QuerydslPredicateBuilderUnitTests.java
+++ b/src/test/java/org/springframework/data/web/querydsl/QuerydslPredicateBuilderUnitTests.java
@@ -15,32 +15,49 @@
*/
package org.springframework.data.web.querydsl;
-import static org.hamcrest.core.Is.*;
+import static java.util.Collections.*;
+import static org.hamcrest.Matchers.*;
+import static org.hamcrest.core.Is.is;
import static org.junit.Assert.*;
-import java.util.Collections;
+import java.util.List;
-import org.hamcrest.core.Is;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.MutablePropertyValues;
+import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.querydsl.QUser;
import org.springframework.data.querydsl.User;
+import org.springframework.data.querydsl.Users;
import org.springframework.data.util.ClassTypeInformation;
import com.mysema.query.BooleanBuilder;
+import com.mysema.query.collections.CollQueryFactory;
import com.mysema.query.types.Predicate;
/**
+ * Unit tests for {@link QuerydslPredicateBuilder}.
+ *
* @author Christoph Strobl
+ * @author Oliver Gierke
*/
public class QuerydslPredicateBuilderUnitTests {
+ static final QuerydslBindings DEFAULT_BINDINGS = new QuerydslBindings();
+
QuerydslPredicateBuilder builder;
@Before
public void setUp() {
- builder = new QuerydslPredicateBuilder();
+ builder = new QuerydslPredicateBuilder(new DefaultConversionService());
+ }
+
+ /**
+ * @see DATACMNS-669
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void rejectsNullConversionService() {
+ new QuerydslPredicateBuilder(null);
}
/**
@@ -48,7 +65,7 @@ public class QuerydslPredicateBuilderUnitTests {
*/
@Test(expected = IllegalArgumentException.class)
public void getPredicateShouldThrowErrorWhenBindingContextIsNull() {
- builder.getPredicate(new MutablePropertyValues(), null);
+ builder.getPredicate(new MutablePropertyValues(), null, null);
}
/**
@@ -57,8 +74,8 @@ public class QuerydslPredicateBuilderUnitTests {
@Test
public void getPredicateShouldReturnEmptyPredicateWhenPropertiesAreEmpty() {
- assertThat(builder.getPredicate(new MutablePropertyValues(), new QuerydslBindingContext(
- ClassTypeInformation.OBJECT, null, null)), is((Predicate) new BooleanBuilder()));
+ assertThat(builder.getPredicate(new MutablePropertyValues(), DEFAULT_BINDINGS, ClassTypeInformation.OBJECT),
+ is((Predicate) new BooleanBuilder()));
}
/**
@@ -67,10 +84,31 @@ public class QuerydslPredicateBuilderUnitTests {
@Test
public void resolveArgumentShouldCreateSingleStringParameterPredicateCorrectly() throws Exception {
- Predicate predicate = builder.getPredicate(
- new MutablePropertyValues(Collections.singletonMap("firstname", new String[] { "rand" })),
- new QuerydslBindingContext(ClassTypeInformation.from(User.class), null, null));
+ Predicate predicate = builder.getPredicate(new MutablePropertyValues(singletonMap("firstname", "Oliver")),
+ DEFAULT_BINDINGS, ClassTypeInformation.from(User.class));
- assertThat(predicate, Is. is(QUser.user.firstname.eq("rand")));
+ assertThat(predicate, is((Predicate) QUser.user.firstname.eq("Oliver")));
+
+ List result = CollQueryFactory.from(QUser.user, Users.USERS).where(predicate).list(QUser.user);
+
+ assertThat(result, hasSize(1));
+ assertThat(result, hasItem(Users.OLIVER));
+ }
+
+ /**
+ * @see DATACMNS-669
+ */
+ @Test
+ public void resolveArgumentShouldCreateNestedStringParameterPredicateCorrectly() throws Exception {
+
+ Predicate predicate = builder.getPredicate(new MutablePropertyValues(singletonMap("address.city", "Linz")),
+ DEFAULT_BINDINGS, ClassTypeInformation.from(User.class));
+
+ assertThat(predicate, is((Predicate) QUser.user.address.city.eq("Linz")));
+
+ List result = CollQueryFactory.from(QUser.user, Users.USERS).where(predicate).list(QUser.user);
+
+ assertThat(result, hasSize(1));
+ assertThat(result, hasItem(Users.CHRISTOPH));
}
}