Browse Source

Adapt to AOT Infrastructure changes in Commons.

See spring-projects/spring-data-commons#3267
pull/4854/head
Mark Paluch 3 months ago
parent
commit
4f0d75b05a
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 2
      spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/repository/AotRepositoryBenchmark.java
  2. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/MongoAotPredicates.java
  3. 9
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/MongoManagedTypesBeanRegistrationAotProcessor.java
  4. 48
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/MongoTypeFilters.java
  5. 22
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AotMongoRepositoryPostProcessor.java
  6. 3
      spring-data-mongodb/src/main/resources/META-INF/spring/aot.factories
  7. 5
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/AotFragmentTestConfigurationSupport.java
  8. 81
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/AotMongoRepositoryPostProcessorUnitTests.java
  9. 4
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/QueryMethodContributionUnitTests.java
  10. 81
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/TestMongoAotRepositoryContext.java

2
spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/repository/AotRepositoryBenchmark.java

@ -24,6 +24,7 @@ import org.openjdk.jmh.annotations.State; @@ -24,6 +24,7 @@ import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.springframework.aot.test.generate.TestGenerationContext;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.test.tools.TestCompiler;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
@ -57,6 +58,7 @@ public class AotRepositoryBenchmark extends AbstractMicrobenchmark { @@ -57,6 +58,7 @@ public class AotRepositoryBenchmark extends AbstractMicrobenchmark {
public static Class<?> aot;
public static TestMongoAotRepositoryContext repositoryContext = new TestMongoAotRepositoryContext(
new DefaultListableBeanFactory(),
SmallerPersonRepository.class,
RepositoryComposition.of(RepositoryFragment.structural(SimpleMongoRepository.class),
RepositoryFragment.structural(QuerydslMongoPredicateExecutor.class)));

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/MongoAotPredicates.java

@ -34,7 +34,7 @@ import org.springframework.util.ClassUtils; @@ -34,7 +34,7 @@ import org.springframework.util.ClassUtils;
public class MongoAotPredicates {
public static final Predicate<Class<?>> IS_SIMPLE_TYPE = (type) -> MongoSimpleTypes.HOLDER.isSimpleType(type)
|| TypeUtils.type(type).isPartOf("org.bson");
|| TypeUtils.type(type).isPartOf("org.bson") || TypeUtils.type(type).isPartOf("com.mongodb");
public static final Predicate<ReactiveLibrary> IS_REACTIVE_LIBARARY_AVAILABLE = ReactiveWrappers::isAvailable;
public static final Predicate<ClassLoader> IS_SYNC_CLIENT_PRESENT = (classLoader) -> ClassUtils
.isPresent("com.mongodb.client.MongoClient", classLoader);

9
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/MongoManagedTypesBeanRegistrationAotProcessor.java

@ -45,13 +45,8 @@ class MongoManagedTypesBeanRegistrationAotProcessor extends ManagedTypesBeanRegi @@ -45,13 +45,8 @@ class MongoManagedTypesBeanRegistrationAotProcessor extends ManagedTypesBeanRegi
}
@Override
protected void contributeType(ResolvableType type, GenerationContext generationContext, AotContext aotContext) {
if (MongoAotPredicates.IS_SIMPLE_TYPE.test(type.toClass())) {
return;
}
super.contributeType(type, generationContext, aotContext);
protected void registerTypeHints(ResolvableType type, AotContext aotContext, GenerationContext generationContext) {
super.registerTypeHints(type, aotContext, generationContext);
lazyLoadingProxyAotProcessor.registerLazyLoadingProxyIfNeeded(type.toClass(), generationContext);
}
}

48
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/MongoTypeFilters.java

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
/*
* Copyright 2025 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.mongodb.aot;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.function.Predicate;
import org.springframework.data.util.Predicates;
import org.springframework.data.util.TypeCollector;
/**
* {@link TypeCollector} predicates to exclude MongoDB driver types.
*
* @author Mark Paluch
* @since 5.0
*/
class MongoTypeFilters implements TypeCollector.TypeCollectorFilters {
@Override
public Predicate<Class<?>> classPredicate() {
return MongoAotPredicates.IS_SIMPLE_TYPE.negate();
}
@Override
public Predicate<Field> fieldPredicate() {
return Predicates.<Field> declaringClass(MongoAotPredicates.IS_SIMPLE_TYPE).negate();
}
@Override
public Predicate<Method> methodPredicate() {
return Predicates.<Method> declaringClass(MongoAotPredicates.IS_SIMPLE_TYPE).negate();
}
}

22
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AotMongoRepositoryPostProcessor.java

@ -23,12 +23,12 @@ import org.springframework.data.mongodb.aot.MongoAotPredicates; @@ -23,12 +23,12 @@ import org.springframework.data.mongodb.aot.MongoAotPredicates;
import org.springframework.data.repository.config.AotRepositoryContext;
import org.springframework.data.repository.config.RepositoryRegistrationAotProcessor;
import org.springframework.data.util.TypeContributor;
import org.springframework.data.util.TypeUtils;
/**
* Mongodb-specific {@link RepositoryRegistrationAotProcessor} that contributes generated code for repositories.
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 4.0
*/
public class AotMongoRepositoryPostProcessor extends RepositoryRegistrationAotProcessor {
@ -38,32 +38,24 @@ public class AotMongoRepositoryPostProcessor extends RepositoryRegistrationAotPr @@ -38,32 +38,24 @@ public class AotMongoRepositoryPostProcessor extends RepositoryRegistrationAotPr
private final LazyLoadingProxyAotProcessor lazyLoadingProxyAotProcessor = new LazyLoadingProxyAotProcessor();
@Override
protected @Nullable MongoRepositoryContributor contribute(AotRepositoryContext repositoryContext,
protected void configureTypeContributions(AotRepositoryContext repositoryContext,
GenerationContext generationContext) {
// do some custom type registration here
super.contribute(repositoryContext, generationContext);
super.configureTypeContributions(repositoryContext, generationContext);
repositoryContext.getResolvedTypes().stream().filter(MongoAotPredicates.IS_SIMPLE_TYPE.negate()).forEach(type -> {
TypeContributor.contribute(type, it -> true, generationContext);
lazyLoadingProxyAotProcessor.registerLazyLoadingProxyIfNeeded(type, generationContext);
});
if (!repositoryContext.isGeneratedRepositoriesEnabled(MODULE_NAME)) {
return null;
}
return new MongoRepositoryContributor(repositoryContext);
}
@Override
protected void contributeType(Class<?> type, GenerationContext generationContext) {
protected @Nullable MongoRepositoryContributor contributeAotRepository(AotRepositoryContext repositoryContext) {
if (TypeUtils.type(type).isPartOf("org.springframework.data.mongodb", "com.mongodb")) {
return;
if (!repositoryContext.isGeneratedRepositoriesEnabled(MODULE_NAME)) {
return null;
}
super.contributeType(type, generationContext);
return new MongoRepositoryContributor(repositoryContext);
}
}

3
spring-data-mongodb/src/main/resources/META-INF/spring/aot.factories

@ -4,3 +4,6 @@ org.springframework.aot.hint.RuntimeHintsRegistrar=\ @@ -4,3 +4,6 @@ org.springframework.aot.hint.RuntimeHintsRegistrar=\
org.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\
org.springframework.data.mongodb.aot.MongoManagedTypesBeanRegistrationAotProcessor
org.springframework.data.util.TypeCollector$TypeCollectorFilters=\
org.springframework.data.mongodb.aot.MongoTypeFilters

5
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/AotFragmentTestConfigurationSupport.java

@ -54,7 +54,6 @@ public class AotFragmentTestConfigurationSupport implements BeanFactoryPostProce @@ -54,7 +54,6 @@ public class AotFragmentTestConfigurationSupport implements BeanFactoryPostProce
private final Class<?> repositoryInterface;
private final boolean registerFragmentFacade;
private final TestMongoAotRepositoryContext repositoryContext;
public AotFragmentTestConfigurationSupport(Class<?> repositoryInterface) {
this(repositoryInterface, true);
@ -64,15 +63,15 @@ public class AotFragmentTestConfigurationSupport implements BeanFactoryPostProce @@ -64,15 +63,15 @@ public class AotFragmentTestConfigurationSupport implements BeanFactoryPostProce
this.repositoryInterface = repositoryInterface;
this.registerFragmentFacade = registerFragmentFacade;
this.repositoryContext = new TestMongoAotRepositoryContext(repositoryInterface, null);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
TestMongoAotRepositoryContext repositoryContext = new TestMongoAotRepositoryContext(beanFactory,
repositoryInterface, null);
TestGenerationContext generationContext = new TestGenerationContext(repositoryInterface);
repositoryContext.setBeanFactory(beanFactory);
new MongoRepositoryContributor(repositoryContext).contribute(generationContext);
generationContext.writeGeneratedContent();

81
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/AotMongoRepositoryPostProcessorUnitTests.java

@ -19,14 +19,11 @@ import static org.assertj.core.api.Assertions.*; @@ -19,14 +19,11 @@ import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import org.jmolecules.ddd.annotation.Entity;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.junitpioneer.jupiter.ClearSystemProperty;
import org.junitpioneer.jupiter.SetSystemProperty;
@ -36,18 +33,14 @@ import org.springframework.aot.generate.ClassNameGenerator; @@ -36,18 +33,14 @@ import org.springframework.aot.generate.ClassNameGenerator;
import org.springframework.aot.generate.DefaultGenerationContext;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.generate.InMemoryGeneratedFiles;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.data.annotation.Id;
import org.springframework.data.aot.AotContext;
import org.springframework.data.aot.AotTypeConfiguration;
import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.config.AotRepositoryContext;
import org.springframework.data.repository.config.AotRepositoryContextSupport;
import org.springframework.data.repository.config.AotRepositoryInformation;
import org.springframework.data.repository.config.RepositoryConfigurationSource;
import org.springframework.data.repository.core.RepositoryInformation;
@ -65,10 +58,10 @@ class AotMongoRepositoryPostProcessorUnitTests { @@ -65,10 +58,10 @@ class AotMongoRepositoryPostProcessorUnitTests {
@SetSystemProperty(key = AotDetector.AOT_ENABLED, value = "true")
void repositoryProcessorShouldEnableAotRepositoriesByDefaultWhenAotIsEnabled() {
GenerationContext ctx = createGenerationContext();
GenericApplicationContext context = new GenericApplicationContext();
context.refresh();
MongoRepositoryContributor contributor = createContributorWithPersonTypes(context, ctx);
MongoRepositoryContributor contributor = createContributorWithPersonTypes(context);
assertThat(contributor).isNotNull();
}
@ -77,10 +70,10 @@ class AotMongoRepositoryPostProcessorUnitTests { @@ -77,10 +70,10 @@ class AotMongoRepositoryPostProcessorUnitTests {
@ClearSystemProperty(key = AotContext.GENERATED_REPOSITORIES_ENABLED)
void shouldEnableAotRepositoriesByDefault() {
GenerationContext ctx = createGenerationContext();
GenericApplicationContext context = new GenericApplicationContext();
context.refresh();
MongoRepositoryContributor contributor = createContributorWithPersonTypes(context, ctx);
MongoRepositoryContributor contributor = createContributorWithPersonTypes(context);
assertThat(contributor).isNotNull();
}
@ -89,10 +82,10 @@ class AotMongoRepositoryPostProcessorUnitTests { @@ -89,10 +82,10 @@ class AotMongoRepositoryPostProcessorUnitTests {
@SetSystemProperty(key = AotContext.GENERATED_REPOSITORIES_ENABLED, value = "false")
void shouldDisableAotRepositoriesWhenGeneratedRepositoriesIsFalse() {
GenerationContext ctx = createGenerationContext();
GenericApplicationContext context = new GenericApplicationContext();
context.refresh();
MongoRepositoryContributor contributor = createContributorWithPersonTypes(context, ctx);
MongoRepositoryContributor contributor = createContributorWithPersonTypes(context);
assertThat(contributor).isNull();
}
@ -101,10 +94,10 @@ class AotMongoRepositoryPostProcessorUnitTests { @@ -101,10 +94,10 @@ class AotMongoRepositoryPostProcessorUnitTests {
@SetSystemProperty(key = "spring.aot.mongodb.repositories.enabled", value = "false")
void shouldDisableAotRepositoriesWhenJpaGeneratedRepositoriesIsFalse() {
GenerationContext ctx = createGenerationContext();
GenericApplicationContext context = new GenericApplicationContext();
context.refresh();
MongoRepositoryContributor contributor = createContributorWithPersonTypes(context, ctx);
MongoRepositoryContributor contributor = createContributorWithPersonTypes(context);
assertThat(contributor).isNull();
}
@ -113,15 +106,14 @@ class AotMongoRepositoryPostProcessorUnitTests { @@ -113,15 +106,14 @@ class AotMongoRepositoryPostProcessorUnitTests {
return new DefaultGenerationContext(new ClassNameGenerator(ClassName.OBJECT), new InMemoryGeneratedFiles());
}
private MongoRepositoryContributor createContributorWithPersonTypes(GenericApplicationContext context,
GenerationContext ctx) {
private MongoRepositoryContributor createContributorWithPersonTypes(GenericApplicationContext context) {
return new AotMongoRepositoryPostProcessor().contribute(new DummyAotRepositoryContext(context) {
return new AotMongoRepositoryPostProcessor().contributeAotRepository(new DummyAotRepositoryContext(context) {
@Override
public Set<Class<?>> getResolvedTypes() {
return Collections.singleton(Person.class);
}
}, ctx);
});
}
@Entity
@ -131,22 +123,15 @@ class AotMongoRepositoryPostProcessorUnitTests { @@ -131,22 +123,15 @@ class AotMongoRepositoryPostProcessorUnitTests {
interface PersonRepository extends Repository<Person, Long> {}
static class DummyAotRepositoryContext implements AotRepositoryContext {
static class DummyAotRepositoryContext extends AotRepositoryContextSupport {
private final @Nullable AbstractApplicationContext applicationContext;
DummyAotRepositoryContext(@Nullable AbstractApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public String getBeanName() {
return "jpaRepository";
DummyAotRepositoryContext(AbstractApplicationContext applicationContext) {
super(AotContext.from(applicationContext, applicationContext.getEnvironment()));
}
@Override
public String getModuleName() {
return "JPA";
return "MongoDB";
}
@Override
@ -180,40 +165,6 @@ class AotMongoRepositoryPostProcessorUnitTests { @@ -180,40 +165,6 @@ class AotMongoRepositoryPostProcessorUnitTests {
return Set.of();
}
@Override
public Set<Class<?>> getUserDomainTypes() {
return Set.of();
}
@Override
public ConfigurableListableBeanFactory getBeanFactory() {
return applicationContext != null ? applicationContext.getBeanFactory() : null;
}
@Override
public Environment getEnvironment() {
return applicationContext == null ? new StandardEnvironment() : applicationContext.getEnvironment();
}
@Override
public TypeIntrospector introspectType(String typeName) {
return null;
}
@Override
public IntrospectedBeanDefinition introspectBeanDefinition(String beanName) {
return null;
}
@Override
public void typeConfiguration(Class<?> type, Consumer<AotTypeConfiguration> configurationConsumer) {
}
@Override
public Collection<AotTypeConfiguration> typeConfigurations() {
return List.of();
}
}
}

4
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/QueryMethodContributionUnitTests.java

@ -29,6 +29,7 @@ import java.util.regex.Pattern; @@ -29,6 +29,7 @@ import java.util.regex.Pattern;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.data.domain.Limit;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Range;
@ -391,7 +392,8 @@ class QueryMethodContributionUnitTests { @@ -391,7 +392,8 @@ class QueryMethodContributionUnitTests {
Method method = repository.getMethod(methodName, args);
TestMongoAotRepositoryContext repoContext = new TestMongoAotRepositoryContext(repository, null);
TestMongoAotRepositoryContext repoContext = new TestMongoAotRepositoryContext(new DefaultListableBeanFactory(),
repository, null);
MongoRepositoryContributor contributor = new MongoRepositoryContributor(repoContext);
MethodContributor<? extends QueryMethod> methodContributor = contributor.contributeQueryMethod(method);

81
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/TestMongoAotRepositoryContext.java

@ -15,26 +15,19 @@ @@ -15,26 +15,19 @@
*/
package org.springframework.data.mongodb.repository.aot;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.test.tools.ClassFile;
import org.springframework.data.aot.AotTypeConfiguration;
import org.springframework.data.aot.AotContext;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.repository.support.MongoRepositoryFragmentsContributor;
import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;
import org.springframework.data.repository.config.AotRepositoryContext;
import org.springframework.data.repository.config.AotRepositoryContextSupport;
import org.springframework.data.repository.config.AotRepositoryInformation;
import org.springframework.data.repository.config.RepositoryConfigurationSource;
import org.springframework.data.repository.core.RepositoryInformation;
@ -45,14 +38,14 @@ import org.springframework.data.repository.core.support.RepositoryComposition; @@ -45,14 +38,14 @@ import org.springframework.data.repository.core.support.RepositoryComposition;
/**
* @author Christoph Strobl
*/
public class TestMongoAotRepositoryContext implements AotRepositoryContext {
public class TestMongoAotRepositoryContext extends AotRepositoryContextSupport {
private final AotRepositoryInformation repositoryInformation;
private final Environment environment = new StandardEnvironment();
private final Class<?> repositoryInterface;
private @Nullable ConfigurableListableBeanFactory beanFactory;
public TestMongoAotRepositoryContext(Class<?> repositoryInterface, @Nullable RepositoryComposition composition) {
public TestMongoAotRepositoryContext(BeanFactory beanFactory, Class<?> repositoryInterface,
@Nullable RepositoryComposition composition) {
super(AotContext.from(beanFactory, new StandardEnvironment()));
this.repositoryInterface = repositoryInterface;
@ -65,36 +58,6 @@ public class TestMongoAotRepositoryContext implements AotRepositoryContext { @@ -65,36 +58,6 @@ public class TestMongoAotRepositoryContext implements AotRepositoryContext {
fragments.stream().toList());
}
@Override
public ConfigurableListableBeanFactory getBeanFactory() {
return beanFactory;
}
@Override
public TypeIntrospector introspectType(String typeName) {
return null;
}
@Override
public IntrospectedBeanDefinition introspectBeanDefinition(String beanName) {
return null;
}
@Override
public void typeConfiguration(Class<?> type, Consumer<AotTypeConfiguration> configurationConsumer) {
}
@Override
public Collection<AotTypeConfiguration> typeConfigurations() {
return List.of();
}
@Override
public String getBeanName() {
return "dummyRepository";
}
@Override
public String getModuleName() {
return "MongoDB";
@ -130,34 +93,4 @@ public class TestMongoAotRepositoryContext implements AotRepositoryContext { @@ -130,34 +93,4 @@ public class TestMongoAotRepositoryContext implements AotRepositoryContext {
return Set.of();
}
@Override
public Set<Class<?>> getUserDomainTypes() {
return Set.of();
}
public List<ClassFile> getRequiredContextFiles() {
return List.of(classFileForType(repositoryInformation.getRepositoryBaseClass()));
}
static ClassFile classFileForType(Class<?> type) {
String name = type.getName();
ClassPathResource cpr = new ClassPathResource(name.replaceAll("\\.", "/") + ".class");
try {
return ClassFile.of(name, cpr.getContentAsByteArray());
} catch (IOException e) {
throw new IllegalArgumentException("Cannot open [%s].".formatted(cpr.getPath()));
}
}
@Override
public Environment getEnvironment() {
return environment;
}
public void setBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
}

Loading…
Cancel
Save