From dc09d5d34d3cd5b51299afddcdbc66b2597ef5b0 Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Mon, 7 Dec 2020 15:10:03 +0100 Subject: [PATCH] Add JSR310 converters to the converters used for projections. Similar converters where removed because they clashed with the support for nullable wrappers. This adds them back as dedicated converters that does not clash with conversions for nullable wrappers. See https://github.com/spring-projects/spring-data-commons/commit/bd3992dfc56cc53e3be4a6d7ea106594fd7d81e5#diff-96f7084777a2a702d85f5c600e542b10123d6c3332ed3d3f8e329ca7061faab0R55 Original Pull Request: #479 Closes: #2223 --- .../projection/ProxyProjectionFactory.java | 3 + .../ProxyProjectionFactoryUnitTests.java | 66 ++++++++++++++++--- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java b/src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java index 758e5dd05..25bbb5604 100644 --- a/src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java +++ b/src/main/java/org/springframework/data/projection/ProxyProjectionFactory.java @@ -28,6 +28,7 @@ import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.GenericConversionService; +import org.springframework.data.convert.Jsr310Converters; import org.springframework.data.util.NullableWrapperConverters; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -43,6 +44,7 @@ import org.springframework.util.ConcurrentReferenceHashMap; * @author Oliver Gierke * @author Christoph Strobl * @author Mark Paluch + * @author Jens Schauder * @see SpelAwareProxyProjectionFactory * @since 1.10 */ @@ -51,6 +53,7 @@ class ProxyProjectionFactory implements ProjectionFactory, BeanClassLoaderAware final static GenericConversionService CONVERSION_SERVICE = new DefaultConversionService(); static { + Jsr310Converters.getConvertersToRegister().forEach(CONVERSION_SERVICE::addConverter); NullableWrapperConverters.registerConvertersIn(CONVERSION_SERVICE); CONVERSION_SERVICE.removeConvertible(Object.class, Object.class); } diff --git a/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java b/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java index c836037ca..bc10a3441 100755 --- a/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java @@ -19,7 +19,11 @@ import static org.assertj.core.api.Assertions.*; import java.beans.PropertyDescriptor; import java.lang.reflect.Proxy; +import java.time.LocalDateTime; +import java.util.Calendar; import java.util.Collections; +import java.util.Date; +import java.util.GregorianCalendar; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -37,6 +41,8 @@ import org.springframework.test.util.ReflectionTestUtils; * @author Oliver Gierke * @author Wim Deblauwe * @author Mark Paluch + * @author Jens Schauder + * @author Christoph Strobl */ class ProxyProjectionFactoryUnitTests { @@ -276,17 +282,47 @@ class ProxyProjectionFactoryUnitTests { }); } + @Test // DATACMNS-1836 + void supportsDateToLocalDateTimeConversion() { + + Customer customer = new Customer(); + customer.firstname = "Dave"; + customer.birthdate = new GregorianCalendar(1967, Calendar.JANUARY, 9).getTime(); + + customer.address = new Address(); + customer.address.city = "New York"; + customer.address.zipCode = "ZIP"; + + CustomerWithLocalDateTime excerpt = factory.createProjection(CustomerWithLocalDateTime.class, customer); + + assertThat(excerpt.getFirstname()).isEqualTo("Dave"); + assertThat(excerpt.getBirthdate()).isEqualTo(LocalDateTime.of(1967, 1, 9, 0, 0)); + } + + @Test // DATACMNS-1836 + void supportsNullableWrapperDateToLocalDateTimeConversion() { + + Customer customer = new Customer(); + customer.firstname = "Dave"; + customer.birthdate = new GregorianCalendar(1967, Calendar.JANUARY, 9).getTime(); + + customer.address = new Address(); + customer.address.city = "New York"; + customer.address.zipCode = "ZIP"; + + CustomerWithOptional excerpt = factory.createProjection(CustomerWithOptional.class, customer); + + assertThat(excerpt.getFirstname()).isEqualTo("Dave"); + assertThat(excerpt.getBirthdate()).contains(LocalDateTime.of(1967, 1, 9, 0, 0)); + } + interface Contact {} - static class Customer implements Contact { + interface CustomerWithLocalDateTime { - Long id; - String firstname, lastname; - Address address; - byte[] picture; - Address[] shippingAddresses; - Map data; - Optional optional; + String getFirstname(); + + LocalDateTime getBirthdate(); } static class Address { @@ -328,6 +364,8 @@ class ProxyProjectionFactoryUnitTests { Optional getPicture(); Optional getOptional(); + + Optional getBirthdate(); } interface CustomerWithOptionalHavingProjection { @@ -336,4 +374,16 @@ class ProxyProjectionFactoryUnitTests { Optional getAddress(); } + + static class Customer implements Contact { + + Long id; + String firstname, lastname; + Date birthdate; + Address address; + byte[] picture; + Address[] shippingAddresses; + Map data; + Optional optional; + } }