Browse Source

Polishing.

Consistent ConfigurationSource usage across tests to avoid nullability.

See #5107
Original pull request: #5108
pull/4831/merge
Mark Paluch 1 week ago
parent
commit
942cca616e
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 22
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryContributor.java
  2. 63
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/AotFragmentTestConfigurationSupport.java
  3. 24
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryContributorUnitTests.java
  4. 8
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryMetadataTests.java
  5. 18
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/TestMongoAotRepositoryContext.java

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

@ -68,11 +68,11 @@ public class MongoRepositoryContributor extends RepositoryContributor {
private static final Log logger = LogFactory.getLog(MongoRepositoryContributor.class); private static final Log logger = LogFactory.getLog(MongoRepositoryContributor.class);
private final AotRepositoryContext repositoryContext;
private final AotQueryCreator queryCreator; private final AotQueryCreator queryCreator;
private final SimpleTypeHolder simpleTypeHolder; private final SimpleTypeHolder simpleTypeHolder;
private final MongoMappingContext mappingContext; private final MongoMappingContext mappingContext;
private final NamedQueries namedQueries; private final NamedQueries namedQueries;
private final @Nullable String mongoOperationsRef;
public MongoRepositoryContributor(AotRepositoryContext repositoryContext) { public MongoRepositoryContributor(AotRepositoryContext repositoryContext) {
@ -83,8 +83,8 @@ public class MongoRepositoryContributor extends RepositoryContributor {
classLoader = getClass().getClassLoader(); classLoader = getClass().getClassLoader();
} }
this.repositoryContext = repositoryContext;
this.namedQueries = getNamedQueries(repositoryContext.getConfigurationSource(), classLoader); this.namedQueries = getNamedQueries(repositoryContext.getConfigurationSource(), classLoader);
this.mongoOperationsRef = getMongoTemplateRef(repositoryContext.getConfigurationSource());
// avoid Java Time (JSR-310) Type introspection // avoid Java Time (JSR-310) Type introspection
MongoCustomConversions mongoCustomConversions = MongoCustomConversions MongoCustomConversions mongoCustomConversions = MongoCustomConversions
@ -100,14 +100,6 @@ public class MongoRepositoryContributor extends RepositoryContributor {
this.queryCreator = new AotQueryCreator(this.mappingContext); this.queryCreator = new AotQueryCreator(this.mappingContext);
} }
private @Nullable String getMongoTemplateRef(@Nullable RepositoryConfigurationSource configSource) {
if (configSource == null) {
return null;
}
return configSource.getAttribute("mongoTemplateRef").filter(it -> !"mongoTemplate".equals(it)).orElse(null);
}
@SuppressWarnings("NullAway") @SuppressWarnings("NullAway")
private NamedQueries getNamedQueries(@Nullable RepositoryConfigurationSource configSource, ClassLoader classLoader) { private NamedQueries getNamedQueries(@Nullable RepositoryConfigurationSource configSource, ClassLoader classLoader) {
@ -145,9 +137,10 @@ public class MongoRepositoryContributor extends RepositoryContributor {
constructorBuilder.addParameter("operations", MongoOperations.class, customizer -> { constructorBuilder.addParameter("operations", MongoOperations.class, customizer -> {
String mongoOperationsRef = getMongoTemplateRef();
customizer.bindToField() customizer.bindToField()
.origin(StringUtils.hasText(this.mongoOperationsRef) .origin(StringUtils.hasText(mongoOperationsRef)
? new RuntimeBeanReference(this.mongoOperationsRef, MongoOperations.class) ? new RuntimeBeanReference(mongoOperationsRef, MongoOperations.class)
: new RuntimeBeanReference(MongoOperations.class)); : new RuntimeBeanReference(MongoOperations.class));
}); });
@ -158,6 +151,11 @@ public class MongoRepositoryContributor extends RepositoryContributor {
}); });
} }
private @Nullable String getMongoTemplateRef() {
return repositoryContext.getConfigurationSource().getAttribute("mongoTemplateRef")
.filter(it -> !"mongoTemplate".equals(it)).orElse(null);
}
@Override @Override
@SuppressWarnings("NullAway") @SuppressWarnings("NullAway")
protected @Nullable MethodContributor<? extends QueryMethod> contributeQueryMethod(Method method) { protected @Nullable MethodContributor<? extends QueryMethod> contributeQueryMethod(Method method) {

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

@ -18,6 +18,8 @@ package org.springframework.data.mongodb.repository.aot;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import org.mockito.Mockito;
import org.springframework.aot.test.generate.TestGenerationContext; import org.springframework.aot.test.generate.TestGenerationContext;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
@ -27,12 +29,26 @@ import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.env.StandardEnvironment; import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.test.tools.TestCompiler; import org.springframework.core.test.tools.TestCompiler;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.expression.ValueExpressionParser; import org.springframework.data.expression.ValueExpressionParser;
import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
import org.springframework.data.repository.config.RepositoryConfigurationSource;
import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport; import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
import org.springframework.data.repository.query.QueryMethodValueEvaluationContextAccessor; import org.springframework.data.repository.query.QueryMethodValueEvaluationContextAccessor;
@ -53,23 +69,54 @@ import org.springframework.util.ReflectionUtils;
public class AotFragmentTestConfigurationSupport implements BeanFactoryPostProcessor { public class AotFragmentTestConfigurationSupport implements BeanFactoryPostProcessor {
private final Class<?> repositoryInterface; private final Class<?> repositoryInterface;
private final RepositoryConfigurationSource configSource;
private final boolean registerFragmentFacade; private final boolean registerFragmentFacade;
public AotFragmentTestConfigurationSupport(Class<?> repositoryInterface) { public AotFragmentTestConfigurationSupport(Class<?> repositoryInterface) {
this(repositoryInterface, true); this(repositoryInterface, SampleConfiguration.class, true);
}
public AotFragmentTestConfigurationSupport(Class<?> repositoryInterface, Class<?> configClass) {
this(repositoryInterface, configClass, true);
} }
public AotFragmentTestConfigurationSupport(Class<?> repositoryInterface, boolean registerFragmentFacade) { public AotFragmentTestConfigurationSupport(Class<?> repositoryInterface, boolean registerFragmentFacade) {
this(repositoryInterface, SampleConfiguration.class, registerFragmentFacade);
}
public AotFragmentTestConfigurationSupport(Class<?> repositoryInterface, Class<?> configClass,
boolean registerFragmentFacade) {
this.repositoryInterface = repositoryInterface; this.repositoryInterface = repositoryInterface;
this.registerFragmentFacade = registerFragmentFacade; this.registerFragmentFacade = registerFragmentFacade;
this.configSource = new AnnotationRepositoryConfigurationSource(AnnotationMetadata.introspect(configClass),
EnableMongoRepositories.class, new DefaultResourceLoader(), new StandardEnvironment(),
Mockito.mock(BeanDefinitionRegistry.class), DefaultBeanNameGenerator.INSTANCE);
}
@Bean
MongoCustomConversions customConversions() {
return MongoCustomConversions.create(adapter -> adapter.useSpringDataJavaTimeCodecs());
}
@Bean
MongoMappingContext mongoMappingContext(MongoCustomConversions conversions) {
MongoMappingContext context = new MongoMappingContext();
context.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
return context;
}
@Bean
MongoConverter mongoConverter(MongoMappingContext context, MongoCustomConversions conversions) {
MappingMongoConverter converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, context);
converter.setCustomConversions(conversions);
return converter;
} }
@Override @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
TestMongoAotRepositoryContext repositoryContext = new TestMongoAotRepositoryContext(beanFactory, TestMongoAotRepositoryContext repositoryContext = getRepositoryContext(beanFactory);
repositoryInterface, null);
TestGenerationContext generationContext = new TestGenerationContext(repositoryInterface); TestGenerationContext generationContext = new TestGenerationContext(repositoryInterface);
new MongoRepositoryContributor(repositoryContext).contribute(generationContext); new MongoRepositoryContributor(repositoryContext).contribute(generationContext);
@ -101,6 +148,10 @@ public class AotFragmentTestConfigurationSupport implements BeanFactoryPostProce
beanFactory.registerSingleton("generationContext", generationContext); beanFactory.registerSingleton("generationContext", generationContext);
} }
public TestMongoAotRepositoryContext getRepositoryContext(ConfigurableListableBeanFactory beanFactory) {
return new TestMongoAotRepositoryContext(beanFactory, repositoryInterface, configSource);
}
private Object getFragmentFacadeProxy(Object fragment) { private Object getFragmentFacadeProxy(Object fragment) {
return Proxy.newProxyInstance(repositoryInterface.getClassLoader(), new Class<?>[] { repositoryInterface }, return Proxy.newProxyInstance(repositoryInterface.getClassLoader(), new Class<?>[] { repositoryInterface },
@ -157,4 +208,10 @@ public class AotFragmentTestConfigurationSupport implements BeanFactoryPostProce
} }
} }
@EnableMongoRepositories(considerNestedRepositories = true, includeFilters = {
@ComponentScan.Filter(classes = SampleConfiguration.class, type = FilterType.ASSIGNABLE_TYPE) })
public static class SampleConfiguration {
}
} }

