Move runtime hints into another package

Original Pull Request: #2624
This commit is contained in:
Christoph Strobl
2022-06-10 09:29:38 +02:00
parent 51cda9993f
commit 4e23153816
29 changed files with 659 additions and 618 deletions

View File

@@ -28,6 +28,7 @@ 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;
@@ -118,7 +119,7 @@ public interface AotContext {
*/
@NonNull
default TypeScanner getTypeScanner() {
return new TypeScanner(getClassLoader());
return TypeScanner.typeScanner(getClassLoader());
}
/**
@@ -129,14 +130,12 @@ public interface AotContext {
* 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 TypeScanner#scanForTypesAnnotatedWith(Class[])
* @see TypeScanner.Scanner#inPackages(Collection)
* @see #getTypeScanner()
*/
default Set<Class<?>> scanPackageForTypes(@NonNull Collection<Class<? extends Annotation>> identifyingAnnotations,
Collection<String> packageNames) {
return getTypeScanner().scanForTypesAnnotatedWith(identifyingAnnotations).inPackages(packageNames);
return getTypeScanner().scanPackages(packageNames).forTypesAnnotatedWith(identifyingAnnotations).collectAsSet();
}
/**

View File

@@ -1,105 +0,0 @@
/*
* 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.Properties;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.framework.Advised;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.DecoratingProxy;
import org.springframework.core.io.InputStreamSource;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
import org.springframework.data.repository.core.support.RepositoryFragment;
import org.springframework.data.repository.core.support.RepositoryFragmentsFactoryBean;
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
import org.springframework.data.repository.query.QueryByExampleExecutor;
import org.springframework.lang.Nullable;
/**
* @author Christoph Strobl
* @since 3.0
*/
public class DataRuntimeHints implements RuntimeHintsRegistrar {
/*
NativeHint(trigger = MappingContext.class,
types = {
@TypeHint(types = {
RepositoryFactoryBeanSupport.class,
RepositoryFragmentsFactoryBean.class,
RepositoryFragment.class,
TransactionalRepositoryFactoryBeanSupport.class,
QueryByExampleExecutor.class,
MappingContext.class,
RepositoryMetadata.class,
RepositoryMetadata.class,
}),
@TypeHint(types = {ReadingConverter.class, WritingConverter.class}),
@TypeHint(types = {Properties.class, BeanFactory.class, InputStreamSource[].class}),
@TypeHint(types = Throwable.class, access = { TypeAccess.DECLARED_CONSTRUCTORS, TypeAccess.DECLARED_FIELDS}),
@TypeHint(typeNames = {
"org.springframework.data.projection.SpelEvaluatingMethodInterceptor$TargetWrapper",
}, access = { TypeAccess.DECLARED_CONSTRUCTORS, TypeAccess.DECLARED_METHODS, TypeAccess.PUBLIC_METHODS })
},
jdkProxies = @JdkProxyHint(typeNames = {
"org.springframework.data.annotation.QueryAnnotation",
"org.springframework.core.annotation.SynthesizedAnnotation" }
),
initialization = @InitializationHint(types = AbstractMappingContext.class, initTime = InitializationTime.BUILD)
)
*/
@Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
System.out.println("Spring data Runtime Hints");
hints.reflection()
.registerTypes(Arrays.asList(TypeReference.of(RepositoryFactoryBeanSupport.class),
TypeReference.of(RepositoryFragmentsFactoryBean.class), TypeReference.of(RepositoryFragment.class),
TypeReference.of(TransactionalRepositoryFactoryBeanSupport.class),
TypeReference.of(QueryByExampleExecutor.class), TypeReference.of(MappingContext.class),
TypeReference.of(RepositoryMetadata.class)), builder -> {
builder.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS);
});
hints.reflection().registerTypes(
Arrays.asList(TypeReference.of(Properties.class), TypeReference.of(BeanFactory.class),
TypeReference.of(InputStreamSource[].class)),
builder -> builder.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));
hints.reflection().registerType(Throwable.class,
builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS));
hints.reflection().registerType(
TypeReference.of("org.springframework.data.projection.SpelEvaluatingMethodInterceptor$TargetWrapper"),
builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.INVOKE_PUBLIC_METHODS));
hints.proxies().registerJdkProxy(TypeReference.of("org.springframework.data.annotation.QueryAnnotation"),
TypeReference.of("org.springframework.core.annotation.SynthesizedAnnotation"));
hints.proxies().registerJdkProxy(TypeReference.of(AuditorAware.class), TypeReference.of(SpringProxy.class), TypeReference.of(Advised.class), TypeReference.of(DecoratingProxy.class));
}
}

