From a946d651ffbc72879a52dc0b593861251376b547 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 23 Dec 2016 12:53:36 +0100 Subject: [PATCH] DATACMNS-967 - Getters that are default methods are not considered projection input properties anymore. We now exclude getter methods that are default methods from the consideration which properties of a projection interface are considered input properties in the first place. Some additional Java 8 polish in DefaultProjectionInformation. --- .../DefaultProjectionInformation.java | 31 +++++++++++------ .../SpelAwareProxyProjectionFactory.java | 4 +++ ...DefaultProjectionInformationUnitTests.java | 33 ++++++++++++++----- 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java b/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java index 4cb6adb28..c72b95cfa 100644 --- a/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java +++ b/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java @@ -16,9 +16,11 @@ package org.springframework.data.projection; import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import org.springframework.beans.BeanUtils; import org.springframework.util.Assert; @@ -63,15 +65,9 @@ class DefaultProjectionInformation implements ProjectionInformation { */ public List getInputProperties() { - List result = new ArrayList(); - - for (PropertyDescriptor descriptor : properties) { - if (isInputProperty(descriptor)) { - result.add(descriptor); - } - } - - return result; + return properties.stream()// + .filter(it -> isInputProperty(it))// + .collect(Collectors.toList()); } /* @@ -104,7 +100,10 @@ class DefaultProjectionInformation implements ProjectionInformation { private static List collectDescriptors(Class type) { List result = new ArrayList(); - result.addAll(Arrays.asList(BeanUtils.getPropertyDescriptors(type))); + + result.addAll(Arrays.stream(BeanUtils.getPropertyDescriptors(type))// + .filter(it -> !hasDefaultGetter(it))// + .collect(Collectors.toList())); for (Class interfaze : type.getInterfaces()) { result.addAll(collectDescriptors(interfaze)); @@ -112,4 +111,16 @@ class DefaultProjectionInformation implements ProjectionInformation { return result; } + + /** + * Returns whether the given {@link PropertyDescriptor} has a getter that is a Java 8 default method. + * + * @param descriptor must not be {@literal null}. + * @return + */ + private static boolean hasDefaultGetter(PropertyDescriptor descriptor) { + + Method method = descriptor.getReadMethod(); + return method == null ? false : method.isDefault(); + } } diff --git a/src/main/java/org/springframework/data/projection/SpelAwareProxyProjectionFactory.java b/src/main/java/org/springframework/data/projection/SpelAwareProxyProjectionFactory.java index 91fa404c5..5493d5e4d 100644 --- a/src/main/java/org/springframework/data/projection/SpelAwareProxyProjectionFactory.java +++ b/src/main/java/org/springframework/data/projection/SpelAwareProxyProjectionFactory.java @@ -96,6 +96,10 @@ public class SpelAwareProxyProjectionFactory extends ProxyProjectionFactory impl @Override protected boolean isInputProperty(PropertyDescriptor descriptor) { + if (!super.isInputProperty(descriptor)) { + return false; + } + Method readMethod = descriptor.getReadMethod(); if (readMethod == null) { diff --git a/src/test/java/org/springframework/data/projection/DefaultProjectionInformationUnitTests.java b/src/test/java/org/springframework/data/projection/DefaultProjectionInformationUnitTests.java index e12979e64..ffa557c07 100644 --- a/src/test/java/org/springframework/data/projection/DefaultProjectionInformationUnitTests.java +++ b/src/test/java/org/springframework/data/projection/DefaultProjectionInformationUnitTests.java @@ -19,8 +19,8 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import java.beans.PropertyDescriptor; -import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import org.junit.Test; @@ -53,15 +53,23 @@ public class DefaultProjectionInformationUnitTests { assertThat(toNames(information.getInputProperties()), hasItems("age", "firstname", "lastname")); } + /** + * @see DATACMNS-967 + */ + @Test + public void doesNotConsiderDefaultMethodInputProperties() throws Exception { + + ProjectionInformation information = new DefaultProjectionInformation(WithDefaultMethod.class); + + assertThat(information.isClosed(), is(true)); + assertThat(toNames(information.getInputProperties()), hasItems("firstname")); + } + private static List toNames(List descriptors) { - List names = new ArrayList(descriptors.size()); - - for (PropertyDescriptor descriptor : descriptors) { - names.add(descriptor.getName()); - } - - return names; + return descriptors.stream()// + .map(it -> it.getName())// + .collect(Collectors.toList()); } interface CustomerProjection { @@ -75,4 +83,13 @@ public class DefaultProjectionInformationUnitTests { int getAge(); } + + interface WithDefaultMethod { + + String getFirstname(); + + default String getLastname() { + return null; + } + } }