Skip to content

Commit f8fd6da

Browse files
committed
Merge branch '6.2.x'
2 parents 6d28ac6 + 0d72477 commit f8fd6da

File tree

3 files changed

+94
-2
lines changed

3 files changed

+94
-2
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/aot/DefaultBeanRegistrationCodeFragments.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public CodeBlock generateNewBeanDefinitionCode(GenerationContext generationConte
123123

124124
CodeBlock.Builder code = CodeBlock.builder();
125125
RootBeanDefinition mbd = this.registeredBean.getMergedBeanDefinition();
126-
Class<?> beanClass = (mbd.hasBeanClass() ? mbd.getBeanClass() : null);
126+
Class<?> beanClass = (mbd.hasBeanClass() ? ClassUtils.getUserClass(mbd.getBeanClass()) : null);
127127
CodeBlock beanClassCode = generateBeanClassCode(
128128
beanRegistrationCode.getClassName().packageName(),
129129
(beanClass != null ? beanClass : beanType.toClass()));

spring-context/src/test/java/org/springframework/context/aot/ApplicationContextAotGeneratorTests.java

+59-1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
import org.springframework.context.testfixture.context.annotation.PropertySourceConfiguration;
8585
import org.springframework.context.testfixture.context.annotation.QualifierConfiguration;
8686
import org.springframework.context.testfixture.context.annotation.ResourceComponent;
87+
import org.springframework.context.testfixture.context.annotation.ValueCglibConfiguration;
8788
import org.springframework.context.testfixture.context.generator.SimpleComponent;
8889
import org.springframework.core.env.ConfigurableEnvironment;
8990
import org.springframework.core.env.Environment;
@@ -438,12 +439,14 @@ void processAheadOfTimeWithExplicitResolvableType() {
438439
@CompileWithForkedClassLoader
439440
class ConfigurationClassCglibProxy {
440441

442+
private static final String CGLIB_CONFIGURATION_CLASS_SUFFIX = "$$SpringCGLIB$$0";
443+
441444
@Test
442445
void processAheadOfTimeWhenHasCglibProxyWriteProxyAndGenerateReflectionHints() throws IOException {
443446
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
444447
applicationContext.registerBean(CglibConfiguration.class);
445448
TestGenerationContext context = processAheadOfTime(applicationContext);
446-
isRegisteredCglibClass(context, CglibConfiguration.class.getName() + "$$SpringCGLIB$$0");
449+
isRegisteredCglibClass(context, CglibConfiguration.class.getName() + CGLIB_CONFIGURATION_CLASS_SUFFIX);
447450
isRegisteredCglibClass(context, CglibConfiguration.class.getName() + "$$SpringCGLIB$$FastClass$$0");
448451
isRegisteredCglibClass(context, CglibConfiguration.class.getName() + "$$SpringCGLIB$$FastClass$$1");
449452
}
@@ -455,6 +458,43 @@ private void isRegisteredCglibClass(TestGenerationContext context, String cglibC
455458
.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(context.getRuntimeHints());
456459
}
457460

461+
@Test
462+
void processAheadOfTimeExposeUserClassForCglibProxy() {
463+
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
464+
applicationContext.registerBean("config", ValueCglibConfiguration.class);
465+
466+
testCompiledResult(applicationContext, (initializer, compiled) -> {
467+
GenericApplicationContext freshApplicationContext = toFreshApplicationContext(initializer);
468+
assertThat(freshApplicationContext).satisfies(hasBeanDefinitionOfBeanClass("config", ValueCglibConfiguration.class));
469+
assertThat(compiled.getSourceFile(".*ValueCglibConfiguration__BeanDefinitions"))
470+
.contains("new RootBeanDefinition(ValueCglibConfiguration.class)")
471+
.contains("new %s(".formatted(toCglibClassSimpleName(ValueCglibConfiguration.class)));
472+
});
473+
}
474+
475+
@Test
476+
void processAheadOfTimeUsesCglibClassForFactoryMethod() {
477+
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
478+
applicationContext.registerBean("config", CglibConfiguration.class);
479+
480+
testCompiledResult(applicationContext, (initializer, compiled) -> {
481+
GenericApplicationContext freshApplicationContext = toFreshApplicationContext(initializer);
482+
assertThat(freshApplicationContext).satisfies(hasBeanDefinitionOfBeanClass("config", CglibConfiguration.class));
483+
assertThat(compiled.getSourceFile(".*CglibConfiguration__BeanDefinitions"))
484+
.contains("new RootBeanDefinition(CglibConfiguration.class)")
485+
.contains(">forFactoryMethod(%s.class,".formatted(toCglibClassSimpleName(CglibConfiguration.class)))
486+
.doesNotContain(">forFactoryMethod(%s.class,".formatted(CglibConfiguration.class));
487+
});
488+
}
489+
490+
private Consumer<GenericApplicationContext> hasBeanDefinitionOfBeanClass(String name, Class<?> beanClass) {
491+
return context -> {
492+
assertThat(context.containsBean(name)).isTrue();
493+
assertThat(context.getBeanDefinition(name)).isInstanceOfSatisfying(RootBeanDefinition.class,
494+
rbd -> assertThat(rbd.getBeanClass()).isEqualTo(beanClass));
495+
};
496+
}
497+
458498
@Test
459499
void processAheadOfTimeWhenHasCglibProxyUseProxy() {
460500
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
@@ -493,6 +533,20 @@ void processAheadOfTimeWhenHasCglibProxyAndMixedAutowiring() {
493533
});
494534
}
495535

536+
@Test
537+
void processAheadOfTimeWhenHasCglibProxyWithAnnotationsOnTheUserClasConstructor() {
538+
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
539+
applicationContext.registerBean("config", ValueCglibConfiguration.class);
540+
testCompiledResult(applicationContext, (initializer, compiled) -> {
541+
GenericApplicationContext freshApplicationContext = toFreshApplicationContext(context -> {
542+
context.setEnvironment(new MockEnvironment().withProperty("name", "AOT World"));
543+
initializer.initialize(context);
544+
});
545+
assertThat(freshApplicationContext.getBean(ValueCglibConfiguration.class)
546+
.getName()).isEqualTo("AOT World");
547+
});
548+
}
549+
496550
@Test
497551
void processAheadOfTimeWhenHasCglibProxyWithArgumentsUseProxy() {
498552
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
@@ -516,6 +570,10 @@ void processAheadOfTimeWhenHasCglibProxyWithArgumentsRegisterIntrospectionHintsO
516570
.accepts(generationContext.getRuntimeHints());
517571
}
518572

573+
private String toCglibClassSimpleName(Class<?> configClass) {
574+
return configClass.getSimpleName() + CGLIB_CONFIGURATION_CLASS_SUFFIX;
575+
}
576+
519577
}
520578

521579
@Nested
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2002-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.context.testfixture.context.annotation;
18+
19+
import org.springframework.beans.factory.annotation.Value;
20+
import org.springframework.context.annotation.Configuration;
21+
22+
@Configuration
23+
public class ValueCglibConfiguration {
24+
25+
private final String name;
26+
27+
public ValueCglibConfiguration(@Value("${name:World}") String name) {
28+
this.name = name;
29+
}
30+
31+
public String getName() {
32+
return this.name;
33+
}
34+
}

0 commit comments

Comments
 (0)