diff --git a/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java b/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java index 7ed61c8ab..17b432695 100644 --- a/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java +++ b/src/main/java/org/springframework/data/projection/DefaultProjectionInformation.java @@ -20,15 +20,17 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import org.springframework.beans.BeanUtils; +import org.springframework.data.util.ReflectionUtils; import org.springframework.util.Assert; /** * Default implementation of {@link ProjectionInformation}. Exposes all properties of the type as required input * properties. - * + * * @author Oliver Gierke * @since 1.12 */ @@ -39,7 +41,7 @@ class DefaultProjectionInformation implements ProjectionInformation { /** * Creates a new {@link DefaultProjectionInformation} for the given type. - * + * * @param type must not be {@literal null}. */ public DefaultProjectionInformation(Class type) { @@ -47,10 +49,10 @@ class DefaultProjectionInformation implements ProjectionInformation { Assert.notNull(type, "Projection type must not be null!"); this.projectionType = type; - this.properties = Arrays.asList(BeanUtils.getPropertyDescriptors(type)); + this.properties = collectDescriptors(type); } - /* + /* * (non-Javadoc) * @see org.springframework.data.projection.ProjectionInformation#getType() */ @@ -71,7 +73,7 @@ class DefaultProjectionInformation implements ProjectionInformation { .collect(Collectors.toList()); } - /* + /* * (non-Javadoc) * @see org.springframework.data.projection.ProjectionInformation#isDynamic() */ @@ -84,7 +86,7 @@ class DefaultProjectionInformation implements ProjectionInformation { * Returns whether the given {@link PropertyDescriptor} describes an input property for the projection, i.e. a * property that needs to be present on the source to be able to create reasonable projections for the type the * descriptor was looked up on. - * + * * @param descriptor will never be {@literal null}. * @return */ @@ -92,6 +94,26 @@ class DefaultProjectionInformation implements ProjectionInformation { return true; } + /** + * Collects {@link PropertyDescriptor}s for all properties exposed by the given type and all its super interfaces. + * + * @param type must not be {@literal null}. + * @return + */ + private static List collectDescriptors(Class type) { + + List result = new ArrayList(); + result.addAll(Arrays.stream(BeanUtils.getPropertyDescriptors(type))// + .filter(it -> !hasDefaultGetter(it))// + .collect(Collectors.toList())); + + for (Class interfaze : type.getInterfaces()) { + result.addAll(collectDescriptors(interfaze)); + } + + return result.stream().distinct().collect(Collectors.toList()); + } + /** * Returns whether the given {@link PropertyDescriptor} has a getter that is a Java 8 default method. * diff --git a/src/main/java/org/springframework/data/util/Optionals.java b/src/main/java/org/springframework/data/util/Optionals.java index fe57165d2..d40a51d33 100644 --- a/src/main/java/org/springframework/data/util/Optionals.java +++ b/src/main/java/org/springframework/data/util/Optionals.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ import org.springframework.util.Assert; /** * Utility methods to work with {@link Optional}s. - * + * * @author Oliver Gierke */ @UtilityClass @@ -40,7 +40,7 @@ public class Optionals { /** * Returns whether any of the given {@link Optional}s is present. - * + * * @param optionals must not be {@literal null}. * @return */ @@ -53,7 +53,7 @@ public class Optionals { /** * Turns the given {@link Optional} into a one-element {@link Stream} or an empty one if not present. - * + * * @param optionals must not be {@literal null}. * @return */ @@ -67,7 +67,7 @@ public class Optionals { /** * Applies the given function to the elements of the source and returns the first non-empty result. - * + * * @param source must not be {@literal null}. * @param function must not be {@literal null}. * @return @@ -85,7 +85,7 @@ public class Optionals { /** * Applies the given function to the elements of the source and returns the first non-empty result. - * + * * @param source must not be {@literal null}. * @param function must not be {@literal null}. * @return @@ -103,7 +103,7 @@ public class Optionals { /** * Invokes the given {@link Supplier}s for {@link Optional} results one by one and returns the first non-empty one. - * + * * @param suppliers must not be {@literal null}. * @return */ @@ -117,7 +117,7 @@ public class Optionals { /** * Invokes the given {@link Supplier}s for {@link Optional} results one by one and returns the first non-empty one. - * + * * @param suppliers must not be {@literal null}. * @return */ @@ -134,7 +134,7 @@ public class Optionals { /** * Returns the next element of the given {@link Iterator} or {@link Optional#empty()} in case there is no next * element. - * + * * @param iterator must not be {@literal null}. * @return */ @@ -148,7 +148,7 @@ public class Optionals { /** * Returns a {@link Pair} if both {@link Optional} instances have values or {@link Optional#empty()} if one or both * are missing. - * + * * @param left * @param right * @return @@ -159,7 +159,7 @@ public class Optionals { /** * Invokes the given {@link BiConsumer} if all given {@link Optional} are present. - * + * * @param left must not be {@literal null}. * @param right must not be {@literal null}. * @param consumer must not be {@literal null}. @@ -178,7 +178,7 @@ public class Optionals { /** * Maps the values contained in the given {@link Optional} if both of them are present. - * + * * @param left must not be {@literal null}. * @param right must not be {@literal null}. * @param function must not be {@literal null}. diff --git a/src/test/java/org/springframework/data/projection/DefaultProjectionInformationUnitTests.java b/src/test/java/org/springframework/data/projection/DefaultProjectionInformationUnitTests.java index 4e51dca42..016ee2be2 100755 --- a/src/test/java/org/springframework/data/projection/DefaultProjectionInformationUnitTests.java +++ b/src/test/java/org/springframework/data/projection/DefaultProjectionInformationUnitTests.java @@ -60,6 +60,7 @@ public class DefaultProjectionInformationUnitTests { return descriptors.stream()// .map(FeatureDescriptor::getName)// + .distinct() .collect(Collectors.toList()); }