diff --git a/src/main/java/org/springframework/data/util/Predicates.java b/src/main/java/org/springframework/data/util/Predicates.java index 7821c51a9..c7f3e9344 100644 --- a/src/main/java/org/springframework/data/util/Predicates.java +++ b/src/main/java/org/springframework/data/util/Predicates.java @@ -15,6 +15,7 @@ */ package org.springframework.data.util; +import java.lang.reflect.Constructor; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -30,22 +31,24 @@ import org.springframework.util.Assert; */ public interface Predicates { - public static final Predicate IS_ENUM_MEMBER = member -> member.getDeclaringClass().isEnum(); - public static final Predicate IS_HIBERNATE_MEMBER = member -> member.getName().startsWith("$$_hibernate"); // this + Predicate IS_ENUM_MEMBER = member -> member.getDeclaringClass().isEnum(); + Predicate IS_HIBERNATE_MEMBER = member -> member.getName().startsWith("$$_hibernate"); // this // should // go // into // JPA - public static final Predicate IS_OBJECT_MEMBER = member -> Object.class.equals(member.getDeclaringClass()); - public static final Predicate IS_JAVA = member -> member.getDeclaringClass().getPackageName().startsWith("java."); - public static final Predicate IS_NATIVE = member -> Modifier.isNative(member.getModifiers()); - public static final Predicate IS_PRIVATE = member -> Modifier.isPrivate(member.getModifiers()); - public static final Predicate IS_PROTECTED = member -> Modifier.isProtected(member.getModifiers()); - public static final Predicate IS_PUBLIC = member -> Modifier.isPublic(member.getModifiers()); - public static final Predicate IS_SYNTHETIC = Member::isSynthetic; - public static final Predicate IS_STATIC = member -> Modifier.isStatic(member.getModifiers()); + Predicate IS_OBJECT_MEMBER = member -> Object.class.equals(member.getDeclaringClass()); + Predicate IS_JAVA = member -> member.getDeclaringClass().getPackageName().startsWith("java."); + Predicate IS_NATIVE = member -> Modifier.isNative(member.getModifiers()); + Predicate IS_PRIVATE = member -> Modifier.isPrivate(member.getModifiers()); + Predicate IS_PROTECTED = member -> Modifier.isProtected(member.getModifiers()); + Predicate IS_PUBLIC = member -> Modifier.isPublic(member.getModifiers()); + Predicate IS_SYNTHETIC = Member::isSynthetic; - public static final Predicate IS_BRIDGE_METHOD = Method::isBridge; + Predicate> IS_KOTLIN = KotlinReflectionUtils::isSupportedKotlinClass; + Predicate IS_STATIC = member -> Modifier.isStatic(member.getModifiers()); + + Predicate IS_BRIDGE_METHOD = Method::isBridge; /** * A {@link Predicate} that yields always {@code true}. @@ -75,4 +78,29 @@ public interface Predicates { Assert.notNull(predicate, "Predicate must not be null"); return predicate.negate(); } + + /** + * Whether to consider a {@link Constructor}. We generally exclude synthetic constructors for non-Kotlin classes. + * + * @param candidate + * @return + */ + static boolean isIncluded(Constructor candidate) { + return !isExcluded(candidate); + } + + /** + * Whether to not consider a {@link Constructor}. We generally exclude synthetic constructors for non-Kotlin classes. + * + * @param candidate + * @return + */ + static boolean isExcluded(Constructor candidate) { + + if (IS_KOTLIN.test(candidate.getDeclaringClass())) { + return false; + } + + return IS_SYNTHETIC.test(candidate); + } } diff --git a/src/main/java/org/springframework/data/util/TypeCollector.java b/src/main/java/org/springframework/data/util/TypeCollector.java index 818bb35e3..704fd1040 100644 --- a/src/main/java/org/springframework/data/util/TypeCollector.java +++ b/src/main/java/org/springframework/data/util/TypeCollector.java @@ -20,16 +20,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.Consumer; import java.util.function.Predicate; @@ -40,9 +31,15 @@ import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; /** + * Collector to inspect domain types and discover the type graph that is relevant for Spring Data operations. + *

+ * Type inspection walks through all class members (fields, methods, constructors) and introspects those for additional + * types that are part of the domain model. + * * @author Christoph Strobl * @author Sebastien Deleuze * @author John Blum + * @since 3.0 */ public class TypeCollector { @@ -122,13 +119,16 @@ public class TypeCollector { } Set visitConstructorsOfType(ResolvableType type) { + if (!typeFilter.test(type.toClass())) { return Collections.emptySet(); } + Set discoveredTypes = new LinkedHashSet<>(); + for (Constructor constructor : type.toClass().getDeclaredConstructors()) { - if (constructor.isSynthetic()) { + if (Predicates.isExcluded(constructor)) { continue; } for (Class signatureType : TypeUtils.resolveTypesInSignature(type.toClass(), constructor)) { @@ -137,10 +137,12 @@ public class TypeCollector { } } } + return new HashSet<>(discoveredTypes); } Set visitMethodsOfType(ResolvableType type) { + if (!typeFilter.test(type.toClass())) { return Collections.emptySet(); } @@ -160,11 +162,14 @@ public class TypeCollector { } catch (Exception cause) { logger.warn(cause); } + return new HashSet<>(discoveredTypes); } Set visitFieldsOfType(ResolvableType type) { + Set discoveredTypes = new LinkedHashSet<>(); + ReflectionUtils.doWithLocalFields(type.toClass(), field -> { if (!fieldFilter.test(field)) { return; @@ -175,6 +180,7 @@ public class TypeCollector { } } }); + return discoveredTypes; }