View File

@@ -22,7 +22,6 @@ import java.util.stream.Collectors;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.data.aot.TypeScanner.Scanner;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.util.Lazy;
@@ -128,12 +127,10 @@ class DefaultAotRepositoryContext implements AotRepositoryContext {
if (!getIdentifyingAnnotations().isEmpty()) {
Scanner typeScanner = aotContext.getTypeScanner().scanForTypesAnnotatedWith(getIdentifyingAnnotations());
Set<Class<?>> classes = typeScanner.inPackages(getBasePackages());
Set<Class<?>> classes = aotContext.getTypeScanner().scanPackages(getBasePackages()).forTypesAnnotatedWith(getIdentifyingAnnotations()).collectAsSet();
types.addAll(TypeCollector.inspect(classes).list());
}
// context.get
return types;
}
}

View File

@@ -20,25 +20,21 @@ 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.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.ResolvableType;
import org.springframework.data.ManagedTypes;
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;
/**
* {@link BeanRegistrationAotProcessor} handling {@link #getModulePrefix() module prefixed} {@link ManagedTypes}
* instances. This AOT processor allows store specific handling of discovered types to be registered.
* {@link BeanRegistrationAotProcessor} handling {@link #getModuleIdentifier() module} {@link ManagedTypes} instances.
* This AOT processor allows store specific handling of discovered types to be registered.
*
* @author Christoph Strobl
* @author John Blum
@@ -46,28 +42,21 @@ import org.springframework.util.StringUtils;
* @see org.springframework.beans.factory.aot.BeanRegistrationAotProcessor
* @since 3.0
*/
public class ManagedTypesRegistrationAotProcessor implements BeanRegistrationAotProcessor, BeanFactoryAware {
public class ManagedTypesBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {
private final Log logger = LogFactory.getLog(getClass());
private BeanFactory beanFactory;
@Nullable
private String modulePrefix;
@Nullable private String moduleIdentifier;
@Override
public BeanRegistrationAotContribution processAheadOfTime(@NonNull RegisteredBean registeredBean) {
return contribute(registeredBean.getMergedBeanDefinition(), registeredBean.getBeanClass(), registeredBean.getBeanName());
}
@Nullable
@SuppressWarnings("unused")
protected BeanRegistrationAotContribution contribute(@NonNull RootBeanDefinition beanDefinition,
@NonNull Class<?> beanType, @NonNull String beanName) {
if (!isMatch(registeredBean.getBeanClass(), registeredBean.getBeanName())) {
return null;
}
return isMatch(beanType, beanName)
? contribute(AotContext.from(beanFactory), beanFactory.getBean(beanName, ManagedTypes.class))
: null;
BeanFactory beanFactory = registeredBean.getBeanFactory();
return contribute(AotContext.from(registeredBean.getBeanFactory()),
beanFactory.getBean(registeredBean.getBeanName(), ManagedTypes.class));
}
protected boolean isMatch(@Nullable Class<?> beanType, @Nullable String beanName) {
@@ -79,16 +68,16 @@ public class ManagedTypesRegistrationAotProcessor implements BeanRegistrationAot
}
protected boolean matchesPrefix(@Nullable String beanName) {
return StringUtils.startsWithIgnoreCase(beanName, getModulePrefix());
return StringUtils.startsWithIgnoreCase(beanName, getModuleIdentifier());
}
/**
* Hook to provide a customized flavor of {@link BeanRegistrationAotContribution}. By overriding this method
* calls to {@link #contributeType(ResolvableType, GenerationContext)} might no longer be issued.
* Hook to provide a customized flavor of {@link BeanRegistrationAotContribution}. By overriding this method calls to
* {@link #contributeType(ResolvableType, GenerationContext)} might no longer be issued.
*
* @param aotContext never {@literal null}.
* @param managedTypes never {@literal null}.
* @return new instance of {@link ManagedTypesRegistrationAotProcessor} or {@literal null} if nothing to do.
* @return new instance of {@link ManagedTypesBeanRegistrationAotProcessor} or {@literal null} if nothing to do.
*/
@Nullable
protected BeanRegistrationAotContribution contribute(AotContext aotContext, ManagedTypes managedTypes) {
@@ -111,21 +100,16 @@ public class ManagedTypesRegistrationAotProcessor implements BeanRegistrationAot
TypeContributor.contribute(type.toClass(), annotationNamespaces, generationContext);
TypeUtils.resolveUsedAnnotations(type.toClass()).forEach(annotation ->
TypeContributor.contribute(annotation.getType(), annotationNamespaces, generationContext));
TypeUtils.resolveUsedAnnotations(type.toClass()).forEach(
annotation -> TypeContributor.contribute(annotation.getType(), annotationNamespaces, generationContext));
}
@Override
public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
public void setModulePrefix(@Nullable String modulePrefix) {
this.modulePrefix = modulePrefix;
public void setModuleIdentifier(@Nullable String moduleIdentifier) {
this.moduleIdentifier = moduleIdentifier;
}
@Nullable
public String getModulePrefix() {
return this.modulePrefix;
public String getModuleIdentifier() {
return this.moduleIdentifier;
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2012-2018 the original author or authors.
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -22,7 +22,7 @@ import org.springframework.aot.generate.GenerationContext;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.core.ResolvableType;
import org.springframework.data.ManagedTypes;
import org.springframework.data.domain.ManagedTypes;
import org.springframework.lang.NonNull;
/**
@@ -52,7 +52,7 @@ public class ManagedTypesRegistrationAotContribution implements BeanRegistration
@NonNull
protected ManagedTypes getManagedTypes() {
return ManagedTypes.nullSafeManagedTypes(this.managedTypes);
return managedTypes == null ? ManagedTypes.empty() : managedTypes;
}
@Override

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2012-2018 the original author or authors.
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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,

View File

@@ -26,8 +26,6 @@ public class PublicMethodReflectiveProcessor extends SimpleReflectiveProcessor {
@Override
protected void registerTypeHint(ReflectionHints hints, Class<?> type) {
System.out.println("invoking reflective hint annotation for : " + type);
hints.registerType(type, builder -> builder.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2012-2018 the original author or authors.
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -197,10 +197,10 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
Map<String, RepositoryConfigurationExtensionSupport> 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,

View File

@@ -15,11 +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;
@@ -27,14 +28,16 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.data.ManagedTypes;
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;
/**
* {@link BeanFactoryInitializationAotProcessor} implementation used to encapsulate common data infrastructure concerns
* and preprocess the {@link ConfigurableListableBeanFactory} ahead of the AOT compilation in order to prepare
* the Spring Data {@link BeanDefinition BeanDefinitions} for AOT processing.
* and preprocess the {@link ConfigurableListableBeanFactory} ahead of the AOT compilation in order to prepare the
* Spring Data {@link BeanDefinition BeanDefinitions} for AOT processing.
*
* @author Christoph Strobl
* @author John Blum
@@ -63,8 +66,11 @@ public class SpringDataBeanFactoryInitializationAotProcessor implements BeanFact
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
ValueHolder argumentValue = beanDefinition.getConstructorArgumentValues()
.getArgumentValue(0, null, null, null);
if(beanDefinition.getConstructorArgumentValues().isEmpty()) {
return;
}
ValueHolder argumentValue = beanDefinition.getConstructorArgumentValues().getArgumentValue(0, null, null, null);
if (argumentValue.getValue() instanceof Supplier supplier) {
@@ -72,11 +78,16 @@ public class SpringDataBeanFactoryInitializationAotProcessor implements BeanFact
logger.info(String.format("Replacing ManagedType bean definition %s.", beanName));
}
BeanDefinition beanDefinitionReplacement = BeanDefinitionBuilder
.rootBeanDefinition(ManagedTypes.class)
.setFactoryMethod("of")
.addConstructorArgValue(supplier.get())
.getBeanDefinition();
Object value = supplier.get();
if(ObjectUtils.isArray(value)) {
value = CollectionUtils.arrayToList(value);
}
if(!(value instanceof Iterable<?>)) {
value = Collections.singleton(value);
}
BeanDefinition beanDefinitionReplacement = BeanDefinitionBuilder.rootBeanDefinition(ManagedTypes.class)
.setFactoryMethod("fromIterable").addConstructorArgValue(value).getBeanDefinition();
registry.removeBeanDefinition(beanName);
registry.registerBeanDefinition(beanName, beanDefinitionReplacement);

View File

@@ -1,166 +0,0 @@
/*
* 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.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
* Scanner used to scan for {@link Class types} that will be added to the AOT processing infrastructure.
*
* @author Christoph Strobl
* @author John Blum
*/
// TODO: Replace this with AnnotatedTypeScanner, maybe?
public class TypeScanner {
/**
* Factory method used to construct a new {@link TypeScanner} initialized with the given {@link ClassLoader}
* used to resolve scanned {@link Class type}.
*
* @param classLoader {@link ClassLoader} used to resolve scanned {@link Class types}.
* @return a new {@link TypeScanner}.
*/
@NonNull
static TypeScanner scanner(@Nullable ClassLoader classLoader) {
return new TypeScanner(classLoader);
}
private final ClassLoader classLoader;
/**
* Constructs a new instance of {@link TypeScanner} initialized with the given {@link ClassLoader}
* used to resolve scanned {@link Class types}.
*
* @param classLoader {@link ClassLoader} used to resolve scanned {@link Class types}.
*/
public TypeScanner(@Nullable ClassLoader classLoader) {
this.classLoader = classLoader;
}
/**
* Scans for {@link Class types} potentially annotated with any of the given {@link Annotation} types.
*
* @param annotations array of {@link Annotation} types used to filter the scanned {@link Class types};
* must not be {@literal null}.
* @return new instance of {@link Scanner}.
* @see #scanForTypesAnnotatedWith(Collection)
* @see Scanner
*/
@SuppressWarnings("unchecked")
public Scanner scanForTypesAnnotatedWith(Class<? extends Annotation>... annotations) {
return scanForTypesAnnotatedWith(Arrays.asList(annotations));
}
/**
* Scans for {@link Class types} potentially annotated with any of the given {@link Annotation} types.
*
* @param annotations {@link Collection} of {@link Annotation} types used to filter the scanned {@link Class types}.
* @return new instance of {@link Scanner}.
* @see #scanForTypesAnnotatedWith(Class[])
* @see Scanner
*/
public Scanner scanForTypesAnnotatedWith(Collection<Class<? extends Annotation>> annotations) {
return new ScannerImpl().includeTypesAnnotatedWith(annotations);
}
public interface Scanner {
/**
* Collects the {@link String names} of packages to scan.
*
* @param packageNames array of {@link String package names} ot scan; must not be {@literal null}.
* @return the resolved, scanned {@link Class types}.
* @see #inPackages(Collection)
*/
default Set<Class<?>> inPackages(String... packageNames) {
return inPackages(Arrays.asList(packageNames));
}
/**
* Collects the {@link String names} of packages to scan.
*
* @param packageNames {@link Collection} of {@link String package names} ot scan.
* @return the resolved, scanned {@link Class types}.
* @see #inPackages(String...)
*/
Set<Class<?>> inPackages(Collection<String> packageNames);
}
class ScannerImpl implements Scanner {
ClassPathScanningCandidateComponentProvider componentProvider;
ScannerImpl() {
componentProvider = new ClassPathScanningCandidateComponentProvider(false);
componentProvider.setEnvironment(new StandardEnvironment());
componentProvider.setResourceLoader(new DefaultResourceLoader(classLoader));
}
ScannerImpl includeTypesAnnotatedWith(Collection<Class<? extends Annotation>> annotations) {
nullSafeCollection(annotations).stream()
.map(AnnotationTypeFilter::new)
.forEach(componentProvider::addIncludeFilter);
return this;
}
@Override
public Set<Class<?>> inPackages(Collection<String> packageNames) {
Set<Class<?>> types = new LinkedHashSet<>();
nullSafeCollection(packageNames).forEach(pkg ->
componentProvider.findCandidateComponents(pkg).forEach(it ->
resolveType(it.getBeanClassName()).ifPresent(types::add)));
return types;
}
@NonNull
private <T> Collection<T> nullSafeCollection(@Nullable Collection<T> collection) {
return collection != null ? collection : Collections.emptySet();
}
}
private Optional<Class<?>> resolveType(String typeName) {
if (ClassUtils.isPresent(typeName, classLoader)) {
try {
return Optional.of(ClassUtils.forName(typeName, classLoader));
} catch (ClassNotFoundException ignore) {
// just do nothing
}
}
return Optional.empty();
}
}

View File

@@ -0,0 +1,69 @@
/*
* 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.hint;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.framework.Advised;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.core.DecoratingProxy;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.domain.ReactiveAuditorAware;
import org.springframework.lang.Nullable;
/**
* @author Christoph Strobl
* @since 3.0
*/
public class AuditingHints {
/**
* {@link RuntimeHintsRegistrar} to be applied when auditing is enabled. Can be used along with
* {@link org.springframework.context.annotation.ImportRuntimeHints @ImportRuntimeHints} for conditional registration.
*
* @author Christoph Strobl
* @since 3.0
*/
public static class AuditingRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
registerSpringProxy(AuditorAware.class, hints);
}
}
/**
* {@link RuntimeHintsRegistrar} to be applied when reactive auditing is enabled. Can be used along with
* {@link org.springframework.context.annotation.ImportRuntimeHints @ImportRuntimeHints} for conditional registration.
*
* @author Christoph Strobl
* @since 3.0
*/
public static class ReactiveAuditingRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
registerSpringProxy(ReactiveAuditorAware.class, hints);
}
}
private static void registerSpringProxy(Class<?> type, RuntimeHints runtimeHints) {
runtimeHints.proxies().registerJdkProxy(TypeReference.of(type), TypeReference.of(SpringProxy.class),
TypeReference.of(Advised.class), TypeReference.of(DecoratingProxy.class));
}
}

View File

@@ -0,0 +1,83 @@
/*
* 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.hint;
import java.util.Arrays;
import java.util.Properties;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.io.InputStreamSource;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
import org.springframework.data.repository.core.support.RepositoryFragment;
import org.springframework.data.repository.core.support.RepositoryFragmentsFactoryBean;
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
import org.springframework.data.repository.query.QueryByExampleExecutor;
import org.springframework.lang.Nullable;
/**
* {@link RuntimeHintsRegistrar} holding required hints to bootstrap data repositories. <br />
* Already registered via {@literal aot.factories}.
*
* @author Christoph Strobl
* @since 3.0
*/
public class RepositoryRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
// repository infrastructure
hints.reflection().registerTypes(Arrays.asList( //
TypeReference.of(RepositoryFactoryBeanSupport.class), //
TypeReference.of(RepositoryFragmentsFactoryBean.class), //
TypeReference.of(RepositoryFragment.class), //
TypeReference.of(TransactionalRepositoryFactoryBeanSupport.class), //
TypeReference.of(QueryByExampleExecutor.class), //
TypeReference.of(MappingContext.class), //
TypeReference.of(RepositoryMetadata.class) //
), builder -> {
builder.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS);
});
// named queries
hints.reflection().registerTypes(Arrays.asList( //
TypeReference.of(Properties.class), //
TypeReference.of(BeanFactory.class), //
TypeReference.of(InputStreamSource[].class) //
), builder -> builder.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));
//
hints.reflection().registerType(Throwable.class,
builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS));
// SpEL support
hints.reflection().registerType(
TypeReference.of("org.springframework.data.projection.SpelEvaluatingMethodInterceptor$TargetWrapper"),
builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.INVOKE_PUBLIC_METHODS));
// annotated queries
hints.proxies().registerJdkProxy( //
TypeReference.of("org.springframework.data.annotation.QueryAnnotation"), //
TypeReference.of("org.springframework.core.annotation.SynthesizedAnnotation"));
}
}