diff --git a/src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java b/src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java index c9f0c68e3..013522815 100644 --- a/src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java +++ b/src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java @@ -26,6 +26,8 @@ import java.util.Map.Entry; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.core.CollectionFactory; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; @@ -43,6 +45,7 @@ class ProjectingMethodInterceptor implements MethodInterceptor { private final ProjectionFactory factory; private final MethodInterceptor delegate; + private final ConversionService conversionService; /** * Creates a new {@link ProjectingMethodInterceptor} using the given {@link ProjectionFactory} and delegate @@ -59,6 +62,7 @@ class ProjectingMethodInterceptor implements MethodInterceptor { this.factory = factory; this.delegate = delegate; + this.conversionService = new DefaultConversionService(); } /* @@ -75,13 +79,16 @@ class ProjectingMethodInterceptor implements MethodInterceptor { } TypeInformation type = ClassTypeInformation.fromReturnTypeOf(invocation.getMethod()); + Class rawType = type.getType(); - if (type.isCollectionLike() && !ClassUtils.isPrimitiveArray(type.getType())) { + if (type.isCollectionLike() && !ClassUtils.isPrimitiveArray(rawType)) { return projectCollectionElements(asCollection(result), type); } else if (type.isMap()) { return projectMapValues((Map) result, type); + } else if (conversionRequiredAndPossible(result, rawType)) { + return conversionService.convert(result, rawType); } else { - return getProjection(result, type.getType()); + return getProjection(result, rawType); } } @@ -134,6 +141,23 @@ class ProjectingMethodInterceptor implements MethodInterceptor { : factory.createProjection(returnType, result); } + /** + * Returns whether the source object needs to be converted to the given target type and whether we can convert it at + * all. + * + * @param source can be {@literal null}. + * @param targetType must not be {@literal null}. + * @return + */ + private boolean conversionRequiredAndPossible(Object source, Class targetType) { + + if (source == null || targetType.isInstance(source)) { + return false; + } + + return conversionService.canConvert(source.getClass(), targetType); + } + /** * Turns the given value into a {@link Collection}. Will turn an array into a collection an wrap all other values into * a single-element collection. diff --git a/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java b/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java index 4952caa1f..91c7830ac 100644 --- a/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java @@ -157,7 +157,7 @@ public class ProxyProjectionFactoryUnitTests { List result = factory.getInputProperties(CustomerExcerpt.class); - assertThat(result, hasSize(4)); + assertThat(result, hasSize(5)); assertThat(result, hasItems("firstname", "address", "shippingAddresses", "picture")); } @@ -220,8 +220,23 @@ public class ProxyProjectionFactoryUnitTests { assertThat(excerpt.getShippingAddresses(), is(arrayWithSize(1))); } + /** + * @see DATACMNS-782 + */ + @Test + public void convertsPrimitiveValues() { + + Customer customer = new Customer(); + customer.id = 1L; + + CustomerExcerpt excerpt = factory.createProjection(CustomerExcerpt.class, customer); + + assertThat(excerpt.getId(), is(customer.id.toString())); + } + static class Customer { + public Long id; public String firstname, lastname; public Address address; public byte[] picture; @@ -235,6 +250,8 @@ public class ProxyProjectionFactoryUnitTests { interface CustomerExcerpt { + String getId(); + String getFirstname(); AddressExcerpt getAddress();