Resolve package cycle between repository and aot packages.

Closes #2707
This commit is contained in:
Mark Paluch
2022-10-11 11:44:45 +02:00
parent 0fe04e37f8
commit 103d41f7f4
15 changed files with 87 additions and 78 deletions

View File

@@ -25,8 +25,6 @@ import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.core.DecoratingProxy;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.domain.ReactiveAuditorAware;
import org.springframework.data.repository.util.ReactiveWrappers;
import org.springframework.data.repository.util.ReactiveWrappers.ReactiveLibrary;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
@@ -40,6 +38,9 @@ import org.springframework.util.ClassUtils;
*/
class AuditingBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {
private static final boolean PROJECT_REACTOR_PRESENT = ClassUtils.isPresent("reactor.core.publisher.Flux",
AuditingBeanRegistrationAotProcessor.class.getClassLoader());
@Nullable
@Override
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
@@ -49,7 +50,7 @@ class AuditingBeanRegistrationAotProcessor implements BeanRegistrationAotProcess
generationContext.getRuntimeHints());
}
if (ReactiveWrappers.isAvailable(ReactiveLibrary.PROJECT_REACTOR) && isReactiveAuditorAware(registeredBean)) {
if (PROJECT_REACTOR_PRESENT && isReactiveAuditorAware(registeredBean)) {
return (generationContext, beanRegistrationCode) -> registerSpringProxy(ReactiveAuditorAware.class,
generationContext.getRuntimeHints());
}

View File

@@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.aot;
package org.springframework.data.repository.aot;
import java.lang.annotation.Annotation;
import java.util.Set;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.data.aot.AotContext;
import org.springframework.data.repository.core.RepositoryInformation;
/**

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.aot;
package org.springframework.data.repository.aot;
import java.lang.reflect.Method;
import java.util.Collection;
@@ -43,29 +43,29 @@ class AotRepositoryInformation extends RepositoryInformationSupport implements R
this.fragments = fragments;
}
/**
* @return configured repository fragments.
* @since 3.0
*/
@Override
public Set<RepositoryFragment<?>> getFragments() {
return new LinkedHashSet<>(fragments.get());
}
// Not required during AOT processing.
@Override
public boolean isCustomMethod(Method method) {
// TODO:
return false;
}
@Override
public boolean isBaseClassMethod(Method method) {
// TODO
return false;
}
@Override
public Method getTargetClassMethod(Method method) {
// TODO
return method;
}
/**
* @return configured repository fragments.
* @since 3.0
*/
public Set<RepositoryFragment<?>> getFragments() {
return new LinkedHashSet<>(fragments.get());
}
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.aot;
package org.springframework.data.repository.aot;
import java.lang.annotation.Annotation;
import java.util.LinkedHashSet;
@@ -22,6 +22,9 @@ import java.util.stream.Collectors;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.data.aot.AotContext;
import org.springframework.data.aot.TypeCollector;
import org.springframework.data.aot.TypeUtils;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.util.Lazy;
@@ -104,12 +107,12 @@ class DefaultAotRepositoryContext implements AotRepositoryContext {
}
@Override
public TypeIntrospector introspectType(String typeName) {
public AotContext.TypeIntrospector introspectType(String typeName) {
return aotContext.introspectType(typeName);
}
@Override
public IntrospectedBeanDefinition introspectBeanDefinition(String beanName) {
public AotContext.IntrospectedBeanDefinition introspectBeanDefinition(String beanName) {
return aotContext.introspectBeanDefinition(beanName);
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.aot;
package org.springframework.data.repository.aot;
import java.util.ArrayList;
import java.util.Collection;
@@ -81,9 +81,8 @@ class RepositoryBeanDefinitionReader {
}));
}
static Supplier<org.springframework.data.repository.core.RepositoryMetadata> metadataSupplier(
private static Supplier<org.springframework.data.repository.core.RepositoryMetadata> metadataSupplier(
RepositoryConfiguration<?> metadata, ConfigurableListableBeanFactory beanFactory) {
return Lazy.of(() -> new DefaultRepositoryMetadata(forName(metadata.getRepositoryInterface(), beanFactory)));
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.aot;
package org.springframework.data.repository.aot;
import java.io.Serializable;
import java.lang.annotation.Annotation;
@@ -41,7 +41,9 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.DecoratingProxy;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.data.aot.AotContext;
import org.springframework.data.aot.TypeContributor;
import org.springframework.data.aot.TypeUtils;
import org.springframework.data.projection.EntityProjectionIntrospector;
import org.springframework.data.projection.TargetAware;
import org.springframework.data.repository.Repository;
@@ -73,7 +75,7 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
* 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
* @see RepositoryRegistrationAotProcessor
*/
public static RepositoryRegistrationAotContribution fromProcessor(
RepositoryRegistrationAotProcessor repositoryRegistrationAotProcessor) {
@@ -94,7 +96,7 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
* @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
* @see RepositoryRegistrationAotProcessor
*/
protected RepositoryRegistrationAotContribution(
RepositoryRegistrationAotProcessor repositoryRegistrationAotProcessor) {
@@ -232,10 +234,6 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
}
}
private boolean isRepositoryWithTypeParameters(ResolvableType type) {
return type.getGenerics().length == 3;
}
/**
* {@link BiConsumer Callback} for data module specific contributions.
*
@@ -380,24 +378,14 @@ public class RepositoryRegistrationAotContribution implements BeanRegistrationAo
|| ClassUtils.isPrimitiveArray(type); //
}
static boolean isSpringDataManagedAnnotation(@Nullable MergedAnnotation<?> annotation) {
return annotation != null && (isInSpringDataNamespace(annotation.getType())
|| annotation.getMetaTypes().stream().anyMatch(RepositoryRegistrationAotContribution::isInSpringDataNamespace));
}
static boolean isInSpringDataNamespace(Class<?> type) {
return type.getPackage().getName().startsWith(TypeContributor.DATA_NAMESPACE);
}
static void contributeType(Class<?> type, GenerationContext generationContext) {
TypeContributor.contribute(type, it -> true, generationContext);
}
// 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?
public Predicate<Class<?>> typeFilter() { // like only document ones. // TODO: As in MongoDB?
return it -> true;
}
private static boolean isRepositoryWithTypeParameters(ResolvableType type) {
return type.getGenerics().length == 3;
}
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.aot;
package org.springframework.data.repository.aot;
import java.lang.annotation.Annotation;
import java.util.Collections;
@@ -35,6 +35,7 @@ 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.aot.TypeContributor;
import org.springframework.data.repository.config.RepositoryConfiguration;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
@@ -83,11 +84,11 @@ public class RepositoryRegistrationAotProcessor implements BeanRegistrationAotPr
repositoryContext.getResolvedTypes().stream()
.filter(it -> !RepositoryRegistrationAotContribution.isJavaOrPrimitiveType(it))
.forEach(it -> RepositoryRegistrationAotContribution.contributeType(it, generationContext));
.forEach(it -> RepositoryRegistrationAotProcessor.contributeType(it, generationContext));
repositoryContext.getResolvedAnnotations().stream()
.filter(RepositoryRegistrationAotContribution::isSpringDataManagedAnnotation).map(MergedAnnotation::getType)
.forEach(it -> RepositoryRegistrationAotContribution.contributeType(it, generationContext));
.filter(RepositoryRegistrationAotProcessor::isSpringDataManagedAnnotation).map(MergedAnnotation::getType)
.forEach(it -> RepositoryRegistrationAotProcessor.contributeType(it, generationContext));
}
private boolean isRepositoryBean(RegisteredBean bean) {
@@ -161,4 +162,18 @@ public class RepositoryRegistrationAotProcessor implements BeanRegistrationAotPr
protected void logTrace(String message, Object... arguments) {
logAt(Log::isTraceEnabled, Log::trace, message, arguments);
}
private static boolean isSpringDataManagedAnnotation(@Nullable MergedAnnotation<?> annotation) {
return annotation != null && (isInSpringDataNamespace(annotation.getType())
|| annotation.getMetaTypes().stream().anyMatch(RepositoryRegistrationAotProcessor::isInSpringDataNamespace));
}
private static void contributeType(Class<?> type, GenerationContext generationContext) {
TypeContributor.contribute(type, it -> true, generationContext);
}
private static boolean isInSpringDataNamespace(Class<?> type) {
return type.getPackage().getName().startsWith(TypeContributor.DATA_NAMESPACE);
}
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.aot.hint;
package org.springframework.data.repository.aot.hint;
import java.util.Arrays;
import java.util.Properties;

View File

@@ -2,4 +2,4 @@
* Predefined Runtime Hints.
*/
@org.springframework.lang.NonNullApi
package org.springframework.data.aot.hint;
package org.springframework.data.repository.aot.hint;

View File

@@ -0,0 +1,5 @@
/**
* Support for processing of repositories with Ahead of Time compilation.
*/
@org.springframework.lang.NonNullApi
package org.springframework.data.repository.aot;

View File

@@ -18,15 +18,13 @@ package org.springframework.data.repository.config;
import java.util.Collection;
import java.util.Locale;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.io.ResourceLoader;
import org.springframework.data.aot.RepositoryRegistrationAotProcessor;
import org.springframework.data.repository.aot.RepositoryRegistrationAotProcessor;
import org.springframework.lang.NonNull;
import org.springframework.util.StringUtils;
/**
* SPI to implement store specific extension to the repository bean definition registration process.
@@ -46,9 +44,7 @@ public interface RepositoryConfigurationExtension {
*/
default String getModuleIdentifier() {
return getModuleName()
.toLowerCase(Locale.ENGLISH)
.replace(' ', '-');
return getModuleName().toLowerCase(Locale.ENGLISH).replace(' ', '-');
}
/**
@@ -63,7 +59,7 @@ public interface RepositoryConfigurationExtension {
* required by the Spring Data Repository infrastructure components at native runtime.
*
* @return the {@link BeanRegistrationAotProcessor} type responsible for contributing AOT/native configuration.
* Defaults to {@link RepositoryRegistrationAotProcessor}. Must not be {@literal null}.
* Defaults to {@link RepositoryRegistrationAotProcessor}. Must not be {@literal null}.
* @see org.springframework.beans.factory.aot.BeanRegistrationAotProcessor
* @since 3.0
*/
@@ -75,8 +71,8 @@ public interface RepositoryConfigurationExtension {
/**
* Returns all {@link RepositoryConfiguration}s obtained through the given {@link RepositoryConfigurationSource}.
*
* @param configSource {@link RepositoryConfigurationSource} encapsulating the source (XML, Annotation) of
* the repository configuration.
* @param configSource {@link RepositoryConfigurationSource} encapsulating the source (XML, Annotation) of the
* repository configuration.
* @param loader {@link ResourceLoader} used to load resources.
* @param strictMatchesOnly whether to return strict repository matches only. Handing in {@literal true} will cause
* the repository interfaces and domain types handled to be checked whether they are managed by the current
@@ -107,8 +103,8 @@ public interface RepositoryConfigurationExtension {
* repositories bean definitions have been registered.
*
* @param registry {@link BeanDefinitionRegistry} containing bean definitions.
* @param configurationSource {@link RepositoryConfigurationSource} encapsulating the source (e.g. XML, Annotation)
* of the repository configuration.
* @param configurationSource {@link RepositoryConfigurationSource} encapsulating the source (e.g. XML, Annotation) of
* the repository configuration.
*/
void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource configurationSource);