diff --git a/src/main/java/org/springframework/data/aot/AotContext.java b/src/main/java/org/springframework/data/aot/AotContext.java
index 48edc6fdf..fcd666c43 100644
--- a/src/main/java/org/springframework/data/aot/AotContext.java
+++ b/src/main/java/org/springframework/data/aot/AotContext.java
@@ -17,6 +17,7 @@ package org.springframework.data.aot;
import java.lang.annotation.Annotation;
import java.util.Collection;
+import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
@@ -26,26 +27,23 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.data.util.TypeScanner;
-import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.ObjectUtils;
/**
- * The context in which the AOT processing happens.
- *
- * Grants access to the {@link ConfigurableListableBeanFactory beanFactory} and {@link ClassLoader}. Holds a few
- * convenience methods to check if a type {@link #isTypePresent(String) is present} and allows resolution of them.
- *
- * WARNING: Unstable internal API!
+ * The context in which the AOT processing happens. Grants access to the {@link ConfigurableListableBeanFactory
+ * beanFactory} and {@link ClassLoader}. Holds a few convenience methods to check if a type
+ * {@link #isTypePresent(String) is present} and allows resolution of them throug {@link TypeIntrospector} and
+ * {@link IntrospectedBeanDefinition}.
+ *
+ * Mainly for internal use within the framework.
*
* @author Christoph Strobl
* @author John Blum
- * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory
+ * @author Mark Paluch
+ * @see BeanFactory
* @since 3.0
*/
public interface AotContext {
@@ -57,22 +55,11 @@ public interface AotContext {
* @return a new instance of {@link AotContext}.
* @see BeanFactory
*/
- static AotContext from(@NonNull BeanFactory beanFactory) {
+ static AotContext from(BeanFactory beanFactory) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
- return new AotContext() {
-
- private final ConfigurableListableBeanFactory bf = beanFactory instanceof ConfigurableListableBeanFactory
- ? (ConfigurableListableBeanFactory) beanFactory
- : new DefaultListableBeanFactory(beanFactory);
-
- @NonNull
- @Override
- public ConfigurableListableBeanFactory getBeanFactory() {
- return bf;
- }
- };
+ return new DefaultAotContext(beanFactory);
}
/**
@@ -84,10 +71,9 @@ public interface AotContext {
ConfigurableListableBeanFactory getBeanFactory();
/**
- * Returns the {@link ClassLoader} used by this {@link AotContext} to resolve {@link Class types}.
- *
- * By default, this is the same {@link ClassLoader} used by the {@link BeanFactory} to resolve {@link Class types}
- * declared in bean definitions.
+ * Returns the {@link ClassLoader} used by this {@link AotContext} to resolve {@link Class types}. By default, this is
+ * the same {@link ClassLoader} used by the {@link BeanFactory} to resolve {@link Class types} declared in bean
+ * definitions.
*
* @return the {@link ClassLoader} used by this {@link AotContext} to resolve {@link Class types}.
* @see ConfigurableListableBeanFactory#getBeanClassLoader()
@@ -98,184 +84,196 @@ public interface AotContext {
}
/**
- * Determines whether the given {@link String named} {@link Class type} is present on the application classpath.
+ * Returns the required {@link ClassLoader} used by this {@link AotContext} to resolve {@link Class types}. By
+ * default, this is the same {@link ClassLoader} used by the {@link BeanFactory} to resolve {@link Class types}
+ * declared in bean definitions.
+ *
+ * @return the {@link ClassLoader} used by this {@link AotContext} to resolve {@link Class types}.
+ * @throws IllegalStateException if no {@link ClassLoader} is available.
+ */
+ default ClassLoader getRequiredClassLoader() {
+
+ ClassLoader loader = getClassLoader();
+
+ if (loader == null) {
+ throw new IllegalStateException("Required ClassLoader is not available");
+ }
+
+ return loader;
+ }
+
+ /**
+ * Returns a {@link TypeIntrospector} to obtain further detail about a {@link Class type} given its fully-qualified
+ * type name
*
* @param typeName {@link String name} of the {@link Class type} to evaluate; must not be {@literal null}.
- * @return {@literal true} if the given {@link String named} {@link Class type} is present
- * on the application classpath.
- * @see #getClassLoader()
+ * @return the type introspector for further type-based introspection.
*/
- default boolean isTypePresent(@NonNull String typeName) {
- return ClassUtils.isPresent(typeName, getClassLoader());
- }
+ TypeIntrospector introspectType(String typeName);
/**
* Returns a new {@link TypeScanner} used to scan for {@link Class types} that will be contributed to the AOT
* processing infrastructure.
*
- * @return a {@link TypeScanner} used to scan for {@link Class types} that will be contributed to the AOT
- * processing infrastructure.
+ * @return a {@link TypeScanner} used to scan for {@link Class types} that will be contributed to the AOT processing
+ * infrastructure.
* @see TypeScanner
*/
- @NonNull
default TypeScanner getTypeScanner() {
- return TypeScanner.typeScanner(getClassLoader());
+ return TypeScanner.typeScanner(getRequiredClassLoader());
}
/**
* Scans for {@link Class types} in the given {@link String named packages} annotated with the store-specific
* {@link Annotation identifying annotations}.
*
- * @param identifyingAnnotations {@link Collection} of {@link Annotation Annotations} identifying store-specific
- * model {@link Class types}; must not be {@literal null}.
+ * @param identifyingAnnotations {@link Collection} of {@link Annotation Annotations} identifying store-specific model
+ * {@link Class types}; must not be {@literal null}.
* @param packageNames {@link Collection} of {@link String package names} to scan.
* @return a {@link Set} of {@link Class types} found during the scan.
* @see #getTypeScanner()
*/
- default Set> scanPackageForTypes(@NonNull Collection> identifyingAnnotations,
+ default Set> scanPackageForTypes(Collection> identifyingAnnotations,
Collection packageNames) {
return getTypeScanner().scanPackages(packageNames).forTypesAnnotatedWith(identifyingAnnotations).collectAsSet();
}
/**
- * Resolves the required {@link String named} {@link Class type}.
+ * Returns a {@link IntrospectedBeanDefinition} to obtain further detail about the underlying bean definition. A
+ * introspected bean definition can also point to an absent bean definition.
*
- * @param typeName {@link String} containing the {@literal fully-qualified class name} of the {@link Class type}
- * to resolve; must not be {@literal null}.
- * @return a resolved {@link Class type} for the given, required {@link String name}.
- * @throws TypeNotPresentException if the {@link String named} {@link Class type} cannot be found.
+ * @param reference {@link BeanReference} to the managed bean.
+ * @return the introspected bean definition.
*/
- @NonNull
- default Class> resolveRequiredType(@NonNull String typeName) throws TypeNotPresentException {
-
- try {
- return ClassUtils.forName(typeName, getClassLoader());
- } catch (ClassNotFoundException cause) {
- throw new TypeNotPresentException(typeName, cause);
- }
+ default IntrospectedBeanDefinition introspectBeanDefinition(BeanReference reference) {
+ return introspectBeanDefinition(reference.getBeanName());
}
/**
- * Resolves the given {@link String named} {@link Class type} if present.
+ * Returns a {@link IntrospectedBeanDefinition} to obtain further detail about the underlying bean definition. A
+ * introspected bean definition can also point to an absent bean definition.
*
- * @param typeName {@link String} containing the {@literal fully-qualified class name} of the {@link Class type}
- * to resolve; must not be {@literal null}.
- * @return an {@link Optional} value containing the {@link Class type}
- * if the {@link String fully-qualified class name} is present on the application classpath.
- * @see #isTypePresent(String)
- * @see #resolveRequiredType(String)
- * @see java.util.Optional
+ * @param beanName {@link String} containing the {@literal name} of the bean to evaluate; must not be {@literal null}.
+ * @return the introspected bean definition.
*/
- default Optional> resolveType(@NonNull String typeName) {
-
- return isTypePresent(typeName)
- ? Optional.of(resolveRequiredType(typeName))
- : Optional.empty();
- }
+ IntrospectedBeanDefinition introspectBeanDefinition(String beanName);
/**
- * Resolves the {@link BeanDefinition bean's} defined {@link Class type}.
- *
- * @param beanReference {@link BeanReference} to the managed bean.
- * @return the {@link Class type} of the {@link BeanReference referenced bean} if defined; may be {@literal null}.
- * @see BeanReference
+ * Type-based introspector to resolve {@link Class} from a type name and to introspect the bean factory for presence
+ * of beans.
*/
- @Nullable
- default Class> resolveType(@NonNull BeanReference beanReference) {
- return getBeanFactory().getType(beanReference.getBeanName(), false);
- }
+ interface TypeIntrospector {
- /**
- * Gets the {@link BeanDefinition} for the given, required {@link String named bean}.
- *
- * @param beanName {@link String} containing the {@literal name} of the bean; must not be {@literal null}.
- * @return the {@link BeanDefinition} for the given, required {@link String named bean}.
- * @throws NoSuchBeanDefinitionException if a {@link BeanDefinition} cannot be found for
- * the {@link String named bean}.
- * @see BeanDefinition
- */
- @NonNull
- default BeanDefinition getBeanDefinition(@NonNull String beanName) throws NoSuchBeanDefinitionException {
- return getBeanFactory().getBeanDefinition(beanName);
- }
+ /**
+ * Determines whether @link Class type} is present on the application classpath.
+ *
+ * @return {@literal true} if the {@link Class type} is present on the application classpath.
+ * @see #getClassLoader()
+ */
+ boolean isTypePresent();
- /**
- * Gets the {@link RootBeanDefinition} for the given, required {@link String bean name}.
- *
- * @param beanName {@link String} containing the {@literal name} of the bean.
- * @return the {@link RootBeanDefinition} for the given, required {@link String bean name}.
- * @throws NoSuchBeanDefinitionException if a {@link BeanDefinition} cannot be found for
- * the {@link String named bean}.
- * @throws IllegalStateException if the bean is not a {@link RootBeanDefinition root bean}.
- * @see RootBeanDefinition
- */
- @NonNull
- default RootBeanDefinition getRootBeanDefinition(@NonNull String beanName) throws NoSuchBeanDefinitionException {
+ /**
+ * Resolves the required {@link String named} {@link Class type}.
+ *
+ * @return a resolved {@link Class type} for the given.
+ * @throws TypeNotPresentException if the {@link Class type} cannot be found.
+ */
+ Class> resolveRequiredType() throws TypeNotPresentException;
- BeanDefinition beanDefinition = getBeanDefinition(beanName);
+ /**
+ * Resolves the {@link Class type} if present.
+ *
+ * @return an {@link Optional} value containing the {@link Class type} if the type is present on the application
+ * classpath.
+ * @see #isTypePresent()
+ * @see #resolveRequiredType()
+ * @see java.util.Optional
+ */
+ Optional> resolveType();
- if (beanDefinition instanceof RootBeanDefinition rootBeanDefinition) {
- return rootBeanDefinition;
+ /**
+ * Determines whether the {@link Class type} is declared on the application classpath and performs the given,
+ * required {@link Consumer action} if present.
+ *
+ * @param action {@link Consumer} defining the action to perform on the resolved {@link Class type}; must not be
+ * {@literal null}.
+ * @see java.util.function.Consumer
+ * @see #resolveType()
+ */
+ default void ifTypePresent(Consumer> action) {
+ resolveType().ifPresent(action);
}
- throw new IllegalStateException(String.format("%s is not a root bean", beanName));
+ /**
+ * Determines whether the associated bean factory contains at least one bean of this type.
+ *
+ * @return {@literal true} if the {@link Class type} is present on the application classpath.
+ */
+ boolean hasBean();
+
+ /**
+ * Return a {@link List} containing bean names that implement this type.
+ *
+ * @return a {@link List} of bean names. The list is empty if the bean factory does not hold any beans of this type.
+ */
+ List getBeanNames();
+
}
/**
- * Determines whether a bean identified by the given, required {@link String name} is a
- * {@link org.springframework.beans.factory.FactoryBean}.
- *
- * @param beanName {@link String} containing the {@literal name} of the bean to evaluate;
- * must not be {@literal null}.
- * @return {@literal true} if the bean identified by the given, required {@link String name} is a
- * {@link org.springframework.beans.factory.FactoryBean}.
+ * Interface defining introspection methods for bean definitions.
*/
- default boolean isFactoryBean(@NonNull String beanName) {
- return getBeanFactory().isFactoryBean(beanName);
+ interface IntrospectedBeanDefinition {
+
+ /**
+ * Determines whether a bean definition identified by the given, required {@link String name} is present.
+ *
+ * @return {@literal true} if the bean definition identified by the given, required {@link String name} registered
+ * with.
+ */
+ boolean isPresent();
+
+ /**
+ * Determines whether a bean identified by the given, required {@link String name} is a
+ * {@link org.springframework.beans.factory.FactoryBean}.
+ *
+ * @return {@literal true} if the bean identified by the given, required {@link String name} is a
+ * {@link org.springframework.beans.factory.FactoryBean}.
+ */
+ boolean isFactoryBean();
+
+ /**
+ * Gets the {@link BeanDefinition} for the given, required {@link String named bean}.
+ *
+ * @return the {@link BeanDefinition} for the given, required {@link String named bean}.
+ * @throws NoSuchBeanDefinitionException if a {@link BeanDefinition} cannot be found for the {@link String named
+ * bean}.
+ * @see BeanDefinition
+ */
+
+ BeanDefinition getBeanDefinition() throws NoSuchBeanDefinitionException;
+
+ /**
+ * Gets the {@link RootBeanDefinition} for the given, required {@link String bean name}.
+ *
+ * @return the {@link RootBeanDefinition} for the given, required {@link String bean name}.
+ * @throws NoSuchBeanDefinitionException if a {@link BeanDefinition} cannot be found for the {@link String named
+ * bean}.
+ * @throws IllegalStateException if the bean is not a {@link RootBeanDefinition root bean}.
+ * @see RootBeanDefinition
+ */
+ RootBeanDefinition getRootBeanDefinition() throws NoSuchBeanDefinitionException;
+
+ /**
+ * Resolves the {@link BeanDefinition bean's} defined {@link Class type}.
+ *
+ * @return the {@link Class type} of the {@link BeanReference referenced bean} if defined; may be {@literal null}.
+ * @see BeanReference
+ */
+ @Nullable
+ Class> resolveType();
+
}
- /**
- * Determines whether a Spring {@link org.springframework.transaction.TransactionManager} is present.
- *
- * @return {@literal true} if a Spring {@link org.springframework.transaction.TransactionManager} is present.
- */
- default boolean isTransactionManagerPresent() {
-
- return resolveType("org.springframework.transaction.TransactionManager")
- .filter(it -> !ObjectUtils.isEmpty(getBeanFactory().getBeanNamesForType(it)))
- .isPresent();
- }
-
- /**
- * Determines whether the given, required {@link String type name} is declared on the application classpath
- * and performs the given, required {@link Consumer action} if present.
- *
- * @param typeName {@link String name} of the {@link Class type} to process; must not be {@literal null}.
- * @param action {@link Consumer} defining the action to perform on the resolved {@link Class type};
- * must not be {@literal null}.
- * @see java.util.function.Consumer
- * @see #resolveType(String)
- */
- default void ifTypePresent(@NonNull String typeName, @NonNull Consumer> action) {
- resolveType(typeName).ifPresent(action);
- }
-
- /**
- * Runs the given {@link Consumer action} on any {@link org.springframework.transaction.TransactionManager} beans
- * defined in the application context.
- *
- * @param beanNamesConsumer {@link Consumer} defining the action to perform on
- * the {@link org.springframework.transaction.TransactionManager} beans if present; must not be {@literal null}.
- * @see java.util.function.Consumer
- */
- default void ifTransactionManagerPresent(@NonNull Consumer beanNamesConsumer) {
-
- ifTypePresent("org.springframework.transaction.TransactionManager", txMgrType -> {
- String[] txMgrBeanNames = getBeanFactory().getBeanNamesForType(txMgrType);
- if (!ObjectUtils.isEmpty(txMgrBeanNames)) {
- beanNamesConsumer.accept(txMgrBeanNames);
- }
- });
- }
}
diff --git a/src/main/java/org/springframework/data/aot/AotRepositoryInformation.java b/src/main/java/org/springframework/data/aot/AotRepositoryInformation.java
index 1ee8f8cca..c2361a10b 100644
--- a/src/main/java/org/springframework/data/aot/AotRepositoryInformation.java
+++ b/src/main/java/org/springframework/data/aot/AotRepositoryInformation.java
@@ -25,14 +25,11 @@ import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryInformationSupport;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFragment;
-import org.springframework.lang.NonNull;
/**
* {@link RepositoryInformation} based on {@link RepositoryMetadata} collected at build time.
*
* @author Christoph Strobl
- * @see org.springframework.data.repository.core.RepositoryInformation
- * @see org.springframework.data.repository.core.RepositoryMetadata
* @since 3.0
*/
class AotRepositoryInformation extends RepositoryInformationSupport implements RepositoryInformation {
@@ -47,20 +44,19 @@ class AotRepositoryInformation extends RepositoryInformationSupport implements R
}
@Override
- public boolean isCustomMethod(@NonNull Method method) {
+ public boolean isCustomMethod(Method method) {
// TODO:
return false;
}
@Override
- public boolean isBaseClassMethod(@NonNull Method method) {
+ public boolean isBaseClassMethod(Method method) {
// TODO
return false;
}
- @NonNull
@Override
- public Method getTargetClassMethod(@NonNull Method method) {
+ public Method getTargetClassMethod(Method method) {
// TODO
return method;
}
@@ -69,7 +65,6 @@ class AotRepositoryInformation extends RepositoryInformationSupport implements R
* @return configured repository fragments.
* @since 3.0
*/
- @NonNull
public Set> getFragments() {
return new LinkedHashSet<>(fragments.get());
}
diff --git a/src/main/java/org/springframework/data/aot/DefaultAotContext.java b/src/main/java/org/springframework/data/aot/DefaultAotContext.java
new file mode 100644
index 000000000..a6bb28d80
--- /dev/null
+++ b/src/main/java/org/springframework/data/aot/DefaultAotContext.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2022 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.aot;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Default {@link AotContext} implementation.
+ *
+ * @author Mark Paluch
+ * @since 3.0
+ */
+class DefaultAotContext implements AotContext {
+
+ private final ConfigurableListableBeanFactory factory;
+
+ public DefaultAotContext(BeanFactory beanFactory) {
+ factory = beanFactory instanceof ConfigurableListableBeanFactory ? (ConfigurableListableBeanFactory) beanFactory
+ : new DefaultListableBeanFactory(beanFactory);
+ }
+
+ @Override
+ public ConfigurableListableBeanFactory getBeanFactory() {
+ return factory;
+ }
+
+ @Override
+ public TypeIntrospector introspectType(String typeName) {
+ return new DefaultTypeIntrospector(typeName);
+ }
+
+ @Override
+ public IntrospectedBeanDefinition introspectBeanDefinition(String beanName) {
+ return new DefaultIntrospectedBeanDefinition(beanName);
+ }
+
+ class DefaultTypeIntrospector implements TypeIntrospector {
+
+ private final String typeName;
+
+ DefaultTypeIntrospector(String typeName) {
+ this.typeName = typeName;
+ }
+
+ @Override
+ public boolean isTypePresent() {
+ return ClassUtils.isPresent(typeName, getClassLoader());
+ }
+
+ @Override
+ public Class> resolveRequiredType() throws TypeNotPresentException {
+ try {
+ return ClassUtils.forName(typeName, getClassLoader());
+ } catch (ClassNotFoundException cause) {
+ throw new TypeNotPresentException(typeName, cause);
+ }
+ }
+
+ @Override
+ public Optional> resolveType() {
+ return isTypePresent() ? Optional.of(resolveRequiredType()) : Optional.empty();
+ }
+
+ @Override
+ public boolean hasBean() {
+ return !getBeanNames().isEmpty();
+ }
+
+ @Override
+ public List getBeanNames() {
+ return isTypePresent() ? Arrays.asList(factory.getBeanNamesForType(resolveRequiredType()))
+ : Collections.emptyList();
+ }
+ }
+
+ class DefaultIntrospectedBeanDefinition implements IntrospectedBeanDefinition {
+
+ private final String beanName;
+
+ DefaultIntrospectedBeanDefinition(String beanName) {
+ this.beanName = beanName;
+ }
+
+ @Override
+ public boolean isPresent() {
+ return factory.containsBeanDefinition(beanName);
+ }
+
+ @Override
+ public boolean isFactoryBean() {
+ return factory.isFactoryBean(beanName);
+ }
+
+ @Override
+ public BeanDefinition getBeanDefinition() throws NoSuchBeanDefinitionException {
+ return factory.getBeanDefinition(beanName);
+ }
+
+ @Override
+ public RootBeanDefinition getRootBeanDefinition() throws NoSuchBeanDefinitionException {
+ BeanDefinition beanDefinition = getBeanDefinition();
+
+ if (beanDefinition instanceof RootBeanDefinition rootBeanDefinition) {
+ return rootBeanDefinition;
+ }
+
+ throw new IllegalStateException(String.format("%s is not a root bean", beanName));
+ }
+
+ @Override
+ public Class> resolveType() {
+ return factory.getType(beanName, false);
+ }
+ }
+}
diff --git a/src/main/java/org/springframework/data/aot/DefaultAotRepositoryContext.java b/src/main/java/org/springframework/data/aot/DefaultAotRepositoryContext.java
index 13bd945eb..e93d15764 100644
--- a/src/main/java/org/springframework/data/aot/DefaultAotRepositoryContext.java
+++ b/src/main/java/org/springframework/data/aot/DefaultAotRepositoryContext.java
@@ -35,26 +35,23 @@ import org.springframework.data.util.Lazy;
*/
class DefaultAotRepositoryContext implements AotRepositoryContext {
- private AotContext aotContext;
-
+ private final AotContext aotContext;
private final Lazy>> resolvedAnnotations = Lazy.of(this::discoverAnnotations);
private final Lazy>> managedTypes = Lazy.of(this::discoverTypes);
private RepositoryInformation repositoryInformation;
-
private Set basePackages;
private Set> identifyingAnnotations;
-
private String beanName;
+ public DefaultAotRepositoryContext(AotContext aotContext) {
+ this.aotContext = aotContext;
+ }
+
public AotContext getAotContext() {
return aotContext;
}
- public void setAotContext(AotContext aotContext) {
- this.aotContext = aotContext;
- }
-
@Override
public ConfigurableListableBeanFactory getBeanFactory() {
return getAotContext().getBeanFactory();
@@ -106,6 +103,16 @@ class DefaultAotRepositoryContext implements AotRepositoryContext {
return managedTypes.get();
}
+ @Override
+ public TypeIntrospector introspectType(String typeName) {
+ return aotContext.introspectType(typeName);
+ }
+
+ @Override
+ public IntrospectedBeanDefinition introspectBeanDefinition(String beanName) {
+ return aotContext.introspectBeanDefinition(beanName);
+ }
+
protected Set> discoverAnnotations() {
Set> annotations = getResolvedTypes().stream()
@@ -127,7 +134,8 @@ class DefaultAotRepositoryContext implements AotRepositoryContext {
if (!getIdentifyingAnnotations().isEmpty()) {
- Set> classes = aotContext.getTypeScanner().scanPackages(getBasePackages()).forTypesAnnotatedWith(getIdentifyingAnnotations()).collectAsSet();
+ Set> classes = aotContext.getTypeScanner().scanPackages(getBasePackages())
+ .forTypesAnnotatedWith(getIdentifyingAnnotations()).collectAsSet();
types.addAll(TypeCollector.inspect(classes).list());
}
diff --git a/src/main/java/org/springframework/data/aot/ManagedTypesBeanRegistrationAotProcessor.java b/src/main/java/org/springframework/data/aot/ManagedTypesBeanRegistrationAotProcessor.java
index 018fc6117..474768f7e 100644
--- a/src/main/java/org/springframework/data/aot/ManagedTypesBeanRegistrationAotProcessor.java
+++ b/src/main/java/org/springframework/data/aot/ManagedTypesBeanRegistrationAotProcessor.java
@@ -20,6 +20,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.springframework.aot.generate.GenerationContext;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
@@ -27,7 +28,6 @@ import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.core.ResolvableType;
import org.springframework.data.domain.ManagedTypes;
-import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@@ -38,8 +38,6 @@ import org.springframework.util.StringUtils;
*
* @author Christoph Strobl
* @author John Blum
- * @see org.springframework.beans.factory.BeanFactoryAware
- * @see org.springframework.beans.factory.aot.BeanRegistrationAotProcessor
* @since 3.0
*/
public class ManagedTypesBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {
@@ -48,7 +46,7 @@ public class ManagedTypesBeanRegistrationAotProcessor implements BeanRegistratio
@Nullable private String moduleIdentifier;
@Override
- public BeanRegistrationAotContribution processAheadOfTime(@NonNull RegisteredBean registeredBean) {
+ public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
if (!isMatch(registeredBean.getBeanClass(), registeredBean.getBeanName())) {
return null;
diff --git a/src/main/java/org/springframework/data/aot/ManagedTypesRegistrationAotContribution.java b/src/main/java/org/springframework/data/aot/ManagedTypesRegistrationAotContribution.java
index c8785f9a4..3b81186a2 100644
--- a/src/main/java/org/springframework/data/aot/ManagedTypesRegistrationAotContribution.java
+++ b/src/main/java/org/springframework/data/aot/ManagedTypesRegistrationAotContribution.java
@@ -23,7 +23,7 @@ import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.core.ResolvableType;
import org.springframework.data.domain.ManagedTypes;
-import org.springframework.lang.NonNull;
+import org.springframework.lang.Nullable;
/**
* {@link BeanRegistrationAotContribution} used to contribute a {@link ManagedTypes} registration.
@@ -38,8 +38,8 @@ public class ManagedTypesRegistrationAotContribution implements BeanRegistration
private final ManagedTypes managedTypes;
private final BiConsumer contributionAction;
- public ManagedTypesRegistrationAotContribution(AotContext aotContext, ManagedTypes managedTypes,
- @NonNull BiConsumer contributionAction) {
+ public ManagedTypesRegistrationAotContribution(AotContext aotContext, @Nullable ManagedTypes managedTypes,
+ BiConsumer contributionAction) {
this.aotContext = aotContext;
this.managedTypes = managedTypes;
@@ -50,14 +50,12 @@ public class ManagedTypesRegistrationAotContribution implements BeanRegistration
return this.aotContext;
}
- @NonNull
protected ManagedTypes getManagedTypes() {
return managedTypes == null ? ManagedTypes.empty() : managedTypes;
}
@Override
- public void applyTo(@NonNull GenerationContext generationContext,
- @NonNull BeanRegistrationCode beanRegistrationCode) {
+ public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) {
List> types = getManagedTypes().toList();
diff --git a/src/main/java/org/springframework/data/aot/Predicates.java b/src/main/java/org/springframework/data/aot/Predicates.java
index 868afb625..30b8cabc1 100644
--- a/src/main/java/org/springframework/data/aot/Predicates.java
+++ b/src/main/java/org/springframework/data/aot/Predicates.java
@@ -32,7 +32,11 @@ import java.util.function.Predicate;
public abstract class Predicates {
public static final Predicate IS_ENUM_MEMBER = member -> member.getDeclaringClass().isEnum();
- public static final Predicate IS_HIBERNATE_MEMBER = member -> member.getName().startsWith("$$_hibernate");
+ public static final 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());
diff --git a/src/main/java/org/springframework/data/aot/RepositoryBeanDefinitionReader.java b/src/main/java/org/springframework/data/aot/RepositoryBeanDefinitionReader.java
index 558af4e79..d6b1cf420 100644
--- a/src/main/java/org/springframework/data/aot/RepositoryBeanDefinitionReader.java
+++ b/src/main/java/org/springframework/data/aot/RepositoryBeanDefinitionReader.java
@@ -17,13 +17,14 @@ package org.springframework.data.aot;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.data.repository.config.RepositoryFragmentConfiguration;
-import org.springframework.data.repository.config.RepositoryMetadata;
+import org.springframework.data.repository.config.RepositoryConfiguration;
+import org.springframework.data.repository.config.RepositoryFragmentConfigurationProvider;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFragment;
@@ -31,19 +32,15 @@ import org.springframework.data.util.Lazy;
import org.springframework.util.ClassUtils;
/**
- * Reader used to extract {@link RepositoryInformation} from {@link RepositoryMetadata}.
+ * Reader used to extract {@link RepositoryInformation} from {@link RepositoryConfiguration}.
*
* @author Christoph Strobl
* @author John Blum
- * @see org.springframework.data.repository.config.RepositoryFragmentConfiguration
- * @see org.springframework.data.repository.config.RepositoryMetadata
- * @see org.springframework.data.repository.core.RepositoryInformation
- * @see org.springframework.data.repository.core.support.RepositoryFragment
* @since 3.0.0
*/
class RepositoryBeanDefinitionReader {
- static RepositoryInformation readRepositoryInformation(RepositoryMetadata> metadata,
+ static RepositoryInformation readRepositoryInformation(RepositoryConfiguration> metadata,
ConfigurableListableBeanFactory beanFactory) {
return new AotRepositoryInformation(metadataSupplier(metadata, beanFactory),
@@ -51,33 +48,33 @@ class RepositoryBeanDefinitionReader {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
- private static Supplier>> fragments(RepositoryMetadata metadata,
+ private static Supplier>> fragments(RepositoryConfiguration> metadata,
ConfigurableListableBeanFactory beanFactory) {
- return Lazy.of(() -> (Collection>) metadata.getFragmentConfiguration().stream()
- .flatMap(it -> {
+ if (metadata instanceof RepositoryFragmentConfigurationProvider provider) {
- RepositoryFragmentConfiguration fragmentConfiguration = (RepositoryFragmentConfiguration) it;
- List fragments = new ArrayList<>(2);
+ return Lazy.of(() -> {
+ return provider.getFragmentConfiguration().stream().flatMap(it -> {
- if (fragmentConfiguration.getClassName() != null) {
- fragments.add(RepositoryFragment.implemented(forName(fragmentConfiguration.getClassName(), beanFactory)));
- }
- if (fragmentConfiguration.getInterfaceName() != null) {
- fragments.add(RepositoryFragment.structural(forName(fragmentConfiguration.getInterfaceName(), beanFactory)));
- }
+ List> fragments = new ArrayList<>(1);
- return fragments.stream();
- })
- .collect(Collectors.toList()));
+ // TODO: Implemented accepts an Object, not a class.
+ fragments.add(RepositoryFragment.implemented(forName(it.getClassName(), beanFactory)));
+ fragments.add(RepositoryFragment.structural(forName(it.getInterfaceName(), beanFactory)));
+
+ return fragments.stream();
+ }).collect(Collectors.toList());
+ });
+ }
+
+ return Lazy.of(Collections::emptyList);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
- private static Supplier> repositoryBaseClass(RepositoryMetadata metadata,
+ private static Supplier> repositoryBaseClass(RepositoryConfiguration metadata,
ConfigurableListableBeanFactory beanFactory) {
- return Lazy.of(() ->
- (Class>) metadata.getRepositoryBaseClassName().map(it -> forName(it.toString(), beanFactory))
+ return Lazy.of(() -> (Class>) metadata.getRepositoryBaseClassName().map(it -> forName(it.toString(), beanFactory))
.orElseGet(() -> {
// TODO: retrieve the default without loading the actual RepositoryBeanFactory
return Object.class;
@@ -85,7 +82,7 @@ class RepositoryBeanDefinitionReader {
}
static Supplier metadataSupplier(
- RepositoryMetadata> metadata, ConfigurableListableBeanFactory beanFactory) {
+ RepositoryConfiguration> metadata, ConfigurableListableBeanFactory beanFactory) {
return Lazy.of(() -> new DefaultRepositoryMetadata(forName(metadata.getRepositoryInterface(), beanFactory)));
}
diff --git a/src/main/java/org/springframework/data/aot/RepositoryRegistrationAotContribution.java b/src/main/java/org/springframework/data/aot/RepositoryRegistrationAotContribution.java
index 6d6d7691d..1e8fc318d 100644
--- a/src/main/java/org/springframework/data/aot/RepositoryRegistrationAotContribution.java
+++ b/src/main/java/org/springframework/data/aot/RepositoryRegistrationAotContribution.java
@@ -19,7 +19,6 @@ import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -27,7 +26,6 @@ import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
-import java.util.stream.Collectors;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.framework.Advised;
@@ -47,12 +45,11 @@ import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.data.projection.EntityProjectionIntrospector;
import org.springframework.data.projection.TargetAware;
import org.springframework.data.repository.Repository;
+import org.springframework.data.repository.config.RepositoryConfiguration;
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
-import org.springframework.data.repository.config.RepositoryMetadata;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
import org.springframework.data.repository.core.support.RepositoryFragment;
-import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@@ -62,29 +59,24 @@ import org.springframework.util.ClassUtils;
* {@link BeanRegistrationAotContribution} used to contribute repository registrations.
*
* @author John Blum
- * @see org.springframework.aot.generate.GenerationContext
- * @see org.springframework.beans.factory.aot.BeanRegistrationAotContribution
- * @see org.springframework.beans.factory.support.RegisteredBean
- * @see org.springframework.data.aot.RepositoryRegistrationAotProcessor
- * @since 3.0.0
+ * @since 3.0
*/
public class RepositoryRegistrationAotContribution implements BeanRegistrationAotContribution {
- private static final String KOTLIN_COROUTINE_REPOSITORY_TYPE_NAME =
- "org.springframework.data.repository.kotlin.CoroutineCrudRepository";
+ private static final String KOTLIN_COROUTINE_REPOSITORY_TYPE_NAME = "org.springframework.data.repository.kotlin.CoroutineCrudRepository";
/**
* Factory method used to construct a new instance of {@link RepositoryRegistrationAotContribution} initialized with
* the given, required {@link RepositoryRegistrationAotProcessor} from which this contribution was created.
*
- * @param repositoryRegistrationAotProcessor reference back to the {@link RepositoryRegistrationAotProcessor} from which this
- * contribution was created.
+ * @param repositoryRegistrationAotProcessor reference back to the {@link RepositoryRegistrationAotProcessor} from
+ * which this contribution was created.
* @return a new instance of {@link RepositoryRegistrationAotContribution}.
* @throws IllegalArgumentException if the {@link RepositoryRegistrationAotProcessor} is {@literal null}.
* @see org.springframework.data.aot.RepositoryRegistrationAotProcessor
*/
public static RepositoryRegistrationAotContribution fromProcessor(
- @NonNull RepositoryRegistrationAotProcessor repositoryRegistrationAotProcessor) {
+ RepositoryRegistrationAotProcessor repositoryRegistrationAotProcessor) {
return new RepositoryRegistrationAotContribution(repositoryRegistrationAotProcessor);
}
@@ -93,28 +85,25 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
private BiConsumer moduleContribution;
- @NonNull
private final RepositoryRegistrationAotProcessor repositoryRegistrationAotProcessor;
/**
- * Constructs a new instance of the {@link RepositoryRegistrationAotContribution} initialized with the given,
- * required {@link RepositoryRegistrationAotProcessor} from which this contribution was created.
+ * Constructs a new instance of the {@link RepositoryRegistrationAotContribution} initialized with the given, required
+ * {@link RepositoryRegistrationAotProcessor} from which this contribution was created.
*
- * @param repositoryRegistrationAotProcessor reference back to the {@link RepositoryRegistrationAotProcessor} from which this
- * contribution was created.
+ * @param repositoryRegistrationAotProcessor reference back to the {@link RepositoryRegistrationAotProcessor} from
+ * which this contribution was created.
* @throws IllegalArgumentException if the {@link RepositoryRegistrationAotProcessor} is {@literal null}.
* @see org.springframework.data.aot.RepositoryRegistrationAotProcessor
*/
protected RepositoryRegistrationAotContribution(
- @NonNull RepositoryRegistrationAotProcessor repositoryRegistrationAotProcessor) {
+ RepositoryRegistrationAotProcessor repositoryRegistrationAotProcessor) {
- Assert.notNull(repositoryRegistrationAotProcessor,
- "RepositoryRegistrationAotProcessor must not be null");
+ Assert.notNull(repositoryRegistrationAotProcessor, "RepositoryRegistrationAotProcessor must not be null");
this.repositoryRegistrationAotProcessor = repositoryRegistrationAotProcessor;
}
- @NonNull
protected ConfigurableListableBeanFactory getBeanFactory() {
return getRepositoryRegistrationAotProcessor().getBeanFactory();
}
@@ -123,16 +112,14 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
return Optional.ofNullable(this.moduleContribution);
}
- @NonNull
protected AotRepositoryContext getRepositoryContext() {
Assert.state(this.repositoryContext != null,
- "The AOT RepositoryContext was not properly initialized; did you call the forBean(:RegisteredBean) method");
+ "The AOT RepositoryContext was not properly initialized; did you call the forBean(:RegisteredBean) method");
return this.repositoryContext;
}
- @NonNull
protected RepositoryRegistrationAotProcessor getRepositoryRegistrationAotProcessor() {
return this.repositoryRegistrationAotProcessor;
}
@@ -146,20 +133,21 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
}
/**
- * Builds a {@link RepositoryRegistrationAotContribution} for given, required {@link RegisteredBean}
- * representing the {@link Repository} registered in the bean registry.
+ * Builds a {@link RepositoryRegistrationAotContribution} for given, required {@link RegisteredBean} representing the
+ * {@link Repository} registered in the bean registry.
*
* @param repositoryBean {@link RegisteredBean} for the {@link Repository}; must not be {@literal null}.
- * @return a {@link RepositoryRegistrationAotContribution} to contribute AOT metadata and code
- * for the {@link Repository} {@link RegisteredBean}.
+ * @return a {@link RepositoryRegistrationAotContribution} to contribute AOT metadata and code for the
+ * {@link Repository} {@link RegisteredBean}.
* @throws IllegalArgumentException if the {@link RegisteredBean} is {@literal null}.
* @see org.springframework.beans.factory.support.RegisteredBean
*/
- public RepositoryRegistrationAotContribution forBean(@NonNull RegisteredBean repositoryBean) {
+ public RepositoryRegistrationAotContribution forBean(RegisteredBean repositoryBean) {
Assert.notNull(repositoryBean, "The RegisteredBean for the repository must not be null");
- RepositoryMetadata> repositoryMetadata = getRepositoryRegistrationAotProcessor().getRepositoryMetadata(repositoryBean);
+ RepositoryConfiguration> repositoryMetadata = getRepositoryRegistrationAotProcessor()
+ .getRepositoryMetadata(repositoryBean);
this.repositoryContext = buildAotRepositoryContext(repositoryBean, repositoryMetadata);
@@ -168,14 +156,14 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
return this;
}
- protected DefaultAotRepositoryContext buildAotRepositoryContext(@NonNull RegisteredBean bean,
- @NonNull RepositoryMetadata> repositoryMetadata) {
+ protected DefaultAotRepositoryContext buildAotRepositoryContext(RegisteredBean bean,
+ RepositoryConfiguration> repositoryMetadata) {
RepositoryInformation repositoryInformation = resolveRepositoryInformation(repositoryMetadata);
- DefaultAotRepositoryContext repositoryContext = new DefaultAotRepositoryContext();
+ DefaultAotRepositoryContext repositoryContext = new DefaultAotRepositoryContext(
+ AotContext.from(this.getBeanFactory()));
- repositoryContext.setAotContext(this::getBeanFactory);
repositoryContext.setBeanName(bean.getBeanName());
repositoryContext.setBasePackages(repositoryMetadata.getBasePackages().toSet());
repositoryContext.setIdentifyingAnnotations(resolveIdentifyingAnnotations());
@@ -190,17 +178,17 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
try {
// TODO: Getting all beans of type RepositoryConfigurationExtensionSupport will have the effect that
- // if the user is currently operating in multi-store mode, then all identifying annotations from
- // all stores will be included in the resulting Set.
- // When using AOT, is multi-store mode allowed? I don't see why not, but does this work correctly
- // with AOT, ATM?
- Map repositoryConfigurationExtensionBeans =
- getBeanFactory().getBeansOfType(RepositoryConfigurationExtensionSupport.class);
+ // if the user is currently operating in multi-store mode, then all identifying annotations from
+ // all stores will be included in the resulting Set.
+ // When using AOT, is multi-store mode allowed? I don't see why not, but does this work correctly
+ // with AOT, ATM?
+ Map repositoryConfigurationExtensionBeans = getBeanFactory()
+ .getBeansOfType(RepositoryConfigurationExtensionSupport.class);
-// repositoryConfigurationExtensionBeans.values().stream()
-// .map(RepositoryConfigurationExtensionSupport::getIdentifyingAnnotations)
-// .flatMap(Collection::stream)
-// .collect(Collectors.toCollection(() -> identifyingAnnotations));
+ // repositoryConfigurationExtensionBeans.values().stream()
+ // .map(RepositoryConfigurationExtensionSupport::getIdentifyingAnnotations)
+ // .flatMap(Collection::stream)
+ // .collect(Collectors.toCollection(() -> identifyingAnnotations));
} catch (Throwable ignore) {
// Possible BeansException because no bean exists of type RepositoryConfigurationExtension,
@@ -210,26 +198,25 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
return identifyingAnnotations;
}
- private RepositoryInformation resolveRepositoryInformation(RepositoryMetadata> repositoryMetadata) {
+ private RepositoryInformation resolveRepositoryInformation(RepositoryConfiguration> repositoryMetadata) {
return RepositoryBeanDefinitionReader.readRepositoryInformation(repositoryMetadata, getBeanFactory());
}
/**
- * Helps the AOT processing render the {@link FactoryBean} type correctly that is used to tell the outcome of the {@link FactoryBean}.
- *
- * We just need to set the target {@link Repository} {@link Class type} of the {@link RepositoryFactoryBeanSupport}
- * while keeping the actual ID and DomainType set to {@link Object}. If the generic type signature does not match,
- * then we do not try to resolve and remap the types, but rather set the {@literal factoryBeanObjectType} attribute
- * on the {@link RootBeanDefinition}.
+ * Helps the AOT processing render the {@link FactoryBean} type correctly that is used to tell the outcome of the
+ * {@link FactoryBean}. We just need to set the target {@link Repository} {@link Class type} of the
+ * {@link RepositoryFactoryBeanSupport} while keeping the actual ID and DomainType set to {@link Object}. If the
+ * generic type signature does not match, then we do not try to resolve and remap the types, but rather set the
+ * {@literal factoryBeanObjectType} attribute on the {@link RootBeanDefinition}.
*/
- protected void enhanceRepositoryBeanDefinition(@NonNull RegisteredBean repositoryBean,
- @NonNull RepositoryMetadata> repositoryMetadata, @NonNull AotRepositoryContext repositoryContext) {
+ protected void enhanceRepositoryBeanDefinition(RegisteredBean repositoryBean,
+ RepositoryConfiguration> repositoryMetadata, AotRepositoryContext repositoryContext) {
logTrace(String.format("Enhancing repository factory bean definition [%s]", repositoryBean.getBeanName()));
Class> repositoryFactoryBeanType = repositoryContext
- .resolveType(repositoryMetadata.getRepositoryFactoryBeanClassName())
- .orElse(RepositoryFactoryBeanSupport.class);
+ .introspectType(repositoryMetadata.getRepositoryFactoryBeanClassName()).resolveType()
+ .orElse(RepositoryFactoryBeanSupport.class);
ResolvableType resolvedRepositoryFactoryBeanType = ResolvableType.forClass(repositoryFactoryBeanType);
@@ -237,16 +224,16 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
if (isRepositoryWithTypeParameters(resolvedRepositoryFactoryBeanType)) {
repositoryBeanDefinition.setTargetType(ResolvableType.forClassWithGenerics(repositoryFactoryBeanType,
- repositoryContext.getRepositoryInformation().getRepositoryInterface(), Object.class, Object.class));
+ repositoryContext.getRepositoryInformation().getRepositoryInterface(), Object.class, Object.class));
} else {
repositoryBeanDefinition.setTargetType(resolvedRepositoryFactoryBeanType);
repositoryBeanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE,
- repositoryContext.getRepositoryInformation().getRepositoryInterface());
+ repositoryContext.getRepositoryInformation().getRepositoryInterface());
}
}
private boolean isRepositoryWithTypeParameters(ResolvableType type) {
- return type != null && type.getGenerics().length == 3;
+ return type.getGenerics().length == 3;
}
/**
@@ -255,7 +242,7 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
* @param moduleContribution {@link BiConsumer} used by data modules to submit contributions; can be {@literal null}.
* @return this.
*/
- @NonNull
+
@SuppressWarnings("unused")
public RepositoryRegistrationAotContribution withModuleContribution(
@Nullable BiConsumer moduleContribution) {
@@ -264,29 +251,27 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
}
@Override
- public void applyTo(@NonNull GenerationContext generationContext,
- @NonNull BeanRegistrationCode beanRegistrationCode) {
+ public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) {
contributeRepositoryInfo(this.repositoryContext, generationContext);
getModuleContribution().ifPresent(it -> it.accept(getRepositoryContext(), generationContext));
}
- private void contributeRepositoryInfo(@NonNull AotRepositoryContext repositoryContext,
- @NonNull GenerationContext contribution) {
+ private void contributeRepositoryInfo(AotRepositoryContext repositoryContext, GenerationContext contribution) {
RepositoryInformation repositoryInformation = getRepositoryInformation();
- logTrace("Contributing repository information for [%s]",
- repositoryInformation.getRepositoryInterface());
+ logTrace("Contributing repository information for [%s]", repositoryInformation.getRepositoryInterface());
// TODO: is this the way?
contribution.getRuntimeHints().reflection()
- .registerType(repositoryInformation.getRepositoryInterface(), hint ->
- hint.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS))
- .registerType(repositoryInformation.getRepositoryBaseClass(), hint ->
- hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS))
- .registerType(repositoryInformation.getDomainType(), hint ->
- hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.DECLARED_FIELDS));
+ .registerType(repositoryInformation.getRepositoryInterface(),
+ hint -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS))
+ .registerType(repositoryInformation.getRepositoryBaseClass(),
+ hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS))
+ .registerType(repositoryInformation.getDomainType(),
+ hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
+ MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.DECLARED_FIELDS));
// Repository Fragments
for (RepositoryFragment> fragment : getRepositoryInformation().getFragments()) {
@@ -308,26 +293,26 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
SpringProxy.class, Advised.class, DecoratingProxy.class);
// Transactional Repository Proxy
- //repositoryContext.ifTransactionManagerPresent(transactionManagerBeanNames -> {
+ // repositoryContext.ifTransactionManagerPresent(transactionManagerBeanNames -> {
- // TODO: Is the following double JDK Proxy registration above necessary or would a single JDK Proxy
- // registration suffice?
- // In other words, simply having a single JDK Proxy registration either with or without
- // the additional Serializable TypeReference?
- // NOTE: Using a single JDK Proxy registration causes the
- // simpleRepositoryWithTxManagerNoKotlinNoReactiveButComponent() test case method to fail.
- List transactionalRepositoryProxyTypeReferences =
- transactionalRepositoryProxyTypeReferences(repositoryInformation);
+ // TODO: Is the following double JDK Proxy registration above necessary or would a single JDK Proxy
+ // registration suffice?
+ // In other words, simply having a single JDK Proxy registration either with or without
+ // the additional Serializable TypeReference?
+ // NOTE: Using a single JDK Proxy registration causes the
+ // simpleRepositoryWithTxManagerNoKotlinNoReactiveButComponent() test case method to fail.
+ List transactionalRepositoryProxyTypeReferences = transactionalRepositoryProxyTypeReferences(
+ repositoryInformation);
+ contribution.getRuntimeHints().proxies()
+ .registerJdkProxy(transactionalRepositoryProxyTypeReferences.toArray(new TypeReference[0]));
+
+ if (isComponentAnnotatedRepository(repositoryInformation)) {
+ transactionalRepositoryProxyTypeReferences.add(TypeReference.of(Serializable.class));
contribution.getRuntimeHints().proxies()
.registerJdkProxy(transactionalRepositoryProxyTypeReferences.toArray(new TypeReference[0]));
-
- if (isComponentAnnotatedRepository(repositoryInformation)) {
- transactionalRepositoryProxyTypeReferences.add(TypeReference.of(Serializable.class));
- contribution.getRuntimeHints().proxies()
- .registerJdkProxy(transactionalRepositoryProxyTypeReferences.toArray(new TypeReference[0]));
- }
- //});
+ }
+ // });
// Reactive Repositories
if (repositoryInformation.isReactiveRepository()) {
@@ -342,12 +327,10 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
}
// Repository query methods
- repositoryInformation.getQueryMethods()
- .map(repositoryInformation::getReturnedDomainClass)
- .filter(Class::isInterface)
- .forEach(type -> {
- if (EntityProjectionIntrospector.ProjectionPredicate.typeHierarchy()
- .test(type, repositoryInformation.getDomainType())) {
+ repositoryInformation.getQueryMethods().map(repositoryInformation::getReturnedDomainClass)
+ .filter(Class::isInterface).forEach(type -> {
+ if (EntityProjectionIntrospector.ProjectionPredicate.typeHierarchy().test(type,
+ repositoryInformation.getDomainType())) {
contributeProjection(type, contribution);
}
});
@@ -360,58 +343,52 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
private boolean isKotlinCoroutineRepository(AotRepositoryContext repositoryContext,
RepositoryInformation repositoryInformation) {
- return repositoryContext.resolveType(KOTLIN_COROUTINE_REPOSITORY_TYPE_NAME)
- .filter(it -> ClassUtils.isAssignable(it, repositoryInformation.getRepositoryInterface()))
- .isPresent();
+ return repositoryContext.introspectType(KOTLIN_COROUTINE_REPOSITORY_TYPE_NAME).resolveType()
+ .filter(it -> ClassUtils.isAssignable(it, repositoryInformation.getRepositoryInterface())).isPresent();
}
private List kotlinRepositoryReflectionTypeReferences() {
- return new ArrayList<>(Arrays.asList(
- TypeReference.of("org.springframework.data.repository.kotlin.CoroutineCrudRepository"),
- TypeReference.of(Repository.class),
- TypeReference.of(Iterable.class),
- TypeReference.of("kotlinx.coroutines.flow.Flow"),
- TypeReference.of("kotlin.collections.Iterable"),
- TypeReference.of("kotlin.Unit"),
- TypeReference.of("kotlin.Long"),
- TypeReference.of("kotlin.Boolean")
- ));
+ return new ArrayList<>(
+ Arrays.asList(TypeReference.of("org.springframework.data.repository.kotlin.CoroutineCrudRepository"),
+ TypeReference.of(Repository.class), //
+ TypeReference.of(Iterable.class), //
+ TypeReference.of("kotlinx.coroutines.flow.Flow"), //
+ TypeReference.of("kotlin.collections.Iterable"), //
+ TypeReference.of("kotlin.Unit"), //
+ TypeReference.of("kotlin.Long"), //
+ TypeReference.of("kotlin.Boolean")));
}
private List transactionalRepositoryProxyTypeReferences(RepositoryInformation repositoryInformation) {
- return new ArrayList<>(Arrays.asList(
- TypeReference.of(repositoryInformation.getRepositoryInterface()),
- TypeReference.of(Repository.class),
- TypeReference.of("org.springframework.transaction.interceptor.TransactionalProxy"),
- TypeReference.of("org.springframework.aop.framework.Advised"),
- TypeReference.of(DecoratingProxy.class)
- ));
+ return new ArrayList<>(Arrays.asList(TypeReference.of(repositoryInformation.getRepositoryInterface()),
+ TypeReference.of(Repository.class), //
+ TypeReference.of("org.springframework.transaction.interceptor.TransactionalProxy"), //
+ TypeReference.of("org.springframework.aop.framework.Advised"), //
+ TypeReference.of(DecoratingProxy.class)));
}
private void contributeProjection(Class> type, GenerationContext generationContext) {
- generationContext.getRuntimeHints().proxies()
- .registerJdkProxy(type, TargetAware.class, SpringProxy.class, DecoratingProxy.class);
+ generationContext.getRuntimeHints().proxies().registerJdkProxy(type, TargetAware.class, SpringProxy.class,
+ DecoratingProxy.class);
}
static boolean isJavaOrPrimitiveType(Class> type) {
-
- return TypeUtils.type(type).isPartOf("java")
- || type.isPrimitive()
- || ClassUtils.isPrimitiveArray(type);
+ return TypeUtils.type(type).isPartOf("java") //
+ || ClassUtils.isPrimitiveOrWrapper(type) //
+ || ClassUtils.isPrimitiveArray(type); //
}
- static boolean isSpringDataManagedAnnotation(MergedAnnotation> annotation) {
+ static boolean isSpringDataManagedAnnotation(@Nullable MergedAnnotation> annotation) {
- return annotation != null
- && (isInSpringDataNamespace(annotation.getType()) || annotation.getMetaTypes().stream()
- .anyMatch(RepositoryRegistrationAotContribution::isInSpringDataNamespace));
+ return annotation != null && (isInSpringDataNamespace(annotation.getType())
+ || annotation.getMetaTypes().stream().anyMatch(RepositoryRegistrationAotContribution::isInSpringDataNamespace));
}
static boolean isInSpringDataNamespace(Class> type) {
- return type != null && type.getPackage().getName().startsWith(TypeContributor.DATA_NAMESPACE);
+ return type.getPackage().getName().startsWith(TypeContributor.DATA_NAMESPACE);
}
static void contributeType(Class> type, GenerationContext generationContext) {
@@ -419,8 +396,8 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
}
// TODO What was this meant to be used for? Was this type filter maybe meant to be used in
- // the TypeContributor.contribute(:Class, :Predicate :GenerationContext) method
- // used in the contributeType(..) method above?
+ // the TypeContributor.contribute(:Class, :Predicate :GenerationContext) method
+ // used in the contributeType(..) method above?
public Predicate> typeFilter() { // like only document ones. // TODO: As in MongoDB?
return it -> true;
}
diff --git a/src/main/java/org/springframework/data/aot/RepositoryRegistrationAotProcessor.java b/src/main/java/org/springframework/data/aot/RepositoryRegistrationAotProcessor.java
index 77d89034b..e549820a8 100644
--- a/src/main/java/org/springframework/data/aot/RepositoryRegistrationAotProcessor.java
+++ b/src/main/java/org/springframework/data/aot/RepositoryRegistrationAotProcessor.java
@@ -35,10 +35,9 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.annotation.MergedAnnotation;
+import org.springframework.data.repository.config.RepositoryConfiguration;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
-import org.springframework.data.repository.config.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
-import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -46,24 +45,22 @@ import org.springframework.util.StringUtils;
/**
* {@link BeanRegistrationAotProcessor} responsible processing and providing AOT configuration for repositories.
*
- * Processes {@link RepositoryFactoryBeanSupport repository factory beans} to provide generic type information to
- * the AOT tooling to allow deriving target type from the {@link RootBeanDefinition bean definition}. If generic types
- * do not match due to customization of the factory bean by the user, at least the target repository type is provided
- * via the {@link FactoryBean#OBJECT_TYPE_ATTRIBUTE}.
+ * Processes {@link RepositoryFactoryBeanSupport repository factory beans} to provide generic type information to the
+ * AOT tooling to allow deriving target type from the {@link RootBeanDefinition bean definition}. If generic types do
+ * not match due to customization of the factory bean by the user, at least the target repository type is provided via
+ * the {@link FactoryBean#OBJECT_TYPE_ATTRIBUTE}.
*
*
- * With {@link RepositoryRegistrationAotProcessor#contribute(AotRepositoryContext, GenerationContext)}, stores
- * can provide custom logic for contributing additional (eg. reflection) configuration. By default, reflection
- * configuration will be added for types reachable from the repository declaration and query methods as well as
- * all used {@link Annotation annotations} from the {@literal org.springframework.data} namespace.
+ * With {@link RepositoryRegistrationAotProcessor#contribute(AotRepositoryContext, GenerationContext)}, stores can
+ * provide custom logic for contributing additional (eg. reflection) configuration. By default, reflection configuration
+ * will be added for types reachable from the repository declaration and query methods as well as all used
+ * {@link Annotation annotations} from the {@literal org.springframework.data} namespace.
*
- * The processor is typically configured via {@link RepositoryConfigurationExtension#getRepositoryAotProcessor()}
- * and gets added by the {@link org.springframework.data.repository.config.RepositoryConfigurationDelegate}.
+ * The processor is typically configured via {@link RepositoryConfigurationExtension#getRepositoryAotProcessor()} and
+ * gets added by the {@link org.springframework.data.repository.config.RepositoryConfigurationDelegate}.
*
* @author Christoph Strobl
* @author John Blum
- * @see org.springframework.beans.factory.BeanFactoryAware
- * @see org.springframework.beans.factory.aot.BeanRegistrationAotProcessor
* @since 3.0.0
*/
@SuppressWarnings("unused")
@@ -73,45 +70,41 @@ public class RepositoryRegistrationAotProcessor implements BeanRegistrationAotPr
private final Log logger = LogFactory.getLog(getClass());
- private Map> configMap;
+ private Map> configMap;
@Nullable
@Override
- public BeanRegistrationAotContribution processAheadOfTime(@NonNull RegisteredBean bean) {
+ public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean bean) {
- return isRepositoryBean(bean)
- ? newRepositoryRegistrationAotContribution(bean)
- : null;
+ return isRepositoryBean(bean) ? newRepositoryRegistrationAotContribution(bean) : null;
}
protected void contribute(AotRepositoryContext repositoryContext, GenerationContext generationContext) {
repositoryContext.getResolvedTypes().stream()
- .filter(it -> !RepositoryRegistrationAotContribution
- .isJavaOrPrimitiveType(it))
+ .filter(it -> !RepositoryRegistrationAotContribution.isJavaOrPrimitiveType(it))
.forEach(it -> RepositoryRegistrationAotContribution.contributeType(it, generationContext));
repositoryContext.getResolvedAnnotations().stream()
- .filter(RepositoryRegistrationAotContribution::isSpringDataManagedAnnotation)
- .map(MergedAnnotation::getType)
+ .filter(RepositoryRegistrationAotContribution::isSpringDataManagedAnnotation).map(MergedAnnotation::getType)
.forEach(it -> RepositoryRegistrationAotContribution.contributeType(it, generationContext));
}
private boolean isRepositoryBean(RegisteredBean bean) {
- return bean != null && getConfigMap().containsKey(bean.getBeanName());
+ return getConfigMap().containsKey(bean.getBeanName());
}
protected RepositoryRegistrationAotContribution newRepositoryRegistrationAotContribution(
- @NonNull RegisteredBean repositoryBean) {
+ RegisteredBean repositoryBean) {
- RepositoryRegistrationAotContribution contribution =
- RepositoryRegistrationAotContribution.fromProcessor(this).forBean(repositoryBean);
+ RepositoryRegistrationAotContribution contribution = RepositoryRegistrationAotContribution.fromProcessor(this)
+ .forBean(repositoryBean);
return contribution.withModuleContribution(this::contribute);
}
@Override
- public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException {
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory,
() -> "AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory: " + beanFactory);
@@ -119,44 +112,40 @@ public class RepositoryRegistrationAotProcessor implements BeanRegistrationAotPr
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
- @NonNull
protected ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
- public void setConfigMap(@Nullable Map> configMap) {
+ public void setConfigMap(@Nullable Map> configMap) {
this.configMap = configMap;
}
- @NonNull
- public Map> getConfigMap() {
+ public Map> getConfigMap() {
return nullSafeMap(this.configMap);
}
- @NonNull
private Map nullSafeMap(@Nullable Map map) {
return map != null ? map : Collections.emptyMap();
}
@Nullable
- protected RepositoryMetadata> getRepositoryMetadata(@NonNull RegisteredBean bean) {
+ protected RepositoryConfiguration> getRepositoryMetadata(RegisteredBean bean) {
return getConfigMap().get(nullSafeBeanName(bean));
}
- private String nullSafeBeanName(@Nullable RegisteredBean bean) {
+ private String nullSafeBeanName(RegisteredBean bean) {
- String beanName = bean != null ? bean.getBeanName() : null;
+ String beanName = bean.getBeanName();
return StringUtils.hasText(beanName) ? beanName : "";
}
- @NonNull
protected Log getLogger() {
return this.logger;
}
- private void logAt(Predicate logLevelPredicate, BiConsumer logOperation,
- String message, Object... arguments) {
+ private void logAt(Predicate logLevelPredicate, BiConsumer logOperation, String message,
+ Object... arguments) {
Log logger = getLogger();
diff --git a/src/main/java/org/springframework/data/aot/SpringDataBeanFactoryInitializationAotProcessor.java b/src/main/java/org/springframework/data/aot/SpringDataBeanFactoryInitializationAotProcessor.java
index 9e5cba659..8227a4c75 100644
--- a/src/main/java/org/springframework/data/aot/SpringDataBeanFactoryInitializationAotProcessor.java
+++ b/src/main/java/org/springframework/data/aot/SpringDataBeanFactoryInitializationAotProcessor.java
@@ -15,12 +15,12 @@
*/
package org.springframework.data.aot;
-import java.util.Arrays;
import java.util.Collections;
import java.util.function.Supplier;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -29,7 +29,6 @@ import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueH
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.data.domain.ManagedTypes;
-import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
@@ -52,37 +51,36 @@ public class SpringDataBeanFactoryInitializationAotProcessor implements BeanFact
@Nullable
@Override
- public BeanFactoryInitializationAotContribution processAheadOfTime(
- @NonNull ConfigurableListableBeanFactory beanFactory) {
+ public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) {
processManagedTypes(beanFactory);
return null;
}
- private void processManagedTypes(@NonNull ConfigurableListableBeanFactory beanFactory) {
+ private void processManagedTypes(ConfigurableListableBeanFactory beanFactory) {
if (beanFactory instanceof BeanDefinitionRegistry registry) {
for (String beanName : beanFactory.getBeanNamesForType(ManagedTypes.class)) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
- if(beanDefinition.getConstructorArgumentValues().isEmpty()) {
+ if (beanDefinition.getConstructorArgumentValues().isEmpty()) {
return;
}
ValueHolder argumentValue = beanDefinition.getConstructorArgumentValues().getArgumentValue(0, null, null, null);
- if (argumentValue.getValue() instanceof Supplier supplier) {
+ if (argumentValue.getValue()instanceof Supplier supplier) {
if (logger.isDebugEnabled()) {
logger.info(String.format("Replacing ManagedType bean definition %s.", beanName));
}
Object value = supplier.get();
- if(ObjectUtils.isArray(value)) {
+ if (ObjectUtils.isArray(value)) {
value = CollectionUtils.arrayToList(value);
}
- if(!(value instanceof Iterable>)) {
+ if (!(value instanceof Iterable>)) {
value = Collections.singleton(value);
}
diff --git a/src/main/java/org/springframework/data/aot/TypeCollector.java b/src/main/java/org/springframework/data/aot/TypeCollector.java
index 697280586..b4c0b255d 100644
--- a/src/main/java/org/springframework/data/aot/TypeCollector.java
+++ b/src/main/java/org/springframework/data/aot/TypeCollector.java
@@ -35,9 +35,9 @@ import java.util.function.Predicate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.springframework.core.ResolvableType;
import org.springframework.data.util.Lazy;
-import org.springframework.lang.NonNull;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
@@ -62,39 +62,39 @@ public class TypeCollector {
private final Predicate methodFilter = method -> {
- Predicate excludedDomainsPredicate = methodToTest ->
- excludedDomainsFilter.test(methodToTest.getDeclaringClass());
+ // TODO: Eagerly construct predicate objects to avoid object allocations during test(…)
+ Predicate excludedDomainsPredicate = methodToTest -> excludedDomainsFilter
+ .test(methodToTest.getDeclaringClass());
- Predicate excludedMethodsPredicate = Predicates.IS_BRIDGE_METHOD
- .or(Predicates.IS_OBJECT_MEMBER)
- .or(Predicates.IS_HIBERNATE_MEMBER)
- .or(Predicates.IS_ENUM_MEMBER)
- .or(Predicates.IS_NATIVE)
- .or(Predicates.IS_PRIVATE)
- .or(Predicates.IS_PROTECTED)
- .or(Predicates.IS_SYNTHETIC)
- .or(excludedDomainsPredicate.negate());
+ Predicate excludedMethodsPredicate = Predicates.IS_BRIDGE_METHOD //
+ .or(Predicates.IS_OBJECT_MEMBER) //
+ .or(Predicates.IS_HIBERNATE_MEMBER) //
+ .or(Predicates.IS_ENUM_MEMBER) //
+ .or(Predicates.IS_NATIVE) //
+ .or(Predicates.IS_PRIVATE) //
+ .or(Predicates.IS_PROTECTED) //
+ .or(Predicates.IS_SYNTHETIC) //
+ .or(excludedDomainsPredicate.negate()); //
return !excludedMethodsPredicate.test(method);
};
private Predicate fieldFilter = field -> {
- Predicate excludedFieldPredicate = Predicates.IS_HIBERNATE_MEMBER
- .or(Predicates.IS_SYNTHETIC)
- .or(Predicates.IS_JAVA);
+ // TODO: Eagerly construct predicate objects to avoid object allocations during test(…)
+ Predicate excludedFieldPredicate = Predicates.IS_HIBERNATE_MEMBER //
+ .or(Predicates.IS_SYNTHETIC) //
+ .or(Predicates.IS_JAVA);
return !excludedFieldPredicate.test(field);
};
- @NonNull
- public TypeCollector filterFields(@NonNull Predicate filter) {
+ public TypeCollector filterFields(Predicate filter) {
this.fieldFilter = filter.and(filter);
return this;
}
- @NonNull
- public TypeCollector filterTypes(@NonNull Predicate> filter) {
+ public TypeCollector filterTypes(Predicate> filter) {
this.typeFilter = this.typeFilter.and(filter);
return this;
}
@@ -105,12 +105,10 @@ public class TypeCollector {
* @param types the types to inspect
* @return a type model collector for the type
*/
- @NonNull
public static ReachableTypes inspect(Class>... types) {
return inspect(Arrays.asList(types));
}
- @NonNull
public static ReachableTypes inspect(Collection> types) {
return new ReachableTypes(new TypeCollector(), types);
}
@@ -137,9 +135,11 @@ public class TypeCollector {
additionalTypes.addAll(visitConstructorsOfType(type));
additionalTypes.addAll(visitMethodsOfType(type));
additionalTypes.addAll(visitFieldsOfType(type));
+
if (!ObjectUtils.isEmpty(type.toClass().getDeclaredClasses())) {
additionalTypes.addAll(Arrays.asList(type.toClass().getDeclaredClasses()));
}
+
for (Type discoveredType : additionalTypes) {
processType(ResolvableType.forType(discoveredType, type), cache, callback);
}
@@ -204,7 +204,7 @@ public class TypeCollector {
private final Lazy>> reachableTypes = Lazy.of(this::collect);
private final TypeCollector typeCollector;
- public ReachableTypes(@NonNull TypeCollector typeCollector, @NonNull Iterable> roots) {
+ public ReachableTypes(TypeCollector typeCollector, Iterable> roots) {
this.typeCollector = typeCollector;
this.roots = roots;
@@ -229,7 +229,7 @@ public class TypeCollector {
private final Map mutableCache = new LinkedHashMap<>();
- public void add(@NonNull ResolvableType resolvableType) {
+ public void add(ResolvableType resolvableType) {
mutableCache.put(resolvableType.toString(), resolvableType);
}
@@ -237,7 +237,7 @@ public class TypeCollector {
mutableCache.clear();
}
- public boolean contains(@NonNull ResolvableType key) {
+ public boolean contains(ResolvableType key) {
return mutableCache.containsKey(key.toString());
}
diff --git a/src/main/java/org/springframework/data/aot/TypeUtils.java b/src/main/java/org/springframework/data/aot/TypeUtils.java
index 53980effc..b99a84bea 100644
--- a/src/main/java/org/springframework/data/aot/TypeUtils.java
+++ b/src/main/java/org/springframework/data/aot/TypeUtils.java
@@ -21,9 +21,9 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
+import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.core.MethodParameter;
@@ -38,9 +38,12 @@ import org.springframework.util.ObjectUtils;
/**
* @author Christoph Strobl
*/
-// TODO: Consider moving to the org.springframework.data.util package.
+// TODO: Consider moving to the org.springframework.data.util package or make this package-private if not used somewhere
+// else.
public class TypeUtils {
+ public static String TRANSACTION_MANAGER_CLASS_NAME = "org.springframework.transaction.TransactionManager";
+
/**
* Resolve ALL annotations present for a given type. Will inspect type, constructors, parameters, methods, fields,...
*
@@ -50,25 +53,25 @@ public class TypeUtils {
public static Set> resolveUsedAnnotations(Class> type) {
Set> annotations = new LinkedHashSet<>();
- annotations.addAll(TypeUtils.resolveAnnotationsFor(type).collect(Collectors.toSet()));
+ annotations.addAll(TypeUtils.resolveAnnotationsFor(type).toList());
for (Constructor> ctor : type.getDeclaredConstructors()) {
- annotations.addAll(TypeUtils.resolveAnnotationsFor(ctor).collect(Collectors.toSet()));
+ annotations.addAll(TypeUtils.resolveAnnotationsFor(ctor).toList());
for (Parameter parameter : ctor.getParameters()) {
- annotations.addAll(TypeUtils.resolveAnnotationsFor(parameter).collect(Collectors.toSet()));
+ annotations.addAll(TypeUtils.resolveAnnotationsFor(parameter).toList());
}
}
for (Field field : type.getDeclaredFields()) {
- annotations.addAll(TypeUtils.resolveAnnotationsFor(field).collect(Collectors.toSet()));
+ annotations.addAll(TypeUtils.resolveAnnotationsFor(field).toList());
}
try {
for (Method method : type.getDeclaredMethods()) {
- annotations.addAll(TypeUtils.resolveAnnotationsFor(method).collect(Collectors.toSet()));
+ annotations.addAll(TypeUtils.resolveAnnotationsFor(method).toList());
for (Parameter parameter : method.getParameters()) {
- annotations.addAll(TypeUtils.resolveAnnotationsFor(parameter).collect(Collectors.toSet()));
+ annotations.addAll(TypeUtils.resolveAnnotationsFor(parameter).toList());
}
}
} catch (NoClassDefFoundError e) {
- // ignore an move on
+ // ignore and move on
}
return annotations;
}
@@ -83,13 +86,14 @@ public class TypeUtils {
.from(element, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.standardRepeatables(), filter).stream();
}
- public static Set> resolveAnnotationTypesFor(AnnotatedElement element, AnnotationFilter filter) {
+ public static Collection> resolveAnnotationTypesFor(AnnotatedElement element,
+ AnnotationFilter filter) {
return MergedAnnotations
.from(element, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.standardRepeatables(), filter).stream()
- .map(MergedAnnotation::getType).collect(Collectors.toSet());
+ .map(MergedAnnotation::getType).toList();
}
- public static Set> resolveAnnotationTypesFor(AnnotatedElement element) {
+ public static Collection> resolveAnnotationTypesFor(AnnotatedElement element) {
return resolveAnnotationTypesFor(element, AnnotationFilter.PLAIN);
}
@@ -214,7 +218,7 @@ public class TypeUtils {
private static class TypeOpsImpl implements TypeOps {
- private Class> type;
+ private final Class> type;
TypeOpsImpl(Class> type) {
this.type = type;
diff --git a/src/main/java/org/springframework/data/aot/hint/AuditingHints.java b/src/main/java/org/springframework/data/aot/hint/AuditingHints.java
index 36852ce4b..02c297c3c 100644
--- a/src/main/java/org/springframework/data/aot/hint/AuditingHints.java
+++ b/src/main/java/org/springframework/data/aot/hint/AuditingHints.java
@@ -26,8 +26,13 @@ import org.springframework.data.domain.ReactiveAuditorAware;
import org.springframework.lang.Nullable;
/**
+ * Runtime hint registrars for Spring Data modules that provide auditing functionality.
+ *
+ * Mainly for internal use within the framework.
+ *
* @author Christoph Strobl
* @since 3.0
+ * @see RuntimeHintsRegistrar
*/
public class AuditingHints {
diff --git a/src/main/java/org/springframework/data/aot/hint/package-info.java b/src/main/java/org/springframework/data/aot/hint/package-info.java
new file mode 100644
index 000000000..932f06138
--- /dev/null
+++ b/src/main/java/org/springframework/data/aot/hint/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Predefined Runtime Hints.
+ */
+@org.springframework.lang.NonNullApi
+package org.springframework.data.aot.hint;
diff --git a/src/main/java/org/springframework/data/aot/package-info.java b/src/main/java/org/springframework/data/aot/package-info.java
new file mode 100644
index 000000000..85b86ff76
--- /dev/null
+++ b/src/main/java/org/springframework/data/aot/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Support for registering the need for reflection, resources, java serialization and proxies at runtime for Ahead of
+ * Time compilation.
+ */
+@org.springframework.lang.NonNullApi
+package org.springframework.data.aot;
diff --git a/src/main/java/org/springframework/data/auditing/config/AuditingBeanDefinitionRegistrarSupport.java b/src/main/java/org/springframework/data/auditing/config/AuditingBeanDefinitionRegistrarSupport.java
index d45b25303..e740553f5 100644
--- a/src/main/java/org/springframework/data/auditing/config/AuditingBeanDefinitionRegistrarSupport.java
+++ b/src/main/java/org/springframework/data/auditing/config/AuditingBeanDefinitionRegistrarSupport.java
@@ -56,28 +56,41 @@ public abstract class AuditingBeanDefinitionRegistrarSupport implements ImportBe
Assert.notNull(annotationMetadata, "AnnotationMetadata must not be null");
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
- AbstractBeanDefinition ahbd = registerAuditHandlerBeanDefinition(registry, getConfiguration(annotationMetadata));
+ AbstractBeanDefinition ahbd = registerAuditHandlerBeanDefinition(getConfiguration(annotationMetadata), registry);
registerAuditListenerBeanDefinition(ahbd, registry);
}
/**
* Registers an appropriate BeanDefinition for an {@link AuditingHandler}.
*
- * @param registry must not be {@literal null}.
* @param configuration must not be {@literal null}.
+ * @param registry must not be {@literal null}.
* @return
*/
- private AbstractBeanDefinition registerAuditHandlerBeanDefinition(BeanDefinitionRegistry registry,
- AuditingConfiguration configuration) {
+ protected AbstractBeanDefinition registerAuditHandlerBeanDefinition(AuditingConfiguration configuration,
+ BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(configuration, "AuditingConfiguration must not be null");
- AbstractBeanDefinition ahbd = getAuditHandlerBeanDefinitionBuilder(configuration).getBeanDefinition();
+ BeanDefinitionBuilder builder = getAuditHandlerBeanDefinitionBuilder(configuration);
+ postProcess(builder, configuration, registry);
+ AbstractBeanDefinition ahbd = builder.getBeanDefinition();
registry.registerBeanDefinition(getAuditingHandlerBeanName(), ahbd);
return ahbd;
}
+ /**
+ * Customization hook to post-process the AuditHandler BeanDefinition.
+ *
+ * @param builder must not be {@literal null}.
+ * @param registry must not be {@literal null}.
+ * @param configuration must not be {@literal null}.
+ * @since 3.0
+ */
+ protected void postProcess(BeanDefinitionBuilder builder, AuditingConfiguration configuration,
+ BeanDefinitionRegistry registry) {}
+
/**
* Creates a {@link BeanDefinitionBuilder} to ease the definition of store specific {@link AuditingHandler}
* implementations.
diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java
index bc1606eaa..80695add4 100644
--- a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java
+++ b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java
@@ -17,8 +17,8 @@ package org.springframework.data.repository.config;
import static org.springframework.beans.factory.config.BeanDefinition.*;
+import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
@@ -27,6 +27,7 @@ import java.util.stream.Stream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
@@ -120,7 +121,8 @@ class RepositoryBeanDefinitionBuilder {
extension.getDefaultNamedQueryLocation());
configuration.getNamedQueriesLocation().ifPresent(definitionBuilder::setLocations);
- String namedQueriesBeanName = BeanDefinitionReaderUtils.uniqueBeanName(extension.getModuleIdentifier() + ".named-queries", registry);
+ String namedQueriesBeanName = BeanDefinitionReaderUtils
+ .uniqueBeanName(extension.getModuleIdentifier() + ".named-queries", registry);
BeanDefinition namedQueries = definitionBuilder.build(configuration.getSource());
registry.registerBeanDefinition(namedQueriesBeanName, namedQueries);
@@ -138,41 +140,43 @@ class RepositoryBeanDefinitionBuilder {
}
// TODO: merge that with the one that creates the BD
- RepositoryMetadata buildMetadata(RepositoryConfiguration> configuration) {
+ RepositoryConfigurationAdapter> buildMetadata(RepositoryConfiguration> configuration) {
ImplementationDetectionConfiguration config = configuration
.toImplementationDetectionConfiguration(metadataReaderFactory);
- List repositoryFragmentConfigurationStream = fragmentMetadata.getFragmentInterfaces(configuration.getRepositoryInterface()) //
+ List repositoryFragmentConfigurationStream = fragmentMetadata
+ .getFragmentInterfaces(configuration.getRepositoryInterface()) //
.map(it -> detectRepositoryFragmentConfiguration(it, config)) //
- .flatMap(Optionals::toStream)
- .collect(Collectors.toList());//
+ .flatMap(Optionals::toStream).toList();
- if(repositoryFragmentConfigurationStream.isEmpty()) {
+ if (repositoryFragmentConfigurationStream.isEmpty()) {
ImplementationLookupConfiguration lookup = configuration.toLookupConfiguration(metadataReaderFactory);
Optional beanDefinition = implementationDetector.detectCustomImplementation(lookup);
- if(beanDefinition.isPresent()) {
+ if (beanDefinition.isPresent()) {
repositoryFragmentConfigurationStream = new ArrayList<>(1);
- List interfaceNames = fragmentMetadata.getFragmentInterfaces(configuration.getRepositoryInterface()).collect(Collectors.toList());
+ List interfaceNames = fragmentMetadata.getFragmentInterfaces(configuration.getRepositoryInterface())
+ .toList();
String implClassName = beanDefinition.get().getBeanClassName();
try {
- for (String iName : metadataReaderFactory.getMetadataReader(implClassName).getClassMetadata().getInterfaceNames()) {
- if(interfaceNames.contains(iName)) {
+ for (String iName : metadataReaderFactory.getMetadataReader(implClassName).getClassMetadata()
+ .getInterfaceNames()) {
+ if (interfaceNames.contains(iName)) {
repositoryFragmentConfigurationStream.add(new RepositoryFragmentConfiguration(iName, implClassName));
break;
}
}
- } catch (Exception e) {
- e.printStackTrace();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
}
}
}
- return new RepositoryMetadata(configuration, repositoryFragmentConfigurationStream);
+ return new RepositoryConfigurationAdapter<>(configuration, repositoryFragmentConfigurationStream);
}
private Optional registerCustomImplementation(RepositoryConfiguration> configuration) {
diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryMetadata.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationAdapter.java
similarity index 92%
rename from src/main/java/org/springframework/data/repository/config/RepositoryMetadata.java
rename to src/main/java/org/springframework/data/repository/config/RepositoryConfigurationAdapter.java
index 8516ff437..f0501d100 100644
--- a/src/main/java/org/springframework/data/repository/config/RepositoryMetadata.java
+++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationAdapter.java
@@ -27,12 +27,13 @@ import org.springframework.lang.Nullable;
* @author Christoph Strobl
* @since 3.0
*/
-public class RepositoryMetadata implements RepositoryConfiguration {
+class RepositoryConfigurationAdapter
+ implements RepositoryConfiguration, RepositoryFragmentConfigurationProvider {
RepositoryConfiguration repositoryConfiguration;
List fragmentConfiguration;
- public RepositoryMetadata(RepositoryConfiguration repositoryConfiguration,
+ public RepositoryConfigurationAdapter(RepositoryConfiguration repositoryConfiguration,
List fragmentConfiguration) {
this.repositoryConfiguration = repositoryConfiguration;
@@ -116,6 +117,7 @@ public class RepositoryMetadata impleme
return repositoryConfiguration.getResourceDescription();
}
+ @Override
public List getFragmentConfiguration() {
return fragmentConfiguration;
}
diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java
index 8fe79d2f2..e34474c69 100644
--- a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java
+++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java
@@ -21,13 +21,11 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
-import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.springframework.aot.AotDetector;
+
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
@@ -48,7 +46,6 @@ import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.log.LogMessage;
import org.springframework.core.metrics.ApplicationStartup;
import org.springframework.core.metrics.StartupStep;
-import org.springframework.data.util.TypeScanner;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -71,8 +68,7 @@ public class RepositoryConfigurationDelegate {
private static final String REPOSITORY_REGISTRATION = "Spring Data %s - Registering repository: %s - Interface: %s - Factory: %s";
private static final String MULTIPLE_MODULES = "Multiple Spring Data modules found, entering strict repository configuration mode";
private static final String NON_DEFAULT_AUTOWIRE_CANDIDATE_RESOLVER = "Non-default AutowireCandidateResolver (%s) detected. Skipping the registration of LazyRepositoryInjectionPointResolver. Lazy repository injection will not be working";
-
- static final String FACTORY_BEAN_OBJECT_TYPE = FactoryBean.OBJECT_TYPE_ATTRIBUTE; // "factoryBeanObjectType";
+ private static final String FACTORY_BEAN_OBJECT_TYPE = FactoryBean.OBJECT_TYPE_ATTRIBUTE;
private static final Log logger = LogFactory.getLog(RepositoryConfigurationDelegate.class);
@@ -169,7 +165,7 @@ public class RepositoryConfigurationDelegate {
List definitions = new ArrayList<>();
Map> configurationsByRepositoryName = new HashMap<>(configurations.size());
- Map> metadataByRepositoryBeanName = new HashMap<>(configurations.size());
+ Map> metadataByRepositoryBeanName = new HashMap<>(configurations.size());
for (RepositoryConfiguration extends RepositoryConfigurationSource> configuration : configurations) {
@@ -223,7 +219,7 @@ public class RepositoryConfigurationDelegate {
}
private void registerAotComponents(BeanDefinitionRegistry registry, RepositoryConfigurationExtension extension,
- Map> metadataByRepositoryBeanName) {
+ Map> metadataByRepositoryBeanName) {
// module-specific repository aot processor
String repositoryAotProcessorBeanName = String.format("data-%s.repository-aot-processor" /* might be duplicate */,
diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryFragmentConfigurationProvider.java b/src/main/java/org/springframework/data/repository/config/RepositoryFragmentConfigurationProvider.java
new file mode 100644
index 000000000..401f94f7a
--- /dev/null
+++ b/src/main/java/org/springframework/data/repository/config/RepositoryFragmentConfigurationProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.repository.config;
+
+import java.util.List;
+
+/**
+ * Interface exposing {@link RepositoryFragmentConfiguration}.
+ *
+ * @author Mark Paluch
+ * @since 3.0
+ */
+public interface RepositoryFragmentConfigurationProvider {
+
+ /**
+ * Returns the fragment configuration.
+ *
+ * @return the fragment configuration.
+ */
+ List getFragmentConfiguration();
+}
diff --git a/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java b/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java
index c5e3876b4..fba3c4773 100644
--- a/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java
+++ b/src/main/java/org/springframework/data/repository/core/RepositoryInformationSupport.java
@@ -164,7 +164,6 @@ public abstract class RepositoryInformationSupport implements RepositoryInformat
* @return
*/
protected boolean isQueryAnnotationPresentOn(Method method) {
-
return AnnotationUtils.findAnnotation(method, QueryAnnotation.class) != null;
}
diff --git a/src/main/java/org/springframework/data/repository/core/RepositoryMetadata.java b/src/main/java/org/springframework/data/repository/core/RepositoryMetadata.java
index 9788e65f7..e8f0edd0d 100644
--- a/src/main/java/org/springframework/data/repository/core/RepositoryMetadata.java
+++ b/src/main/java/org/springframework/data/repository/core/RepositoryMetadata.java
@@ -129,10 +129,8 @@ public interface RepositoryMetadata {
boolean isReactiveRepository();
/**
- *
* @return
* @since 3.0
- *
*/
Set> getFragments();
}
diff --git a/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java b/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java
index 35d880abc..a7851a304 100644
--- a/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java
+++ b/src/main/java/org/springframework/data/repository/core/support/DefaultRepositoryInformation.java
@@ -25,8 +25,6 @@ import java.util.concurrent.ConcurrentHashMap;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryInformationSupport;
import org.springframework.data.repository.core.RepositoryMetadata;
-import org.springframework.data.util.TypeInformation;
-import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -102,13 +100,7 @@ class DefaultRepositoryInformation extends RepositoryInformationSupport implemen
return baseComposition.getMethod(method) != null;
}
- /**
- *
- * @return
- * @since 3.0
- *
- */
- @Nullable
+ @Override
public Set> getFragments() {
return composition.getFragments().toSet();
}
diff --git a/src/test/java/org/springframework/data/aot/CodeContributionAssert.java b/src/test/java/org/springframework/data/aot/CodeContributionAssert.java
index 072b1f4fb..ade9ca520 100644
--- a/src/test/java/org/springframework/data/aot/CodeContributionAssert.java
+++ b/src/test/java/org/springframework/data/aot/CodeContributionAssert.java
@@ -15,7 +15,7 @@
*/
package org.springframework.data.aot;
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.*;
import java.util.Arrays;
import java.util.stream.Stream;
@@ -25,19 +25,17 @@ import org.assertj.core.api.AbstractAssert;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.hint.ClassProxyHint;
import org.springframework.aot.hint.JdkProxyHint;
-import org.springframework.aot.hint.ProxyHintsPredicates;
import org.springframework.aot.hint.RuntimeHintsPredicates;
/**
- * AssertJ {@link AbstractAssert Assertion} for code contributions originating from
- * Spring Data Repository infrastructure AOT processing.
+ * AssertJ {@link AbstractAssert Assertion} for code contributions originating from Spring Data Repository
+ * infrastructure AOT processing.
*
* @author Christoph Strobl
* @author John Blum
- * @see org.assertj.core.api.AbstractAssert
- * @see org.springframework.aot.generate.GenerationContext
- * @since 3.0.0
+ * @since 3.0
*/
+@SuppressWarnings("UnusedReturnValue")
public class CodeContributionAssert extends AbstractAssert {
public CodeContributionAssert(GenerationContext contribution) {
@@ -47,8 +45,7 @@ public class CodeContributionAssert extends AbstractAssert... types) {
for (Class> type : types) {
- assertThat(this.actual.getRuntimeHints())
- .describedAs("No reflection entry found for [%s]", type)
+ assertThat(this.actual.getRuntimeHints()).describedAs("No reflection entry found for [%s]", type)
.matches(RuntimeHintsPredicates.reflection().onType(type));
}
@@ -58,8 +55,7 @@ public class CodeContributionAssert extends AbstractAssert... types) {
for (Class> type : types) {
- assertThat(this.actual.getRuntimeHints())
- .describedAs("Reflection entry found for [%s]", type)
+ assertThat(this.actual.getRuntimeHints()).describedAs("Reflection entry found for [%s]", type)
.matches(RuntimeHintsPredicates.reflection().onType(type).negate());
}
@@ -68,8 +64,7 @@ public class CodeContributionAssert extends AbstractAssert entryPoint) {
- assertThat(jdkProxiesFor(entryPoint).findFirst())
- .describedAs("No JDK proxy found for [%s]", entryPoint)
+ assertThat(jdkProxiesFor(entryPoint).findFirst()).describedAs("No JDK proxy found for [%s]", entryPoint)
.isPresent();
return this;
@@ -78,8 +73,7 @@ public class CodeContributionAssert extends AbstractAssert entryPoint) {
assertThat(jdkProxiesFor(entryPoint).findFirst())
- .describedAs("Found JDK proxy matching [%s] though it should not be present", entryPoint)
- .isNotPresent();
+ .describedAs("Found JDK proxy matching [%s] though it should not be present", entryPoint).isNotPresent();
return this;
}
@@ -87,8 +81,8 @@ public class CodeContributionAssert extends AbstractAssert... proxyInterfaces) {
assertThat(jdkProxiesFor(proxyInterfaces[0]))
- .describedAs("Unable to find JDK proxy matching [%s]", Arrays.asList(proxyInterfaces))
- .anySatisfy(it -> new JdkProxyAssert(it).matches(proxyInterfaces));
+ .describedAs("Unable to find JDK proxy matching [%s]", Arrays.asList(proxyInterfaces))
+ .anySatisfy(it -> new JdkProxyAssert(it).matches(proxyInterfaces));
return this;
}
@@ -96,8 +90,7 @@ public class CodeContributionAssert extends AbstractAssert... proxyInterfaces) {
assertThat(jdkProxiesFor(proxyInterfaces[0]))
- .describedAs("Found JDK proxy matching [%s] though it should not be present",
- Arrays.asList(proxyInterfaces))
+ .describedAs("Found JDK proxy matching [%s] though it should not be present", Arrays.asList(proxyInterfaces))
.noneSatisfy(it -> new JdkProxyAssert(it).matches(proxyInterfaces));
return this;
@@ -105,9 +98,8 @@ public class CodeContributionAssert extends AbstractAssert jdkProxiesFor(Class> entryPoint) {
- return this.actual.getRuntimeHints().proxies().jdkProxies()
- .filter(jdkProxyHint -> jdkProxyHint.getProxiedInterfaces().get(0).getCanonicalName()
- .equals(entryPoint.getCanonicalName()));
+ return this.actual.getRuntimeHints().proxies().jdkProxies().filter(jdkProxyHint -> jdkProxyHint
+ .getProxiedInterfaces().get(0).getCanonicalName().equals(entryPoint.getCanonicalName()));
}
public CodeContributionAssert contributesClassProxy(Class>... proxyInterfaces) {
@@ -121,8 +113,7 @@ public class CodeContributionAssert extends AbstractAssert classProxiesFor(Class> entryPoint) {
- return this.actual.getRuntimeHints().proxies().classProxies()
- .filter(jdkProxyHint -> jdkProxyHint.getProxiedInterfaces().get(0).getCanonicalName()
- .equals(entryPoint.getCanonicalName()));
+ return this.actual.getRuntimeHints().proxies().classProxies().filter(jdkProxyHint -> jdkProxyHint
+ .getProxiedInterfaces().get(0).getCanonicalName().equals(entryPoint.getCanonicalName()));
}
}
diff --git a/src/test/java/org/springframework/data/aot/JdkProxyAssert.java b/src/test/java/org/springframework/data/aot/JdkProxyAssert.java
index 1b4489fa2..91ebc2aa9 100644
--- a/src/test/java/org/springframework/data/aot/JdkProxyAssert.java
+++ b/src/test/java/org/springframework/data/aot/JdkProxyAssert.java
@@ -26,7 +26,6 @@ import org.springframework.aot.hint.TypeReference;
/**
* @author Christoph Strobl
- * @since 2022/04
*/
public class JdkProxyAssert extends AbstractAssert {
diff --git a/src/test/java/org/springframework/data/aot/ManagedTypesBeanRegistrationAotProcessorUnitTests.java b/src/test/java/org/springframework/data/aot/ManagedTypesBeanRegistrationAotProcessorUnitTests.java
index b0c7d7d95..084162738 100644
--- a/src/test/java/org/springframework/data/aot/ManagedTypesBeanRegistrationAotProcessorUnitTests.java
+++ b/src/test/java/org/springframework/data/aot/ManagedTypesBeanRegistrationAotProcessorUnitTests.java
@@ -24,6 +24,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.aot.generate.ClassNameGenerator;
import org.springframework.aot.generate.DefaultGenerationContext;
+import org.springframework.aot.generate.GeneratedClasses;
import org.springframework.aot.generate.InMemoryGeneratedFiles;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsPredicates;
@@ -72,7 +73,8 @@ class ManagedTypesBeanRegistrationAotProcessorUnitTests {
BeanRegistrationAotContribution contribution = createPostProcessor("commons")
.processAheadOfTime(RegisteredBean.of(beanFactory, "commons.managed-types"));
- DefaultGenerationContext generationContext = new DefaultGenerationContext(new ClassNameGenerator(),
+ DefaultGenerationContext generationContext = new DefaultGenerationContext(
+ new GeneratedClasses(new ClassNameGenerator(Object.class)),
new InMemoryGeneratedFiles(), new RuntimeHints());
contribution.applyTo(generationContext, null);
diff --git a/src/test/java/org/springframework/data/aot/RepositoryRegistrationAotContributionAssert.java b/src/test/java/org/springframework/data/aot/RepositoryRegistrationAotContributionAssert.java
index dc09f71e9..ac4f30bb9 100644
--- a/src/test/java/org/springframework/data/aot/RepositoryRegistrationAotContributionAssert.java
+++ b/src/test/java/org/springframework/data/aot/RepositoryRegistrationAotContributionAssert.java
@@ -15,8 +15,8 @@
*/
package org.springframework.data.aot;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -27,36 +27,41 @@ import org.assertj.core.api.AbstractAssert;
import org.springframework.aot.generate.ClassNameGenerator;
import org.springframework.aot.generate.DefaultGenerationContext;
import org.springframework.aot.generate.InMemoryGeneratedFiles;
-import org.springframework.aot.hint.RuntimeHints;
import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.support.RepositoryFragment;
-import org.springframework.lang.NonNull;
/**
* AssertJ {@link AbstractAssert Assertion} for {@link RepositoryRegistrationAotContribution}.
*
* @author Christoph Strobl
* @author John Blum
- * @see org.mockito.Mockito
- * @see org.assertj.core.api.AbstractAssert
- * @see org.springframework.data.aot.RepositoryRegistrationAotContribution
- * @since 3.0.0
+ * @since 3.0
*/
public class RepositoryRegistrationAotContributionAssert
- extends AbstractAssert {
+ extends AbstractAssert {
- @NonNull
public static RepositoryRegistrationAotContributionAssert assertThatContribution(
- @NonNull RepositoryRegistrationAotContribution actual) {
+ RepositoryRegistrationAotContribution actual) {
return new RepositoryRegistrationAotContributionAssert(actual);
}
- public RepositoryRegistrationAotContributionAssert(@NonNull RepositoryRegistrationAotContribution actual) {
+ /**
+ * Create the assertion object.
+ *
+ * @param actual
+ */
+ public RepositoryRegistrationAotContributionAssert(RepositoryRegistrationAotContribution actual) {
super(actual, RepositoryRegistrationAotContributionAssert.class);
}
+ /**
+ * Verifies that the actual repository type is equal to the given one.
+ *
+ * @param expected
+ * @return {@code this} assertion object.
+ */
public RepositoryRegistrationAotContributionAssert targetRepositoryTypeIs(Class> expected) {
assertThat(getRepositoryInformation().getRepositoryInterface()).isEqualTo(expected);
@@ -64,6 +69,11 @@ public class RepositoryRegistrationAotContributionAssert
return this.myself;
}
+ /**
+ * Verifies that the actual repository has no repository fragments.
+ *
+ * @return {@code this} assertion object.
+ */
public RepositoryRegistrationAotContributionAssert hasNoFragments() {
assertThat(getRepositoryInformation().getFragments()).isEmpty();
@@ -71,6 +81,11 @@ public class RepositoryRegistrationAotContributionAssert
return this;
}
+ /**
+ * Verifies that the actual repository has repository fragments.
+ *
+ * @return {@code this} assertion object.
+ */
public RepositoryRegistrationAotContributionAssert hasFragments() {
assertThat(getRepositoryInformation().getFragments()).isNotEmpty();
@@ -78,10 +93,14 @@ public class RepositoryRegistrationAotContributionAssert
return this;
}
+ /**
+ * Verifies that the actual repository fragments satisfy the given {@link Consumer}.
+ *
+ * @return {@code this} assertion object.
+ */
public RepositoryRegistrationAotContributionAssert verifyFragments(Consumer>> consumer) {
- assertThat(getRepositoryInformation().getFragments())
- .satisfies(it -> consumer.accept(new LinkedHashSet<>(it)));
+ assertThat(getRepositoryInformation().getFragments()).satisfies(it -> consumer.accept(new LinkedHashSet<>(it)));
return this;
}
@@ -91,8 +110,8 @@ public class RepositoryRegistrationAotContributionAssert
BeanRegistrationCode mockBeanRegistrationCode = mock(BeanRegistrationCode.class);
- DefaultGenerationContext generationContext =
- new DefaultGenerationContext(new ClassNameGenerator(), new InMemoryGeneratedFiles(), new RuntimeHints());
+ DefaultGenerationContext generationContext = new DefaultGenerationContext(new ClassNameGenerator(Object.class),
+ new InMemoryGeneratedFiles());
this.actual.applyTo(generationContext, mockBeanRegistrationCode);
@@ -103,13 +122,10 @@ public class RepositoryRegistrationAotContributionAssert
private RepositoryInformation getRepositoryInformation() {
- assertThat(this.actual)
- .describedAs("No repository interface found on null bean contribution")
- .isNotNull();
+ assertThat(this.actual).describedAs("No repository interface found on null bean contribution").isNotNull();
assertThat(this.actual.getRepositoryInformation())
- .describedAs("No repository interface found on null repository information")
- .isNotNull();
+ .describedAs("No repository interface found on null repository information").isNotNull();
return this.actual.getRepositoryInformation();
}
diff --git a/src/test/java/org/springframework/data/aot/RepositoryRegistrationAotProcessorIntegrationTests.java b/src/test/java/org/springframework/data/aot/RepositoryRegistrationAotProcessorIntegrationTests.java
index edf296c7e..93bec97d0 100644
--- a/src/test/java/org/springframework/data/aot/RepositoryRegistrationAotProcessorIntegrationTests.java
+++ b/src/test/java/org/springframework/data/aot/RepositoryRegistrationAotProcessorIntegrationTests.java
@@ -15,8 +15,8 @@
*/
package org.springframework.data.aot;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.springframework.data.aot.RepositoryRegistrationAotContributionAssert.assertThatContribution;
+import static org.assertj.core.api.Assertions.*;
+import static org.springframework.data.aot.RepositoryRegistrationAotContributionAssert.*;
import java.io.Serializable;
@@ -51,9 +51,6 @@ import org.springframework.transaction.interceptor.TransactionalProxy;
* Integration Tests for {@link RepositoryRegistrationAotProcessor}.
*
* @author Christoph Strobl
- * @see org.junit.jupiter.api.Test
- * @see org.springframework.data.aot.RepositoryRegistrationAotProcessor
- * @see org.springframework.data.aot.RepositoryRegistrationAotContributionAssert
* @author John Blum
*/
public class RepositoryRegistrationAotProcessorIntegrationTests {
@@ -61,8 +58,8 @@ public class RepositoryRegistrationAotProcessorIntegrationTests {
@Test // GH-2593
void simpleRepositoryNoTxManagerNoKotlinNoReactiveNoComponent() {
- RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(ConfigWithSimpleCrudRepository.class)
- .forRepository(ConfigWithSimpleCrudRepository.MyRepo.class);
+ RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(
+ ConfigWithSimpleCrudRepository.class).forRepository(ConfigWithSimpleCrudRepository.MyRepo.class);
assertThatContribution(repositoryBeanContribution) //
.targetRepositoryTypeIs(ConfigWithSimpleCrudRepository.MyRepo.class) //
@@ -123,8 +120,7 @@ public class RepositoryRegistrationAotProcessorIntegrationTests {
// interface
.contributesReflectionFor(PagingAndSortingRepository.class) // base repository
.contributesReflectionFor(
- ConfigWithTransactionManagerPresentAndAtComponentAnnotatedRepoisoty.Person.class) // repository domain
- // type
+ ConfigWithTransactionManagerPresentAndAtComponentAnnotatedRepoisoty.Person.class) // domain type
// proxies
.contributesJdkProxy(
@@ -142,8 +138,8 @@ public class RepositoryRegistrationAotProcessorIntegrationTests {
@Test // GH-2593
void contributesFragmentsCorrectly() {
- RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(ConfigWithFragments.class)
- .forRepository(ConfigWithFragments.RepositoryWithFragments.class);
+ RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(
+ ConfigWithFragments.class).forRepository(ConfigWithFragments.RepositoryWithFragments.class);
assertThatContribution(repositoryBeanContribution) //
.targetRepositoryTypeIs(ConfigWithFragments.RepositoryWithFragments.class) //
@@ -175,8 +171,9 @@ public class RepositoryRegistrationAotProcessorIntegrationTests {
@Test // GH-2593
void contributesCustomImplementationCorrectly() {
- RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(ConfigWithCustomImplementation.class)
- .forRepository(ConfigWithCustomImplementation.RepositoryWithCustomImplementation.class);
+ RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(
+ ConfigWithCustomImplementation.class)
+ .forRepository(ConfigWithCustomImplementation.RepositoryWithCustomImplementation.class);
assertThatContribution(repositoryBeanContribution) //
.targetRepositoryTypeIs(ConfigWithCustomImplementation.RepositoryWithCustomImplementation.class) //
@@ -197,12 +194,11 @@ public class RepositoryRegistrationAotProcessorIntegrationTests {
@Test // GH-2593
void contributesDomainTypeAndReachableTypesCorrectly() {
- RepositoryRegistrationAotContribution repositoryBeanContribution =
- computeAotConfiguration(ConfigWithSimpleCrudRepository.class)
- .forRepository(ConfigWithSimpleCrudRepository.MyRepo.class);
+ RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(
+ ConfigWithSimpleCrudRepository.class).forRepository(ConfigWithSimpleCrudRepository.MyRepo.class);
- assertThatContribution(repositoryBeanContribution).codeContributionSatisfies(contribution ->
- contribution.contributesReflectionFor(ConfigWithSimpleCrudRepository.Person.class,
+ assertThatContribution(repositoryBeanContribution).codeContributionSatisfies(
+ contribution -> contribution.contributesReflectionFor(ConfigWithSimpleCrudRepository.Person.class,
ConfigWithSimpleCrudRepository.Address.class));
}
@@ -245,19 +241,18 @@ public class RepositoryRegistrationAotProcessorIntegrationTests {
@Test // GH-2593
void contributesTypesFromQueryMethods() {
- RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(ConfigWithQueryMethods.class)
- .forRepository(ConfigWithQueryMethods.CustomerRepositoryWithQueryMethods.class);
+ RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(
+ ConfigWithQueryMethods.class).forRepository(ConfigWithQueryMethods.CustomerRepositoryWithQueryMethods.class);
assertThatContribution(repositoryBeanContribution)
- .codeContributionSatisfies(contribution ->
- contribution.contributesReflectionFor(ProjectionInterface.class));
+ .codeContributionSatisfies(contribution -> contribution.contributesReflectionFor(ProjectionInterface.class));
}
@Test // GH-2593
void contributesProxiesForPotentialProjections() {
- RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(ConfigWithQueryMethods.class)
- .forRepository(ConfigWithQueryMethods.CustomerRepositoryWithQueryMethods.class);
+ RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(
+ ConfigWithQueryMethods.class).forRepository(ConfigWithQueryMethods.CustomerRepositoryWithQueryMethods.class);
assertThatContribution(repositoryBeanContribution) //
.codeContributionSatisfies(contribution -> {
@@ -271,8 +266,8 @@ public class RepositoryRegistrationAotProcessorIntegrationTests {
@Test // GH-2593
void contributesProxiesForDataAnnotations() {
- RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(ConfigWithQueryMethods.class)
- .forRepository(ConfigWithQueryMethods.CustomerRepositoryWithQueryMethods.class);
+ RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(
+ ConfigWithQueryMethods.class).forRepository(ConfigWithQueryMethods.CustomerRepositoryWithQueryMethods.class);
assertThatContribution(repositoryBeanContribution) //
.codeContributionSatisfies(contribution -> {
@@ -286,8 +281,8 @@ public class RepositoryRegistrationAotProcessorIntegrationTests {
@Test // GH-2593
void doesNotCareAboutNonDataAnnotations() {
- RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(ConfigWithSimpleCrudRepository.class)
- .forRepository(ConfigWithSimpleCrudRepository.MyRepo.class);
+ RepositoryRegistrationAotContribution repositoryBeanContribution = computeAotConfiguration(
+ ConfigWithSimpleCrudRepository.class).forRepository(ConfigWithSimpleCrudRepository.MyRepo.class);
assertThatContribution(repositoryBeanContribution) //
.codeContributionSatisfies(contribution -> {
@@ -311,16 +306,15 @@ public class RepositoryRegistrationAotProcessorIntegrationTests {
String[] repositoryBeanNames = applicationContext.getBeanNamesForType(repositoryType);
assertThat(repositoryBeanNames)
- .describedAs("Unable to find repository [%s] in configuration [%s]",
- repositoryType, configuration)
+ .describedAs("Unable to find repository [%s] in configuration [%s]", repositoryType, configuration)
.hasSize(1);
String repositoryBeanName = repositoryBeanNames[0];
ConfigurableBeanFactory beanFactory = applicationContext.getDefaultListableBeanFactory();
- RepositoryRegistrationAotProcessor repositoryAotProcessor =
- applicationContext.getBean(RepositoryRegistrationAotProcessor.class);
+ RepositoryRegistrationAotProcessor repositoryAotProcessor = applicationContext
+ .getBean(RepositoryRegistrationAotProcessor.class);
repositoryAotProcessor.setBeanFactory(beanFactory);
diff --git a/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java b/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java
index 3a9895bbf..32747be85 100644
--- a/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java
+++ b/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java
@@ -25,6 +25,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.aop.framework.Advised;
+import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
@@ -67,7 +68,7 @@ class RepositoryConfigurationDelegateUnitTests {
var beanDefinition = definition.getBeanDefinition();
- assertThat(beanDefinition.getAttribute(RepositoryConfigurationDelegate.FACTORY_BEAN_OBJECT_TYPE).toString())
+ assertThat(beanDefinition.getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE).toString())
.endsWith("Repository");
}
}