24
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryContributorUnitTests.java

@ -15,8 +15,8 @@
*/ */
package org.springframework.data.mongodb.repository.aot; package org.springframework.data.mongodb.repository.aot;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.*;
import static org.springframework.data.mongodb.test.util.Assertions.assertThat; import static org.springframework.data.mongodb.test.util.Assertions.*;
import example.aot.User; import example.aot.User;
import example.aot.UserRepository; import example.aot.UserRepository;
@ -25,15 +25,20 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.aot.generate.GeneratedFiles; import org.springframework.aot.generate.GeneratedFiles;
import org.springframework.aot.test.generate.TestGenerationContext; import org.springframework.aot.test.generate.TestGenerationContext;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.InputStreamSource; import org.springframework.core.io.InputStreamSource;
import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.repository.Meta; import org.springframework.data.mongodb.repository.Meta;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
@ -47,15 +52,19 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
class MongoRepositoryContributorUnitTests { class MongoRepositoryContributorUnitTests {
@Configuration @Configuration
@EnableMongoRepositories(considerNestedRepositories = true, mongoTemplateRef = "mongoOperations",
includeFilters = { @ComponentScan.Filter(classes = MetaUserRepository.class, type = FilterType.ASSIGNABLE_TYPE) })
static class MongoRepositoryContributorConfiguration extends AotFragmentTestConfigurationSupport { static class MongoRepositoryContributorConfiguration extends AotFragmentTestConfigurationSupport {
public MongoRepositoryContributorConfiguration() { public MongoRepositoryContributorConfiguration() {
super(MetaUserRepository.class); super(MetaUserRepository.class, MongoRepositoryContributorConfiguration.class);
} }
@Bean @Bean
MongoOperations mongoOperations() { MongoOperations mongoOperations(MongoConverter mongoConverter) {
return mock(MongoOperations.class); MongoOperations operations = mock(MongoOperations.class);
when(operations.getConverter()).thenReturn(mongoConverter);
return operations;
} }
} }
@ -66,7 +75,8 @@ class MongoRepositoryContributorUnitTests {
void shouldConsiderMetaAnnotation() throws IOException { void shouldConsiderMetaAnnotation() throws IOException {
InputStreamSource aotFragment = generationContext.getGeneratedFiles().getGeneratedFile(GeneratedFiles.Kind.SOURCE, InputStreamSource aotFragment = generationContext.getGeneratedFiles().getGeneratedFile(GeneratedFiles.Kind.SOURCE,
MetaUserRepository.class.getPackageName().replace('.', '/') + "/MetaUserRepositoryImpl__AotRepository.java"); AotFragmentTestConfigurationSupport.getAotImplFragmentName(MetaUserRepository.class).replace('.', '/')
+ ".java");
String content = new InputStreamResource(aotFragment).getContentAsString(StandardCharsets.UTF_8); String content = new InputStreamResource(aotFragment).getContentAsString(StandardCharsets.UTF_8);
@ -76,7 +86,7 @@ class MongoRepositoryContributorUnitTests {
assertThat(content).contains("filterQuery.diskUse(DiskUse.DENY)"); assertThat(content).contains("filterQuery.diskUse(DiskUse.DENY)");
} }
interface MetaUserRepository extends CrudRepository<User, String> { public interface MetaUserRepository extends CrudRepository<User, String> {
@Meta @Meta
User findAllByLastname(String lastname); User findAllByLastname(String lastname);

8
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryMetadataTests.java

@ -34,6 +34,7 @@ import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource; import org.springframework.core.io.UrlResource;
import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
/** /**
@ -41,7 +42,6 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
* *
* @author Mark Paluch * @author Mark Paluch
*/ */
@SpringJUnitConfig(classes = MongoRepositoryMetadataTests.MongoRepositoryContributorConfiguration.class) @SpringJUnitConfig(classes = MongoRepositoryMetadataTests.MongoRepositoryContributorConfiguration.class)
class MongoRepositoryMetadataTests { class MongoRepositoryMetadataTests {
@ -53,8 +53,10 @@ class MongoRepositoryMetadataTests {
} }
@Bean @Bean
MongoOperations mongoOperations() { MongoOperations mongoOperations(MongoConverter mongoConverter) {
return mock(MongoOperations.class); MongoOperations operations = mock(MongoOperations.class);
when(operations.getConverter()).thenReturn(mongoConverter);
return operations;
} }
} }

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

@ -18,8 +18,6 @@ package org.springframework.data.mongodb.repository.aot;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.Set; import java.util.Set;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.env.StandardEnvironment; import org.springframework.core.env.StandardEnvironment;
@ -41,21 +39,20 @@ import org.springframework.data.repository.core.support.RepositoryComposition;
public class TestMongoAotRepositoryContext extends AotRepositoryContextSupport { public class TestMongoAotRepositoryContext extends AotRepositoryContextSupport {
private final AotRepositoryInformation repositoryInformation; private final AotRepositoryInformation repositoryInformation;
private final Class<?> repositoryInterface; private final RepositoryConfigurationSource configurationSource;
public TestMongoAotRepositoryContext(BeanFactory beanFactory, Class<?> repositoryInterface, public TestMongoAotRepositoryContext(BeanFactory beanFactory, Class<?> repositoryInterface,
@Nullable RepositoryComposition composition) { RepositoryConfigurationSource configurationSource) {
super(AotContext.from(beanFactory, new StandardEnvironment()));
this.repositoryInterface = repositoryInterface; super(AotContext.from(beanFactory, new StandardEnvironment()));
RepositoryMetadata metadata = AnnotationRepositoryMetadata.getMetadata(repositoryInterface); RepositoryMetadata metadata = AnnotationRepositoryMetadata.getMetadata(repositoryInterface);
RepositoryComposition.RepositoryFragments fragments = MongoRepositoryFragmentsContributor.DEFAULT RepositoryComposition.RepositoryFragments fragments = MongoRepositoryFragmentsContributor.DEFAULT
.describe(metadata); .describe(metadata);
this.repositoryInformation = new AotRepositoryInformation(metadata, SimpleMongoRepository.class, this.repositoryInformation = new AotRepositoryInformation(metadata, SimpleMongoRepository.class,
fragments.stream().toList()); fragments.stream().toList());
this.configurationSource = configurationSource;
} }
@Override @Override
@ -65,12 +62,7 @@ public class TestMongoAotRepositoryContext extends AotRepositoryContextSupport {
@Override @Override
public RepositoryConfigurationSource getConfigurationSource() { public RepositoryConfigurationSource getConfigurationSource() {
return null; return configurationSource;
}
@Override
public Set<String> getBasePackages() {
return Set.of(repositoryInterface.getPackageName());
} }
@Override @Override

Loading…
Cancel
Save