Browse Source

DATACMNS-722 - ProxyProjectionFactory now deals with arrays.

We now handle primitive and non-primitive arrays in ProxyProjectionFactory. WE basically skip element projections for the former and correctly implement exactly that for the latter.
1.10.x
Oliver Gierke 11 years ago
parent
commit
d641f978bf
  1. 21
      src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java
  2. 42
      src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java

21
src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java

@ -15,9 +15,11 @@
*/ */
package org.springframework.data.projection; package org.springframework.data.projection;
import java.lang.reflect.Array;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -28,6 +30,7 @@ import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation; import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
/** /**
* {@link MethodInterceptor} to delegate the invocation to a different {@link MethodInterceptor} but creating a * {@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()); TypeInformation<?> type = ClassTypeInformation.fromReturnTypeOf(invocation.getMethod());
if (type.isCollectionLike()) { if (type.isCollectionLike() && !ClassUtils.isPrimitiveArray(type.getType())) {
return projectCollectionElements(asCollection(result), type); return projectCollectionElements(asCollection(result), type);
} else if (type.isMap()) { } else if (type.isMap()) {
return projectMapValues((Map<?, ?>) result, type); return projectMapValues((Map<?, ?>) result, type);
@ -90,14 +93,20 @@ class ProjectingMethodInterceptor implements MethodInterceptor {
* @param type must not be {@literal null}. * @param type must not be {@literal null}.
* @return * @return
*/ */
private Collection<Object> projectCollectionElements(Collection<?> sources, TypeInformation<?> type) { private Object projectCollectionElements(Collection<?> sources, TypeInformation<?> type) {
Collection<Object> result = CollectionFactory.createCollection(type.getType(), sources.size()); Class<?> rawType = type.getType();
Collection<Object> result = CollectionFactory.createCollection(rawType.isArray() ? List.class : rawType,
sources.size());
for (Object source : sources) { for (Object source : sources) {
result.add(getProjection(source, type.getComponentType().getType())); result.add(getProjection(source, type.getComponentType().getType()));
} }
if (rawType.isArray()) {
return result.toArray((Object[]) Array.newInstance(type.getComponentType().getType(), result.size()));
}
return result; return result;
} }
@ -121,8 +130,8 @@ class ProjectingMethodInterceptor implements MethodInterceptor {
} }
private Object getProjection(Object result, Class<?> returnType) { private Object getProjection(Object result, Class<?> returnType) {
return ClassUtils.isAssignable(returnType, result.getClass()) ? result : factory.createProjection(returnType, return ClassUtils.isAssignable(returnType, result.getClass()) ? result
result); : factory.createProjection(returnType, result);
} }
/** /**
@ -139,7 +148,7 @@ class ProjectingMethodInterceptor implements MethodInterceptor {
if (source instanceof Collection) { if (source instanceof Collection) {
return (Collection<?>) source; return (Collection<?>) source;
} else if (source.getClass().isArray()) { } else if (source.getClass().isArray()) {
return Arrays.asList((Object[]) source); return Arrays.asList(ObjectUtils.toObjectArray(source));
} else { } else {
return Collections.singleton(source); return Collections.singleton(source);
} }

42
src/test/java/org/springframework/data/projection/ProxyProjectionFactoryUnitTests.java

@ -157,8 +157,8 @@ public class ProxyProjectionFactoryUnitTests {
List<String> result = factory.getInputProperties(CustomerExcerpt.class); List<String> result = factory.getInputProperties(CustomerExcerpt.class);
assertThat(result, hasSize(2)); assertThat(result, hasSize(4));
assertThat(result, hasItems("firstname", "address")); assertThat(result, hasItems("firstname", "address", "shippingAddresses", "picture"));
} }
/** /**
@ -176,10 +176,44 @@ public class ProxyProjectionFactoryUnitTests {
assertThat(advisors[0].getAdvice(), is(instanceOf(DefaultMethodInvokingMethodInterceptor.class))); 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 { static class Customer {
public String firstname, lastname; public String firstname, lastname;
public Address address; public Address address;
public byte[] picture;
public Address[] shippingAddresses;
} }
static class Address { static class Address {
@ -192,6 +226,10 @@ public class ProxyProjectionFactoryUnitTests {
String getFirstname(); String getFirstname();
AddressExcerpt getAddress(); AddressExcerpt getAddress();
AddressExcerpt[] getShippingAddresses();
byte[] getPicture();
} }
interface AddressExcerpt { interface AddressExcerpt {

Loading…
Cancel
Save