Add AOT repository support
We now use the AOT infrastructure of Spring Framework 6 and data commons to provide AOT support building the foundation for native image compilation. Additionally we register hints for GraalVM native image. See: #4022 Original Pull Request: #4093
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.mongodb;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.data.domain.ManagedTypes;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 4.0
|
||||
*/
|
||||
public final class MongoManagedTypes implements ManagedTypes {
|
||||
|
||||
private final ManagedTypes delegate;
|
||||
|
||||
public MongoManagedTypes(ManagedTypes types) {
|
||||
this.delegate = types;
|
||||
}
|
||||
|
||||
public static MongoManagedTypes from(ManagedTypes managedTypes) {
|
||||
return new MongoManagedTypes(managedTypes);
|
||||
}
|
||||
|
||||
public static MongoManagedTypes of(Iterable<? extends Class<?>> types) {
|
||||
return from(ManagedTypes.fromIterable(types));
|
||||
}
|
||||
|
||||
public static MongoManagedTypes none() {
|
||||
return from(ManagedTypes.empty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<Class<?>> action) {
|
||||
delegate.forEach(action);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.mongodb.aot;
|
||||
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.data.aot.AotRepositoryContext;
|
||||
import org.springframework.data.aot.RepositoryRegistrationAotProcessor;
|
||||
import org.springframework.data.aot.TypeContributor;
|
||||
import org.springframework.data.aot.TypeUtils;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class AotMongoRepositoryPostProcessor extends RepositoryRegistrationAotProcessor {
|
||||
|
||||
private LazyLoadingProxyAotProcessor lazyLoadingProxyAotProcessor = new LazyLoadingProxyAotProcessor();
|
||||
|
||||
@Override
|
||||
protected void contribute(AotRepositoryContext repositoryContext, GenerationContext generationContext) {
|
||||
// do some custom type registration here
|
||||
super.contribute(repositoryContext, generationContext);
|
||||
|
||||
repositoryContext.getResolvedTypes().stream().filter(MongoAotPredicates.IS_SIMPLE_TYPE.negate()).forEach(type -> {
|
||||
TypeContributor.contribute(type, it -> true, generationContext);
|
||||
lazyLoadingProxyAotProcessor.registerLazyLoadingProxyIfNeeded(type, generationContext);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.mongodb.aot;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
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.data.mongodb.core.mapping.event.AfterConvertCallback;
|
||||
import org.springframework.data.mongodb.core.mapping.event.AfterSaveCallback;
|
||||
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertCallback;
|
||||
import org.springframework.data.mongodb.core.mapping.event.BeforeSaveCallback;
|
||||
import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 4.0
|
||||
*/
|
||||
public class DataMongoRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
|
||||
hints.reflection().registerTypes(
|
||||
Arrays.asList(TypeReference.of(SimpleMongoRepository.class), TypeReference.of(BeforeConvertCallback.class),
|
||||
TypeReference.of(BeforeSaveCallback.class), TypeReference.of(AfterConvertCallback.class),
|
||||
TypeReference.of(AfterSaveCallback.class)),
|
||||
builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
|
||||
MemberCategory.INVOKE_PUBLIC_METHODS));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.mongodb.aot;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.aot.TypeUtils;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
import org.springframework.data.mongodb.core.mapping.DocumentReference;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 4.0
|
||||
*/
|
||||
public class LazyLoadingProxyAotProcessor {
|
||||
|
||||
private boolean generalLazyLoadingProxyContributed = false;
|
||||
|
||||
void registerLazyLoadingProxyIfNeeded(Class<?> type, GenerationContext generationContext) {
|
||||
|
||||
Set<Field> refFields = getFieldsWithAnnotationPresent(type, Reference.class);
|
||||
if (refFields.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
refFields.stream() //
|
||||
.filter(LazyLoadingProxyAotProcessor::isLazyLoading) //
|
||||
.forEach(field -> {
|
||||
|
||||
if (!generalLazyLoadingProxyContributed) {
|
||||
generationContext.getRuntimeHints().proxies().registerJdkProxy(
|
||||
TypeReference.of(org.springframework.data.mongodb.core.convert.LazyLoadingProxy.class),
|
||||
TypeReference.of(org.springframework.aop.SpringProxy.class),
|
||||
TypeReference.of(org.springframework.aop.framework.Advised.class),
|
||||
TypeReference.of(org.springframework.core.DecoratingProxy.class));
|
||||
generalLazyLoadingProxyContributed = true;
|
||||
}
|
||||
|
||||
if (field.getType().isInterface()) {
|
||||
|
||||
List<Class<?>> interfaces = new ArrayList<>(
|
||||
TypeUtils.resolveTypesInSignature(ResolvableType.forField(field, type)));
|
||||
|
||||
interfaces.add(0, org.springframework.data.mongodb.core.convert.LazyLoadingProxy.class);
|
||||
interfaces.add(org.springframework.aop.SpringProxy.class);
|
||||
interfaces.add(org.springframework.aop.framework.Advised.class);
|
||||
interfaces.add(org.springframework.core.DecoratingProxy.class);
|
||||
|
||||
generationContext.getRuntimeHints().proxies().registerJdkProxy(interfaces.toArray(Class[]::new));
|
||||
} else {
|
||||
|
||||
generationContext.getRuntimeHints().proxies().registerClassProxy(field.getType(), builder -> {
|
||||
builder.proxiedInterfaces(org.springframework.data.mongodb.core.convert.LazyLoadingProxy.class);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isLazyLoading(Field field) {
|
||||
if (AnnotatedElementUtils.isAnnotated(field, DBRef.class)) {
|
||||
return AnnotatedElementUtils.findMergedAnnotation(field, DBRef.class).lazy();
|
||||
}
|
||||
if (AnnotatedElementUtils.isAnnotated(field, DocumentReference.class)) {
|
||||
return AnnotatedElementUtils.findMergedAnnotation(field, DocumentReference.class).lazy();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Set<Field> getFieldsWithAnnotationPresent(Class<?> type, Class<? extends Annotation> annotation) {
|
||||
|
||||
Set<Field> fields = new LinkedHashSet<>();
|
||||
for (Field field : type.getDeclaredFields()) {
|
||||
if (MergedAnnotations.from(field).get(annotation).isPresent()) {
|
||||
fields.add(field);
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.mongodb.aot;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.data.aot.TypeUtils;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 4.0
|
||||
*/
|
||||
class MongoAotPredicates {
|
||||
|
||||
static final Predicate<Class<?>> IS_SIMPLE_TYPE = (type) -> MongoSimpleTypes.HOLDER.isSimpleType(type) || TypeUtils.type(type).isPartOf("org.bson");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.mongodb.aot;
|
||||
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.data.aot.ManagedTypesBeanRegistrationAotProcessor;
|
||||
import org.springframework.data.mongodb.MongoManagedTypes;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2022/06
|
||||
*/
|
||||
public class MongoManagedTypesBeanRegistrationAotProcessor extends ManagedTypesBeanRegistrationAotProcessor {
|
||||
|
||||
private LazyLoadingProxyAotProcessor lazyLoadingProxyAotProcessor = new LazyLoadingProxyAotProcessor();
|
||||
|
||||
public MongoManagedTypesBeanRegistrationAotProcessor() {
|
||||
setModuleIdentifier("mongo");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isMatch(@Nullable Class<?> beanType, @Nullable String beanName) {
|
||||
return isMongoManagedTypes(beanType) || super.isMatch(beanType, beanName);
|
||||
}
|
||||
|
||||
protected boolean isMongoManagedTypes(@Nullable Class<?> beanType) {
|
||||
return beanType != null && ClassUtils.isAssignable(MongoManagedTypes.class, beanType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void contributeType(ResolvableType type, GenerationContext generationContext) {
|
||||
|
||||
if (MongoAotPredicates.IS_SIMPLE_TYPE.test(type.toClass())) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.contributeType(type, generationContext);
|
||||
lazyLoadingProxyAotProcessor.registerLazyLoadingProxyIfNeeded(type.toClass(), generationContext);
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,8 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
import org.springframework.data.aot.hint.AuditingHints;
|
||||
import org.springframework.data.auditing.DateTimeProvider;
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
|
||||
@@ -37,6 +39,7 @@ import org.springframework.data.domain.AuditorAware;
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Import(MongoAuditingRegistrar.class)
|
||||
@ImportRuntimeHints(AuditingHints.AuditingRuntimeHints.class)
|
||||
public @interface EnableMongoAuditing {
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,18 +18,18 @@ package org.springframework.data.mongodb.config;
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
|
||||
import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport;
|
||||
import org.springframework.data.auditing.config.AuditingConfiguration;
|
||||
import org.springframework.data.config.ParsingUtils;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.mongodb.core.mapping.event.AuditingEntityCallback;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -40,7 +40,7 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
||||
class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport implements Ordered {
|
||||
|
||||
@Override
|
||||
protected Class<? extends Annotation> getAnnotation() {
|
||||
@@ -52,12 +52,34 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
||||
return "mongoAuditingHandler";
|
||||
}
|
||||
|
||||
String persistentEntitiesBeanName;
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
|
||||
|
||||
Assert.notNull(annotationMetadata, "AnnotationMetadata must not be null");
|
||||
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
|
||||
|
||||
if(persistentEntitiesBeanName == null) {
|
||||
if (registry instanceof DefaultListableBeanFactory beanFactory) {
|
||||
for (String bn : beanFactory.getBeanNamesForType(PersistentEntities.class)) {
|
||||
if (bn.startsWith("mongo")) {
|
||||
persistentEntitiesBeanName = bn;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(persistentEntitiesBeanName == null) {
|
||||
|
||||
persistentEntitiesBeanName = BeanDefinitionReaderUtils.uniqueBeanName("mongo.persistent-entities", registry);
|
||||
|
||||
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(PersistentEntities.class)
|
||||
.setFactoryMethod("of")
|
||||
//.addConstructorArgValue(new RuntimeBeanReference(MongoMappingContext.class))
|
||||
.addConstructorArgReference("mongoMappingContext");
|
||||
registry.registerBeanDefinition(persistentEntitiesBeanName, definition.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
super.registerBeanDefinitions(annotationMetadata, registry);
|
||||
}
|
||||
|
||||
@@ -67,11 +89,7 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
||||
Assert.notNull(configuration, "AuditingConfiguration must not be null");
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class);
|
||||
|
||||
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(org.springframework.data.repository.config.PersistentEntitiesFactoryBean.class);
|
||||
definition.addConstructorArgValue(new RuntimeBeanReference(MappingContext.class));
|
||||
|
||||
builder.addConstructorArgValue(definition.getBeanDefinition());
|
||||
builder.addConstructorArgReference(persistentEntitiesBeanName);
|
||||
return configureDefaultAuditHandlerAttributes(configuration, builder);
|
||||
}
|
||||
|
||||
@@ -91,4 +109,9 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
||||
AuditingEntityCallback.class.getName(), registry);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,11 @@ import org.springframework.context.annotation.ClassPathScanningCandidateComponen
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.data.convert.CustomConversions;
|
||||
import org.springframework.data.domain.ManagedTypes;
|
||||
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.FieldNamingStrategy;
|
||||
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
|
||||
import org.springframework.data.mongodb.MongoManagedTypes;
|
||||
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
|
||||
import org.springframework.data.mongodb.core.convert.MongoCustomConversions.MongoConverterConfigurationAdapter;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
@@ -79,11 +81,11 @@ public abstract class MongoConfigurationSupport {
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
@Bean
|
||||
public MongoMappingContext mongoMappingContext(MongoCustomConversions customConversions)
|
||||
public MongoMappingContext mongoMappingContext(MongoCustomConversions customConversions, ManagedTypes managedTypes)
|
||||
throws ClassNotFoundException {
|
||||
|
||||
MongoMappingContext mappingContext = new MongoMappingContext();
|
||||
mappingContext.setInitialEntitySet(getInitialEntitySet());
|
||||
mappingContext.setManagedTypes(managedTypes);
|
||||
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
|
||||
mappingContext.setFieldNamingStrategy(fieldNamingStrategy());
|
||||
mappingContext.setAutoIndexCreation(autoIndexCreation());
|
||||
@@ -91,6 +93,16 @@ public abstract class MongoConfigurationSupport {
|
||||
return mappingContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return new instance of {@link MongoManagedTypes}.
|
||||
* @throws ClassNotFoundException
|
||||
* @since 4.0
|
||||
*/
|
||||
@Bean
|
||||
public MongoManagedTypes managedTypes() throws ClassNotFoundException {
|
||||
return MongoManagedTypes.of(getInitialEntitySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register custom {@link Converter}s in a {@link CustomConversions} object if required. These
|
||||
* {@link CustomConversions} will be registered with the
|
||||
|
||||
@@ -27,12 +27,12 @@ import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.Enhancer;
|
||||
import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.core.NativeDetector;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.mongodb.ClientSessionException;
|
||||
@@ -71,6 +71,16 @@ class LazyLoadingProxyFactory {
|
||||
|
||||
if (!propertyType.isInterface()) {
|
||||
|
||||
if (NativeDetector.inNativeImage()) {
|
||||
|
||||
ProxyFactory factory = new ProxyFactory();
|
||||
factory.addAdvice(interceptor);
|
||||
factory.addInterface(LazyLoadingProxy.class);
|
||||
factory.setTargetClass(propertyType);
|
||||
factory.setProxyTargetClass(true);
|
||||
return factory.getProxy(propertyType.getClassLoader());
|
||||
}
|
||||
|
||||
Factory factory = (Factory) objenesis.newInstance(getEnhancedTypeFor(propertyType));
|
||||
factory.setCallbacks(new Callback[] { interceptor });
|
||||
|
||||
|
||||
@@ -75,6 +75,15 @@ public abstract class MongoSimpleTypes {
|
||||
simpleTypes.add(UUID.class);
|
||||
simpleTypes.add(Instant.class);
|
||||
|
||||
simpleTypes.add(BsonValue.class);
|
||||
simpleTypes.add(BsonNumber.class);
|
||||
simpleTypes.add(BsonType.class);
|
||||
simpleTypes.add(BsonArray.class);
|
||||
simpleTypes.add(BsonSymbol.class);
|
||||
simpleTypes.add(BsonUndefined.class);
|
||||
simpleTypes.add(BsonMinKey.class);
|
||||
simpleTypes.add(BsonMaxKey.class);
|
||||
simpleTypes.add(BsonNull.class);
|
||||
simpleTypes.add(BsonBinary.class);
|
||||
simpleTypes.add(BsonBoolean.class);
|
||||
simpleTypes.add(BsonDateTime.class);
|
||||
|
||||
@@ -19,9 +19,11 @@ import java.lang.annotation.Annotation;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.data.config.ParsingUtils;
|
||||
import org.springframework.data.mongodb.aot.AotMongoRepositoryPostProcessor;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean;
|
||||
@@ -29,6 +31,7 @@ import org.springframework.data.repository.config.AnnotationRepositoryConfigurat
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
|
||||
import org.springframework.data.repository.config.XmlRepositoryConfigurationSource;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
@@ -48,7 +51,7 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getModulePrefix() {
|
||||
public String getModulePrefix() {
|
||||
return "mongo";
|
||||
}
|
||||
|
||||
@@ -62,10 +65,15 @@ public class MongoRepositoryConfigurationExtension extends RepositoryConfigurati
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<Class<? extends Annotation>> getIdentifyingAnnotations() {
|
||||
public Collection<Class<? extends Annotation>> getIdentifyingAnnotations() {
|
||||
return Collections.singleton(Document.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends BeanRegistrationAotProcessor> getRepositoryAotProcessor() {
|
||||
return AotMongoRepositoryPostProcessor.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<Class<?>> getIdentifyingTypes() {
|
||||
return Collections.singleton(MongoRepository.class);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
org.springframework.aot.hint.RuntimeHintsRegistrar=\
|
||||
org.springframework.data.mongodb.aot.DataMongoRuntimeHints
|
||||
org.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\
|
||||
org.springframework.data.mongodb.aot.MongoManagedTypesBeanRegistrationAotProcessor
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.mongodb.aot;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.mongodb.aot.RepositoryRegistrationAotContributionAssert.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.RegisteredBean;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.core.annotation.SynthesizedAnnotation;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.aot.RepositoryRegistrationAotContribution;
|
||||
import org.springframework.data.mongodb.aot.configs.ImperativeConfig;
|
||||
import org.springframework.data.mongodb.core.convert.LazyLoadingProxy;
|
||||
import org.springframework.data.mongodb.core.mapping.Address;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2022/04
|
||||
*/
|
||||
public class AotMongoRepositoryPostProcessorUnitTests {
|
||||
|
||||
@Test
|
||||
void contributesProxiesForDataAnnotations() {
|
||||
|
||||
RepositoryRegistrationAotContribution repositoryBeanContribution = computeConfiguration(ImperativeConfig.class)
|
||||
.forRepository(ImperativeConfig.PersonRepository.class);
|
||||
|
||||
assertThatContribution(repositoryBeanContribution) //
|
||||
.codeContributionSatisfies(contribution -> {
|
||||
|
||||
contribution.contributesJdkProxy(Transient.class, SynthesizedAnnotation.class);
|
||||
contribution.contributesJdkProxy(LastModifiedDate.class, SynthesizedAnnotation.class);
|
||||
contribution.contributesJdkProxy(Document.class, SynthesizedAnnotation.class);
|
||||
contribution.contributesJdkProxy(DBRef.class, SynthesizedAnnotation.class);
|
||||
// TODO: not supported yet contribution.contributesClassProxy(Address.class, LazyLoadingProxy.class);
|
||||
});
|
||||
}
|
||||
|
||||
BeanContributionBuilder computeConfiguration(Class<?> configuration) {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(configuration);
|
||||
ctx.refreshForAotProcessing();
|
||||
|
||||
return it -> {
|
||||
|
||||
String[] repoBeanNames = ctx.getBeanNamesForType(it);
|
||||
assertThat(repoBeanNames).describedAs("Unable to find repository %s in configuration %s.", it, configuration)
|
||||
.hasSize(1);
|
||||
|
||||
String beanName = repoBeanNames[0];
|
||||
|
||||
AotMongoRepositoryPostProcessor postProcessor = ctx.getBean(AotMongoRepositoryPostProcessor.class);
|
||||
|
||||
postProcessor.setBeanFactory(ctx.getDefaultListableBeanFactory());
|
||||
|
||||
BeanRegistrationAotContribution beanRegistrationAotContribution = postProcessor
|
||||
.processAheadOfTime(RegisteredBean.of(ctx.getBeanFactory(), beanName));
|
||||
assertThat(beanRegistrationAotContribution).isInstanceOf(RepositoryRegistrationAotContribution.class);
|
||||
return (RepositoryRegistrationAotContribution) beanRegistrationAotContribution;
|
||||
};
|
||||
}
|
||||
|
||||
interface BeanContributionBuilder {
|
||||
RepositoryRegistrationAotContribution forRepository(Class<?> repositoryInterface);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.mongodb.aot;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.springframework.aot.hint.ClassProxyHint;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2022/04
|
||||
*/
|
||||
public class ClassProxyAssert extends AbstractAssert<ClassProxyAssert, ClassProxyHint> {
|
||||
|
||||
protected ClassProxyAssert(ClassProxyHint classProxyHint) {
|
||||
super(classProxyHint, ClassProxyAssert.class);
|
||||
}
|
||||
|
||||
public void matches(Class<?>... proxyInterfaces) {
|
||||
assertThat(actual.getProxiedInterfaces().stream().map(TypeReference::getCanonicalName))
|
||||
.containsExactly(Arrays.stream(proxyInterfaces).map(Class::getCanonicalName).toArray(String[]::new));
|
||||
}
|
||||
|
||||
public List<TypeReference> getProxiedInterfaces() {
|
||||
return actual.getProxiedInterfaces();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.mongodb.aot;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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.RuntimeHintsPredicates;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2022/04
|
||||
*/
|
||||
public class CodeContributionAssert extends AbstractAssert<CodeContributionAssert, GenerationContext> {
|
||||
|
||||
public CodeContributionAssert(GenerationContext contribution) {
|
||||
super(contribution, CodeContributionAssert.class);
|
||||
}
|
||||
|
||||
public CodeContributionAssert contributesReflectionFor(Class<?>... types) {
|
||||
|
||||
for (Class<?> type : types) {
|
||||
assertThat(this.actual.getRuntimeHints())
|
||||
.describedAs("No reflection entry found for [%s]", type)
|
||||
.matches(RuntimeHintsPredicates.reflection().onType(type));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeContributionAssert doesNotContributeReflectionFor(Class<?>... types) {
|
||||
|
||||
for (Class<?> type : types) {
|
||||
assertThat(this.actual.getRuntimeHints())
|
||||
.describedAs("Reflection entry found for [%s]", type)
|
||||
.matches(RuntimeHintsPredicates.reflection().onType(type).negate());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeContributionAssert contributesJdkProxyFor(Class<?> entryPoint) {
|
||||
|
||||
assertThat(jdkProxiesFor(entryPoint).findFirst())
|
||||
.describedAs("No JDK proxy found for [%s]", entryPoint)
|
||||
.isPresent();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeContributionAssert doesNotContributeJdkProxyFor(Class<?> entryPoint) {
|
||||
|
||||
assertThat(jdkProxiesFor(entryPoint).findFirst())
|
||||
.describedAs("Found JDK proxy matching [%s] though it should not be present", entryPoint)
|
||||
.isNotPresent();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeContributionAssert contributesJdkProxy(Class<?>... proxyInterfaces) {
|
||||
|
||||
assertThat(jdkProxiesFor(proxyInterfaces[0]))
|
||||
.describedAs("Unable to find JDK proxy matching [%s]", Arrays.asList(proxyInterfaces))
|
||||
.anySatisfy(it -> new JdkProxyAssert(it).matches(proxyInterfaces));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeContributionAssert doesNotContributeJdkProxy(Class<?>... proxyInterfaces) {
|
||||
|
||||
assertThat(jdkProxiesFor(proxyInterfaces[0]))
|
||||
.describedAs("Found JDK proxy matching [%s] though it should not be present",
|
||||
Arrays.asList(proxyInterfaces))
|
||||
.noneSatisfy(it -> new JdkProxyAssert(it).matches(proxyInterfaces));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private Stream<JdkProxyHint> jdkProxiesFor(Class<?> entryPoint) {
|
||||
|
||||
return this.actual.getRuntimeHints().proxies().jdkProxies()
|
||||
.filter(jdkProxyHint -> jdkProxyHint.getProxiedInterfaces().get(0).getCanonicalName()
|
||||
.equals(entryPoint.getCanonicalName()));
|
||||
}
|
||||
|
||||
public CodeContributionAssert contributesClassProxy(Class<?>... proxyInterfaces) {
|
||||
|
||||
assertThat(classProxiesFor(proxyInterfaces[0]))
|
||||
.describedAs("Unable to find JDK proxy matching [%s]", Arrays.asList(proxyInterfaces))
|
||||
.anySatisfy(it -> new ClassProxyAssert(it).matches(proxyInterfaces));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private Stream<ClassProxyHint> classProxiesFor(Class<?> entryPoint) {
|
||||
|
||||
return this.actual.getRuntimeHints().proxies().classProxies()
|
||||
.filter(jdkProxyHint -> jdkProxyHint.getProxiedInterfaces().get(0).getCanonicalName()
|
||||
.equals(entryPoint.getCanonicalName()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.mongodb.aot;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.springframework.aot.hint.JdkProxyHint;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2022/04
|
||||
*/
|
||||
public class JdkProxyAssert extends AbstractAssert<JdkProxyAssert, JdkProxyHint> {
|
||||
|
||||
public JdkProxyAssert(JdkProxyHint jdkProxyHint) {
|
||||
super(jdkProxyHint, JdkProxyAssert.class);
|
||||
}
|
||||
|
||||
public void matches(Class<?>... proxyInterfaces) {
|
||||
assertThat(actual.getProxiedInterfaces().stream().map(TypeReference::getCanonicalName))
|
||||
.containsExactly(Arrays.stream(proxyInterfaces).map(Class::getCanonicalName).toArray(String[]::new));
|
||||
}
|
||||
|
||||
public List<TypeReference> getProxiedInterfaces() {
|
||||
return actual.getProxiedInterfaces();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.mongodb.aot;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
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.BeanRegistrationAotContribution;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationCode;
|
||||
import org.springframework.data.aot.RepositoryRegistrationAotContribution;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.core.support.RepositoryFragment;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2022/04
|
||||
*/
|
||||
public class RepositoryRegistrationAotContributionAssert
|
||||
extends AbstractAssert<RepositoryRegistrationAotContributionAssert, RepositoryRegistrationAotContribution> {
|
||||
|
||||
@NonNull
|
||||
public static RepositoryRegistrationAotContributionAssert assertThatContribution(
|
||||
@NonNull RepositoryRegistrationAotContribution actual) {
|
||||
|
||||
return new RepositoryRegistrationAotContributionAssert(actual);
|
||||
}
|
||||
|
||||
public RepositoryRegistrationAotContributionAssert(@NonNull RepositoryRegistrationAotContribution actual) {
|
||||
super(actual, RepositoryRegistrationAotContributionAssert.class);
|
||||
}
|
||||
|
||||
public RepositoryRegistrationAotContributionAssert targetRepositoryTypeIs(Class<?> expected) {
|
||||
|
||||
assertThat(getRepositoryInformation().getRepositoryInterface()).isEqualTo(expected);
|
||||
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
public RepositoryRegistrationAotContributionAssert hasNoFragments() {
|
||||
|
||||
assertThat(getRepositoryInformation().getFragments()).isEmpty();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public RepositoryRegistrationAotContributionAssert hasFragments() {
|
||||
|
||||
assertThat(getRepositoryInformation().getFragments()).isNotEmpty();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public RepositoryRegistrationAotContributionAssert verifyFragments(Consumer<Set<RepositoryFragment<?>>> consumer) {
|
||||
|
||||
assertThat(getRepositoryInformation().getFragments())
|
||||
.satisfies(it -> consumer.accept(new LinkedHashSet<>(it)));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public RepositoryRegistrationAotContributionAssert codeContributionSatisfies(
|
||||
Consumer<CodeContributionAssert> assertWith) {
|
||||
|
||||
BeanRegistrationCode mockBeanRegistrationCode = mock(BeanRegistrationCode.class);
|
||||
|
||||
DefaultGenerationContext generationContext =
|
||||
new DefaultGenerationContext(new ClassNameGenerator(), new InMemoryGeneratedFiles(), new RuntimeHints());
|
||||
|
||||
this.actual.applyTo(generationContext, mockBeanRegistrationCode);
|
||||
|
||||
assertWith.accept(new CodeContributionAssert(generationContext));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private RepositoryInformation getRepositoryInformation() {
|
||||
|
||||
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();
|
||||
|
||||
return this.actual.getRepositoryInformation();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.mongodb.aot.configs;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.FilterType;
|
||||
import org.springframework.data.mongodb.aot.domaintypes.Person;
|
||||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@Configuration
|
||||
@EnableMongoRepositories(considerNestedRepositories = true,
|
||||
includeFilters = { @Filter(type = FilterType.REGEX, pattern = ".*PersonRepository$") })
|
||||
public class ImperativeConfig {
|
||||
|
||||
public interface PersonRepository extends CrudRepository<Person, String> {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.mongodb.aot.domaintypes;
|
||||
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2022/04
|
||||
*/
|
||||
public class Address {
|
||||
|
||||
@Field("the-street")
|
||||
String street;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.mongodb.aot.domaintypes;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 2022/04
|
||||
*/
|
||||
@Document("persons")
|
||||
public class Person {
|
||||
|
||||
@Id String id;
|
||||
@DBRef(lazy = true) Address address;
|
||||
|
||||
@Transient String transientProperty;
|
||||
|
||||
@LastModifiedDate Instant modifiedAt;
|
||||
}
|
||||
@@ -31,7 +31,9 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.data.domain.ManagedTypes;
|
||||
import org.springframework.data.mongodb.MongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.MongoManagedTypes;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
|
||||
import org.springframework.data.mongodb.core.convert.MongoTypeMapper;
|
||||
@@ -91,7 +93,7 @@ public class AbstractMongoConfigurationUnitTests {
|
||||
public void returnsUninitializedMappingContext() throws Exception {
|
||||
|
||||
SampleMongoConfiguration configuration = new SampleMongoConfiguration();
|
||||
MongoMappingContext context = configuration.mongoMappingContext(configuration.customConversions());
|
||||
MongoMappingContext context = configuration.mongoMappingContext(configuration.customConversions(), MongoManagedTypes.of(Collections.singleton(Entity.class)));
|
||||
|
||||
assertThat(context.getPersistentEntities()).isEmpty();
|
||||
context.initialize();
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.data.mongodb.MongoManagedTypes;
|
||||
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
@@ -92,7 +93,7 @@ public class AbstractReactiveMongoConfigurationUnitTests {
|
||||
public void returnsUninitializedMappingContext() throws Exception {
|
||||
|
||||
SampleMongoConfiguration configuration = new SampleMongoConfiguration();
|
||||
MongoMappingContext context = configuration.mongoMappingContext(configuration.customConversions());
|
||||
MongoMappingContext context = configuration.mongoMappingContext(configuration.customConversions(), MongoManagedTypes.of(Collections.singleton(Entity.class)));
|
||||
|
||||
assertThat(context.getPersistentEntities()).isEmpty();
|
||||
context.initialize();
|
||||
|
||||
@@ -105,9 +105,7 @@ public class MappingMongoConverterParserIntegrationTests {
|
||||
|
||||
@Test // DATAMONGO-892
|
||||
void shouldThrowBeanDefinitionParsingExceptionIfConverterDefinedAsNestedBean() {
|
||||
|
||||
assertThatExceptionOfType(BeanDefinitionParsingException.class).isThrownBy(this::loadNestedBeanConfiguration);
|
||||
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-925, DATAMONGO-928
|
||||
|
||||
Reference in New Issue
Block a user