diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/LazyLoadingProxyAotProcessor.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/LazyLoadingProxyAotProcessor.java index 0abeab70c..070a0a4f5 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/LazyLoadingProxyAotProcessor.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/LazyLoadingProxyAotProcessor.java @@ -18,6 +18,7 @@ package org.springframework.data.mongodb.aot; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -25,7 +26,6 @@ import java.util.Set; import org.springframework.aot.generate.GenerationContext; import org.springframework.aot.hint.MemberCategory; 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; @@ -33,7 +33,6 @@ import org.springframework.data.mongodb.core.convert.LazyLoadingProxyFactory; import org.springframework.data.mongodb.core.convert.LazyLoadingProxyFactory.LazyLoadingInterceptor; import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.data.mongodb.core.mapping.DocumentReference; -import org.springframework.data.util.TypeUtils; /** * @author Christoph Strobl @@ -66,9 +65,7 @@ public class LazyLoadingProxyAotProcessor { if (field.getType().isInterface()) { List> interfaces = new ArrayList<>( - TypeUtils.resolveTypesInSignature(ResolvableType.forField(field, type))); - - interfaces.add(0, org.springframework.data.mongodb.core.convert.LazyLoadingProxy.class); + Arrays.asList(LazyLoadingProxyFactory.prepareFactory(field.getType()).getProxiedInterfaces())); interfaces.add(org.springframework.aop.SpringProxy.class); interfaces.add(org.springframework.aop.framework.Advised.class); interfaces.add(org.springframework.core.DecoratingProxy.class); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/LazyLoadingProxyFactory.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/LazyLoadingProxyFactory.java index 4f84d57e4..64f2f0a64 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/LazyLoadingProxyFactory.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/LazyLoadingProxyFactory.java @@ -90,7 +90,14 @@ public final class LazyLoadingProxyFactory { .getProxyClass(LazyLoadingProxy.class.getClassLoader()); } - private ProxyFactory prepareProxyFactory(Class propertyType, Supplier interceptor) { + /** + * Create the {@link ProxyFactory} for the given type, already adding required additional interfaces. + * + * @param propertyType the type to proxy + * @return the proxy type. + * @since 4.0.5 + */ + public static ProxyFactory prepareFactory(Class propertyType) { ProxyFactory proxyFactory = new ProxyFactory(); @@ -100,6 +107,13 @@ public final class LazyLoadingProxyFactory { proxyFactory.addInterface(LazyLoadingProxy.class); proxyFactory.addInterface(propertyType); + + return proxyFactory; + } + + private ProxyFactory prepareProxyFactory(Class propertyType, Supplier interceptor) { + + ProxyFactory proxyFactory = prepareFactory(propertyType); proxyFactory.addAdvice(interceptor.get()); return proxyFactory; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/aot/LazyLoadingProxyAotProcessorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/aot/LazyLoadingProxyAotProcessorUnitTests.java new file mode 100644 index 000000000..dbcc4d8da --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/aot/LazyLoadingProxyAotProcessorUnitTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2023 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.List; + +import org.junit.jupiter.api.Test; +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.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.data.mongodb.core.mapping.DBRef; +import org.springframework.javapoet.ClassName; + +/** + * @author Christoph Strobl + */ +class LazyLoadingProxyAotProcessorUnitTests { + + @Test // GH-4351 + void registersProxyForLazyDbRefCorrectlyWhenTypeIsCollectionInterface() { + + GenerationContext ctx = new DefaultGenerationContext(new ClassNameGenerator(ClassName.get(this.getClass())), + new InMemoryGeneratedFiles()); + + new LazyLoadingProxyAotProcessor().registerLazyLoadingProxyIfNeeded(A.class, ctx); + + assertThat(ctx.getRuntimeHints()) + .satisfies(RuntimeHintsPredicates.proxies().forInterfaces(java.util.Collection.class, + org.springframework.data.mongodb.core.convert.LazyLoadingProxy.class, java.util.List.class, + org.springframework.aop.SpringProxy.class, org.springframework.aop.framework.Advised.class, + org.springframework.core.DecoratingProxy.class)::test); + } + + static class A { + + String id; + + @DBRef(lazy = true) // + List listRef; + } + + static class B { + String id; + } +}