diff --git a/src/main/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilder.java b/src/main/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilder.java index 1b7c6325a..748fae33d 100644 --- a/src/main/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilder.java +++ b/src/main/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilder.java @@ -15,6 +15,7 @@ */ package org.springframework.data.querydsl.binding; +import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; @@ -24,8 +25,11 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import org.springframework.beans.BeanUtils; import org.springframework.beans.PropertyValues; import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.Property; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.data.mapping.PropertyPath; import org.springframework.data.mapping.PropertyReferenceException; import org.springframework.data.querydsl.EntityPathResolver; @@ -191,8 +195,8 @@ public class QuerydslPredicateBuilder { */ private Collection convertToPropertyPathSpecificType(List source, PropertyPath path) { - Class targetType = path.getLeafProperty().getOwningType().getProperty(path.getLeafProperty().getSegment()) - .getType(); + PropertyPath leafProperty = path.getLeafProperty(); + Class targetType = leafProperty.getOwningType().getProperty(leafProperty.getSegment()).getType(); if (source.isEmpty() || isSingleElementCollectionWithoutText(source)) { return Collections.emptyList(); @@ -202,13 +206,36 @@ public class QuerydslPredicateBuilder { for (String value : source) { - target.add(conversionService.canConvert(String.class, targetType) ? conversionService.convert( - targetType.isArray() ? value.split(",") : value, targetType) : value); + target.add(conversionService.canConvert(String.class, targetType) + ? conversionService.convert(value, TypeDescriptor.forObject(value), getTargetTypeDescriptor(path)) : value); } return target; } + /** + * Returns the target {@link TypeDescriptor} for the given {@link PropertyPath} by either inspecting the field or + * property (the latter preferred) to pick up annotations potentially defined for formatting purposes. + * + * @param path must not be {@literal null}. + * @return + */ + private static TypeDescriptor getTargetTypeDescriptor(PropertyPath path) { + + PropertyPath leafProperty = path.getLeafProperty(); + Class owningType = leafProperty.getOwningType().getType(); + + PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(owningType, leafProperty.getSegment()); + + if (descriptor == null) { + return TypeDescriptor.nested(ReflectionUtils.findField(owningType, leafProperty.getSegment()), 0); + } + + return TypeDescriptor.nested( + new Property(owningType, descriptor.getReadMethod(), descriptor.getWriteMethod(), leafProperty.getSegment()), + 0); + } + /** * 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. diff --git a/src/test/java/org/springframework/data/querydsl/User.java b/src/test/java/org/springframework/data/querydsl/User.java index 567def2b8..fd12adae0 100644 --- a/src/test/java/org/springframework/data/querydsl/User.java +++ b/src/test/java/org/springframework/data/querydsl/User.java @@ -18,6 +18,9 @@ package org.springframework.data.querydsl; import java.util.Date; import java.util.List; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.format.annotation.DateTimeFormat.ISO; + import com.mysema.query.annotations.QueryEntity; /** @@ -29,7 +32,7 @@ import com.mysema.query.annotations.QueryEntity; public class User { public String firstname, lastname; - public Date dateOfBirth; + public @DateTimeFormat(iso = ISO.DATE) Date dateOfBirth; public Address address; public List nickNames; public Long inceptionYear; diff --git a/src/test/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilderUnitTests.java b/src/test/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilderUnitTests.java index a12721d17..5e7583d26 100644 --- a/src/test/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilderUnitTests.java +++ b/src/test/java/org/springframework/data/querydsl/binding/QuerydslPredicateBuilderUnitTests.java @@ -19,16 +19,20 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.springframework.test.util.ReflectionTestUtils.*; +import java.text.ParseException; import java.util.List; +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; import org.junit.Before; import org.junit.Test; -import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.data.querydsl.QUser; import org.springframework.data.querydsl.SimpleEntityPathResolver; import org.springframework.data.querydsl.User; import org.springframework.data.querydsl.Users; import org.springframework.data.util.ClassTypeInformation; +import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -53,7 +57,8 @@ public class QuerydslPredicateBuilderUnitTests { @Before public void setUp() { - this.builder = new QuerydslPredicateBuilder(new DefaultConversionService(), SimpleEntityPathResolver.INSTANCE); + this.builder = new QuerydslPredicateBuilder(new DefaultFormattingConversionService(), + SimpleEntityPathResolver.INSTANCE); this.values = new LinkedMultiValueMap(); } @@ -185,4 +190,20 @@ public class QuerydslPredicateBuilderUnitTests { assertThat(constant.getConstant(), instanceOf(String.class)); assertThat((String) (constant.getConstant()), equalTo("rivers,two")); } + + /** + * @see DATACMNS-734 + */ + @Test + public void bindsDateCorrectly() throws ParseException { + + DateTimeFormatter format = DateTimeFormat.forPattern("yyyy-MM-dd"); + String date = format.print(new DateTime()); + + values.add("dateOfBirth", format.print(new DateTime())); + + Predicate predicate = builder.getPredicate(USER_TYPE, values, DEFAULT_BINDINGS); + + assertThat(predicate, is((Predicate) QUser.user.dateOfBirth.eq(format.parseDateTime(date).toDate()))); + } }