diff --git a/src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java b/src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java index bd3b649e0..c9f0c68e3 100644 --- a/src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java +++ b/src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java @@ -15,9 +15,11 @@ */ package org.springframework.data.projection; +import java.lang.reflect.Array; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -28,6 +30,7 @@ import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.ObjectUtils; /** * {@link MethodInterceptor} to delegate the invocation to a different {@link MethodInterceptor} but creating a @@ -73,7 +76,7 @@ class ProjectingMethodInterceptor implements MethodInterceptor { TypeInformation type = ClassTypeInformation.fromReturnTypeOf(invocation.getMethod()); - if (type.isCollectionLike()) { + if (type.isCollectionLike() && !ClassUtils.isPrimitiveArray(type.getType())) { return projectCollectionElements(asCollection(result), type); } else if (type.isMap()) { return projectMapValues((Map) result, type); @@ -90,14 +93,20 @@ class ProjectingMethodInterceptor implements MethodInterceptor { * @param type must not be {@literal null}. * @return */ - private Collection projectCollectionElements(Collection sources, TypeInformation type) { + private Object projectCollectionElements(Collection sources, TypeInformation type) { - Collection result = CollectionFactory.createCollection(type.getType(), sources.size()); + Class rawType = type.getType(); + Collection result = CollectionFactory.createCollection(rawType.isArray() ? List.class : rawType, + sources.size()); for (Object source : sources) { result.add(getProjection(source, type.getComponentType().getType())); } + if (rawType.isArray()) { + return result.toArray((Object[]) Array.newInstance(type.getComponentType().getType(), result.size())); + } + return result; } @@ -121,8 +130,8 @@ class ProjectingMethodInterceptor implements MethodInterceptor { } private Object getProjection(Object result, Class returnType) { - return ClassUtils.isAssignable(returnType, result.getClass()) ? result : factory.createProjection(returnType, - result); + return ClassUtils.isAssignable(returnType, result.getClass()) ? result + : factory.createProjection(returnType, result); } /** @@ -139,7 +148,7 @@ class ProjectingMethodInterceptor implements MethodInterceptor { if (source instanceof Collection) { return (Collection) source; } else if (source.getClass().isArray()) { - return Arrays.asList((Object[]) source); + return Arrays.asList(ObjectUtils.toObjectArray(source)); } else { return Collections.singleton(source); } diff --git a/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java b/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java index 07831f63f..53d9f0067 100644 --- a/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java @@ -157,8 +157,8 @@ public class ProxyProjectionFactoryUnitTests { List result = factory.getInputProperties(CustomerExcerpt.class); - assertThat(result, hasSize(2)); - assertThat(result, hasItems("firstname", "address")); + assertThat(result, hasSize(4)); + assertThat(result, hasItems("firstname", "address", "shippingAddresses", "picture")); } /** @@ -176,10 +176,44 @@ public class ProxyProjectionFactoryUnitTests { assertThat(advisors[0].getAdvice(), is(instanceOf(DefaultMethodInvokingMethodInterceptor.class))); } + /** + * @see DATACMNS-722 + */ + @Test + public void doesNotProjectPrimitiveArray() { + + Customer customer = new Customer(); + customer.picture = "binarydata".getBytes(); + + CustomerExcerpt excerpt = factory.createProjection(CustomerExcerpt.class, customer); + + assertThat(excerpt.getPicture(), is(customer.picture)); + } + + /** + * @see DATACMNS-722 + */ + @Test + public void projectsNonPrimitiveArray() { + + Address address = new Address(); + address.city = "New York"; + address.zipCode = "ZIP"; + + Customer customer = new Customer(); + customer.shippingAddresses = new Address[] { address }; + + CustomerExcerpt excerpt = factory.createProjection(CustomerExcerpt.class, customer); + + assertThat(excerpt.getShippingAddresses(), is(arrayWithSize(1))); + } + static class Customer { public String firstname, lastname; public Address address; + public byte[] picture; + public Address[] shippingAddresses; } static class Address { @@ -192,6 +226,10 @@ public class ProxyProjectionFactoryUnitTests { String getFirstname(); AddressExcerpt getAddress(); + + AddressExcerpt[] getShippingAddresses(); + + byte[] getPicture(); } interface AddressExcerpt {