forked from spring-projects/spring-framework
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Retain existing feature name as prefix in test AOT processing
Prior to this commit, test AOT processing failed if a feature name for generated class names was used for more than one ApplicationContext. For example, when generating code for org.example.MessageService with a "Management" feature name, the "BeanDefinitions" class was named as follows (without a uniquely identifying TestContext###_ feature name prefix). org/example/MessageService__ManagementBeanDefinitions.java When another attempt was made to generate code for the MessageService using the same "Management" feature name, a FileAlreadyExistsException was thrown denoting that the class/file name was already in use. To avoid such naming collisions, this commit introduces a TestContextGenerationContext which provides a custom implementation of withName(String) that prepends an existing feature name (if present) to a new feature name, thereby treating any existing feature name as a prefix to a new, nested feature name. Consequently, code generation for the above example now results in unique class/file names like the following (which retain the uniquely identifying TestContext###_ prefixes). org/example/MessageService__TestContext002_ManagementBeanDefinitions.java org/example/MessageService__TestContext003_ManagementBeanDefinitions.java Closes spring-projectsgh-30861
- Loading branch information
Showing
11 changed files
with
272 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
85 changes: 85 additions & 0 deletions
85
...test/src/main/java/org/springframework/test/context/aot/TestContextGenerationContext.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
* Copyright 2002-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.test.context.aot; | ||
|
||
import org.springframework.aot.generate.ClassNameGenerator; | ||
import org.springframework.aot.generate.DefaultGenerationContext; | ||
import org.springframework.aot.generate.GeneratedClasses; | ||
import org.springframework.aot.generate.GeneratedFiles; | ||
import org.springframework.aot.hint.RuntimeHints; | ||
|
||
/** | ||
* Extension of {@link DefaultGenerationContext} with a custom implementation of | ||
* {@link #withName(String)} that is specific to the <em>Spring TestContext Framework</em>. | ||
* | ||
* @author Sam Brannen | ||
* @since 6.0.12 | ||
*/ | ||
class TestContextGenerationContext extends DefaultGenerationContext { | ||
|
||
private final String featureName; | ||
|
||
|
||
/** | ||
* Create a new {@link TestContextGenerationContext} instance backed by the | ||
* specified {@link ClassNameGenerator}, {@link GeneratedFiles}, and | ||
* {@link RuntimeHints}. | ||
* @param classNameGenerator the naming convention to use for generated class names | ||
* @param generatedFiles the generated files | ||
* @param runtimeHints the runtime hints | ||
*/ | ||
TestContextGenerationContext(ClassNameGenerator classNameGenerator, GeneratedFiles generatedFiles, | ||
RuntimeHints runtimeHints) { | ||
super(classNameGenerator, generatedFiles, runtimeHints); | ||
this.featureName = null; | ||
} | ||
|
||
/** | ||
* Create a new {@link TestContextGenerationContext} instance backed by the | ||
* specified {@link GeneratedClasses}, {@link GeneratedFiles}, and | ||
* {@link RuntimeHints}. | ||
* @param generatedClasses the generated classes | ||
* @param generatedFiles the generated files | ||
* @param runtimeHints the runtime hints | ||
*/ | ||
private TestContextGenerationContext(GeneratedClasses generatedClasses, GeneratedFiles generatedFiles, | ||
RuntimeHints runtimeHints, String featureName) { | ||
super(generatedClasses, generatedFiles, runtimeHints); | ||
this.featureName = featureName; | ||
} | ||
|
||
|
||
/** | ||
* Create a new {@link TestContextGenerationContext} instance using the specified | ||
* feature name to qualify generated assets for a dedicated round of code generation. | ||
* <p>If <em>this</em> {@code TestContextGenerationContext} has a configured feature | ||
* name, the supplied feature name will be appended to the existing feature name | ||
* in order to avoid naming collisions. | ||
* @param featureName the feature name to use | ||
* @return a specialized {@link TestContextGenerationContext} for the specified | ||
* feature name | ||
*/ | ||
@Override | ||
public TestContextGenerationContext withName(String featureName) { | ||
if (this.featureName != null) { | ||
featureName = this.featureName + featureName; | ||
} | ||
GeneratedClasses generatedClasses = getGeneratedClasses().withFeatureNamePrefix(featureName); | ||
return new TestContextGenerationContext(generatedClasses, getGeneratedFiles(), getRuntimeHints(), featureName); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
...g-test/src/test/java/org/springframework/test/context/aot/samples/management/Managed.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/* | ||
* Copyright 2002-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.test.context.aot.samples.management; | ||
|
||
import java.lang.annotation.Documented; | ||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* Marker annotation for "managed" beans. | ||
* | ||
* @author Sam Brannen | ||
* @since 6.0.12 | ||
*/ | ||
@Documented | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.METHOD) | ||
public @interface Managed { | ||
} |
83 changes: 83 additions & 0 deletions
83
...java/org/springframework/test/context/aot/samples/management/ManagementConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
* Copyright 2002-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.test.context.aot.samples.management; | ||
|
||
import java.lang.reflect.Executable; | ||
|
||
import org.springframework.aot.generate.GenerationContext; | ||
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution; | ||
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor; | ||
import org.springframework.beans.factory.aot.BeanRegistrationCode; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.context.aot.ApplicationContextAotGenerator; | ||
import org.springframework.context.support.GenericApplicationContext; | ||
import org.springframework.core.annotation.AnnotatedElementUtils; | ||
|
||
/** | ||
* Configuration class that mimics Spring Boot's AOT support for child management | ||
* contexts in | ||
* {@code org.springframework.boot.actuate.autoconfigure.web.server.ChildManagementContextInitializer}. | ||
* | ||
* <p>See <a href="https://github.com/spring-projects/spring-framework/issues/30861">gh-30861</a>. | ||
* | ||
* @author Sam Brannen | ||
* @since 6.0.12 | ||
*/ | ||
@Configuration | ||
public class ManagementConfiguration { | ||
|
||
@Bean | ||
static BeanRegistrationAotProcessor beanRegistrationAotProcessor() { | ||
return registeredBean -> { | ||
Executable factoryMethod = registeredBean.resolveConstructorOrFactoryMethod(); | ||
// Make AOT contribution for @Managed @Bean methods. | ||
if (AnnotatedElementUtils.hasAnnotation(factoryMethod, Managed.class)) { | ||
return new AotContribution(createManagementContext()); | ||
} | ||
return null; | ||
}; | ||
} | ||
|
||
private static GenericApplicationContext createManagementContext() { | ||
GenericApplicationContext managementContext = new GenericApplicationContext(); | ||
managementContext.registerBean(ManagementMessageService.class); | ||
return managementContext; | ||
} | ||
|
||
|
||
/** | ||
* Mimics Spring Boot's AOT support for child management contexts in | ||
* {@code org.springframework.boot.actuate.autoconfigure.web.server.ChildManagementContextInitializer.AotContribution}. | ||
*/ | ||
private static class AotContribution implements BeanRegistrationAotContribution { | ||
|
||
private final GenericApplicationContext managementContext; | ||
|
||
AotContribution(GenericApplicationContext managementContext) { | ||
this.managementContext = managementContext; | ||
} | ||
|
||
@Override | ||
public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) { | ||
GenerationContext managementGenerationContext = generationContext.withName("Management"); | ||
new ApplicationContextAotGenerator().processAheadOfTime(this.managementContext, managementGenerationContext); | ||
} | ||
|
||
} | ||
|
||
} |
Oops, something went wrong.