Skip to content
This repository was archived by the owner on Feb 23, 2023. It is now read-only.

Commit 1c22c2d

Browse files
committed
Harvest injection points behind cglib proxy if necessary
Closes gh-1273
1 parent 74a0a66 commit 1c22c2d

File tree

6 files changed

+99
-15
lines changed

6 files changed

+99
-15
lines changed

spring-aot/src/main/java/org/springframework/aot/context/bootstrap/generator/bean/descriptor/BeanInstanceExecutableSupplier.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ private boolean isFactoryMethodCandidate(Class<?> beanClass, Method method, Stri
172172
}
173173

174174
private Executable resolveConstructor(Supplier<ResolvableType> beanType, List<ResolvableType> valueTypes) {
175-
Class<?> type = beanType.get().toClass();
175+
Class<?> type = ClassUtils.getUserClass(beanType.get().toClass());
176176
Constructor<?>[] constructors = type.getDeclaredConstructors();
177177
if (constructors.length == 1) {
178178
return constructors[0];

spring-aot/src/main/java/org/springframework/aot/context/bootstrap/generator/bean/descriptor/DefaultBeanInstanceDescriptorFactory.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.springframework.beans.factory.config.BeanDefinition;
2525
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
2626
import org.springframework.util.Assert;
27+
import org.springframework.util.ClassUtils;
2728

2829
/**
2930
* A default {@link BeanInstanceDescriptorFactory} implementation using the standard
@@ -50,7 +51,7 @@ public BeanInstanceDescriptor create(BeanDefinition beanDefinition) {
5051
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
5152
Executable instanceCreator = this.instanceCreatorSupplier.detectBeanInstanceExecutable(beanDefinition);
5253
if (instanceCreator != null) {
53-
Class<?> beanType = beanDefinition.getResolvableType().toClass();
54+
Class<?> beanType = ClassUtils.getUserClass(beanDefinition.getResolvableType().toClass());
5455
List<MemberDescriptor<?>> injectionPoints = this.injectionPointsSupplier.detectInjectionPoints(beanType);
5556
List<PropertyDescriptor> properties = this.propertiesSupplier.detectProperties(beanDefinition);
5657
return BeanInstanceDescriptor.of(beanDefinition.getResolvableType())

spring-aot/src/main/java/org/springframework/data/JpaConfigurationProcessor.java

+5-8
Original file line numberDiff line numberDiff line change
@@ -323,14 +323,11 @@ private static <T> Class<T> loadIfPresent(String name, ClassLoader classLoader)
323323

324324
static void doWithComponents(ConfigurableListableBeanFactory beanFactory, ComponentCallback callback,
325325
ComponentFilter filter) {
326-
beanFactory.getBeanNamesIterator().forEachRemaining((beanName) -> {
327-
Class<?> beanType = beanFactory.getType(beanName);
328-
MergedAnnotation<Component> componentAnnotation = MergedAnnotations.from(beanType).get(Component.class);
329-
if (componentAnnotation.isPresent()) {
330-
if (filter == null || filter.test(beanName, beanType)) {
331-
callback.invoke(beanName, beanType);
332-
}
326+
for (String beanName : beanFactory.getBeanNamesForAnnotation(Component.class)) {
327+
Class<?> beanType = ClassUtils.getUserClass(beanFactory.getType(beanName));
328+
if (filter == null || filter.test(beanName, beanType)) {
329+
callback.invoke(beanName, beanType);
333330
}
334-
});
331+
}
335332
}
336333
}

spring-aot/src/test/java/org/springframework/aot/context/bootstrap/generator/bean/descriptor/DefaultBeanInstanceDescriptorFactoryTests.java

+56-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818

1919
import org.junit.jupiter.api.Test;
2020

21+
import org.springframework.aop.framework.ProxyFactory;
2122
import org.springframework.aot.context.bootstrap.generator.sample.SimpleConfiguration;
23+
import org.springframework.aot.context.bootstrap.generator.sample.injection.FieldInjectionComponent;
2224
import org.springframework.aot.context.bootstrap.generator.sample.injection.InjectionConfiguration;
2325
import org.springframework.beans.factory.config.BeanDefinition;
2426
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -80,10 +82,23 @@ private void assertSimpleConfigurationDescriptor(BeanInstanceDescriptor descript
8082
}
8183

8284
@Test
83-
void createWithInjectionPoints() {
85+
void createWithMethodInjectionPoints() {
8486
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
8587
beanFactory.registerBeanDefinition("test", BeanDefinitionBuilder.rootBeanDefinition(InjectionConfiguration.class).getBeanDefinition());
8688
BeanInstanceDescriptor descriptor = createDescriptor(beanFactory, "test");
89+
assertInjectionConfiguration(descriptor);
90+
}
91+
92+
@Test
93+
void createWithMethodInjectionPointsUsingCglibProxy() {
94+
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
95+
beanFactory.registerBeanDefinition("test", BeanDefinitionBuilder.rootBeanDefinition(
96+
createCglibProxyType(InjectionConfiguration.class)).getBeanDefinition());
97+
BeanInstanceDescriptor descriptor = createDescriptor(beanFactory, "test");
98+
assertInjectionConfiguration(descriptor);
99+
}
100+
101+
private void assertInjectionConfiguration(BeanInstanceDescriptor descriptor) {
87102
assertThat(descriptor.getUserBeanClass()).isEqualTo(InjectionConfiguration.class);
88103
assertThat(descriptor.getInstanceCreator()).isNotNull();
89104
assertThat(descriptor.getInstanceCreator().getMember()).isEqualTo(InjectionConfiguration.class.getDeclaredConstructors()[0]);
@@ -99,6 +114,40 @@ void createWithInjectionPoints() {
99114
assertThat(descriptor.getProperties()).isEmpty();
100115
}
101116

117+
@Test
118+
void createWithFieldInjectionPoints() {
119+
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
120+
beanFactory.registerBeanDefinition("test", BeanDefinitionBuilder.rootBeanDefinition(FieldInjectionComponent.class).getBeanDefinition());
121+
BeanInstanceDescriptor descriptor = createDescriptor(beanFactory, "test");
122+
assertFieldInjectionComponent(descriptor);
123+
}
124+
125+
@Test
126+
void createWithFieldInjectionPointsUsingCglibProxy() {
127+
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
128+
beanFactory.registerBeanDefinition("test", BeanDefinitionBuilder.rootBeanDefinition(
129+
createCglibProxyType(FieldInjectionComponent.class)).getBeanDefinition());
130+
BeanInstanceDescriptor descriptor = createDescriptor(beanFactory, "test");
131+
assertFieldInjectionComponent(descriptor);
132+
}
133+
134+
135+
private void assertFieldInjectionComponent(BeanInstanceDescriptor descriptor) {
136+
assertThat(descriptor.getUserBeanClass()).isEqualTo(FieldInjectionComponent.class);
137+
assertThat(descriptor.getInstanceCreator()).isNotNull();
138+
assertThat(descriptor.getInstanceCreator().getMember()).isEqualTo(FieldInjectionComponent.class.getDeclaredConstructors()[0]);
139+
assertThat(descriptor.getInjectionPoints()).hasSize(2);
140+
assertThat(descriptor.getInjectionPoints()).anySatisfy((injectionPoint) -> {
141+
assertThat(injectionPoint.getMember()).isEqualTo(ReflectionUtils.findField(FieldInjectionComponent.class, "environment"));
142+
assertThat(injectionPoint.isRequired()).isTrue();
143+
});
144+
assertThat(descriptor.getInjectionPoints()).anySatisfy((injectionPoint) -> {
145+
assertThat(injectionPoint.getMember()).isEqualTo(ReflectionUtils.findField(FieldInjectionComponent.class, "bean"));
146+
assertThat(injectionPoint.isRequired()).isFalse();
147+
});
148+
assertThat(descriptor.getProperties()).isEmpty();
149+
}
150+
102151
@Test
103152
void createWithProperties() {
104153
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
@@ -120,4 +169,10 @@ private BeanInstanceDescriptor createDescriptor(DefaultListableBeanFactory beanF
120169
return new DefaultBeanInstanceDescriptorFactory(beanFactory).create(beanFactory.getMergedBeanDefinition(beanName));
121170
}
122171

172+
private Class<?> createCglibProxyType(Class<?> target) {
173+
ProxyFactory proxyFactory = new ProxyFactory();
174+
proxyFactory.setTargetClass(target);
175+
return proxyFactory.getProxy().getClass();
176+
}
177+
123178
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.springframework.aot.context.bootstrap.generator.sample.injection;
2+
3+
import org.springframework.beans.factory.annotation.Autowired;
4+
import org.springframework.core.env.Environment;
5+
6+
public class FieldInjectionComponent {
7+
8+
@Autowired
9+
private Environment environment;
10+
11+
@Autowired(required = false)
12+
private String bean;
13+
14+
}

spring-aot/src/test/java/org/springframework/data/JpaConfigurationProcessorTests.java

+21-4
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,19 @@
1515
*/
1616
package org.springframework.data;
1717

18-
import static org.assertj.core.api.Assertions.*;
18+
import java.util.Arrays;
19+
import java.util.LinkedHashSet;
20+
import java.util.Optional;
1921

2022
import javax.persistence.Entity;
2123
import javax.persistence.GeneratedValue;
2224
import javax.persistence.ManyToOne;
2325
import javax.persistence.OneToMany;
24-
import java.util.Arrays;
25-
import java.util.LinkedHashSet;
26-
import java.util.Optional;
2726

2827
import org.junit.jupiter.api.Disabled;
2928
import org.junit.jupiter.api.Test;
29+
30+
import org.springframework.aop.framework.ProxyFactory;
3031
import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.DefaultNativeReflectionEntry;
3132
import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeConfigurationRegistry;
3233
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -44,6 +45,8 @@
4445
import org.springframework.sample.data.jpa.SomeAnnotation;
4546
import org.springframework.util.ReflectionUtils;
4647

48+
import static org.assertj.core.api.Assertions.assertThat;
49+
4750
/**
4851
* Tests for {@link JpaConfigurationProcessor}.
4952
*
@@ -132,6 +135,20 @@ public void shouldRegisterFieldAccessForPersistenceContext() {
132135
assertThat(reflectionEntry.getFields()).containsExactly(ReflectionUtils.findField(ComponentWithPersistenceContext.class, "entityManager"));
133136
}
134137

138+
@Test
139+
public void shouldRegisterFieldAccessForPersistenceContextBehindCglibProxy() {
140+
NativeConfigRegistryHolder nativeConfigRegistryHolder = processBeansWithPotentialPersistenceContext(
141+
createCglibProxyType(ComponentWithPersistenceContext.class));
142+
DefaultNativeReflectionEntry reflectionEntry = nativeConfigRegistryHolder.getReflectionEntry(ComponentWithPersistenceContext.class);
143+
assertThat(reflectionEntry.getFields()).containsExactly(ReflectionUtils.findField(ComponentWithPersistenceContext.class, "entityManager"));
144+
}
145+
146+
private Class<?> createCglibProxyType(Class<?> target) {
147+
ProxyFactory proxyFactory = new ProxyFactory();
148+
proxyFactory.setTargetClass(target);
149+
return proxyFactory.getProxy().getClass();
150+
}
151+
135152

136153
NativeConfigRegistryHolder processJpaEntities(Class<?>... entities) {
137154

0 commit comments

Comments
 (0)