LogbackConfigurationAotContributionTests Class — spring-boot Architecture
Architecture documentation for the LogbackConfigurationAotContributionTests class in LogbackConfigurationAotContributionTests.java from the spring-boot codebase.
Entity Profile
Relationship Graph
Source Code
core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackConfigurationAotContributionTests.java lines 77–389
class LogbackConfigurationAotContributionTests {
@BeforeEach
@AfterEach
void prepare() {
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
context.reset();
}
@Test
void contributionOfBasicModel() {
TestGenerationContext generationContext = applyContribution(new Model());
InMemoryGeneratedFiles generatedFiles = generationContext.getGeneratedFiles();
assertThat(generatedFiles).has(resource("META-INF/spring/logback-model"));
assertThat(generatedFiles).has(resource("META-INF/spring/logback-pattern-rules"));
SerializationHints serializationHints = generationContext.getRuntimeHints().serialization();
assertThat(serializationHints.javaSerializationHints()
.map(JavaSerializationHint::getType)
.map(TypeReference::getName))
.containsExactlyInAnyOrder(namesOf(Model.class, ArrayList.class, Boolean.class, Integer.class));
assertThat(generationContext.getRuntimeHints().reflection().typeHints()).isEmpty();
InputStreamSource generatedFile = generatedFiles.getGeneratedFile(Kind.RESOURCE,
"META-INF/spring/logback-pattern-rules");
assertThat(generatedFile).isNotNull();
Properties patternRules = load(generatedFile);
assertThat(patternRules).isEmpty();
}
@Test
void contributionOfBasicModelThatMatchesExistingModel() {
TestGenerationContext generationContext = new TestGenerationContext();
Model model = new Model();
applyContribution(model, generationContext);
applyContribution(model, generationContext);
InMemoryGeneratedFiles generatedFiles = generationContext.getGeneratedFiles();
assertThat(generatedFiles).has(resource("META-INF/spring/logback-model"));
assertThat(generatedFiles).has(resource("META-INF/spring/logback-pattern-rules"));
SerializationHints serializationHints = generationContext.getRuntimeHints().serialization();
assertThat(serializationHints.javaSerializationHints()
.map(JavaSerializationHint::getType)
.map(TypeReference::getName))
.containsExactlyInAnyOrder(namesOf(Model.class, ArrayList.class, Boolean.class, Integer.class));
assertThat(generationContext.getRuntimeHints().reflection().typeHints()).isEmpty();
InputStreamSource generatedFile = generatedFiles.getGeneratedFile(Kind.RESOURCE,
"META-INF/spring/logback-pattern-rules");
assertThat(generatedFile).isNotNull();
Properties patternRules = load(generatedFile);
assertThat(patternRules).isEmpty();
}
@Test
void contributionOfBasicModelThatDiffersFromExistingModelThrows() {
TestGenerationContext generationContext = new TestGenerationContext();
applyContribution(new Model(), generationContext);
Model model = new Model();
model.addSubModel(new RootLoggerModel());
assertThatIllegalStateException().isThrownBy(() -> applyContribution(model, generationContext))
.withMessage("Logging configuration differs from the configuration that has already been written. "
+ "Update your logging configuration so that it is the same for each context");
}
@Test
void patternRulesAreStoredAndRegisteredForReflection() {
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
context.putObject(CoreConstants.PATTERN_RULE_REGISTRY,
Map.of("a", "com.example.Alpha", "b", "com.example.Bravo"));
TestGenerationContext generationContext = applyContribution(new Model());
assertThat(invokePublicConstructorsOf("com.example.Alpha")).accepts(generationContext.getRuntimeHints());
assertThat(invokePublicConstructorsOf("com.example.Bravo")).accepts(generationContext.getRuntimeHints());
InputStreamSource generatedFile = generationContext.getGeneratedFiles()
.getGeneratedFile(Kind.RESOURCE, "META-INF/spring/logback-pattern-rules");
assertThat(generatedFile).isNotNull();
Properties patternRules = load(generatedFile);
assertThat(patternRules).hasSize(2);
assertThat(patternRules).containsEntry("a", "com.example.Alpha");
assertThat(patternRules).containsEntry("b", "com.example.Bravo");
}
@Test
void componentModelClassAndSetterParametersAreRegisteredForReflection() {
ComponentModel component = new ComponentModel();
component.setClassName(SizeAndTimeBasedRollingPolicy.class.getName());
Model model = new Model();
model.getSubModels().add(component);
TestGenerationContext generationContext = applyContribution(model);
RuntimeHints runtimeHints = generationContext.getRuntimeHints();
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(SizeAndTimeBasedRollingPolicy.class))
.accepts(runtimeHints);
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(FileAppender.class))
.accepts(runtimeHints);
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(FileSize.class)).accepts(runtimeHints);
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(
TimeBasedFileNamingAndTriggeringPolicy.class))
.accepts(runtimeHints);
assertThat(runtimeHints).satisfies(hasValidTypeName(SizeAndTimeBasedRollingPolicy.class));
assertThat(runtimeHints).satisfies(hasValidTypeName(FileSize.class));
assertThat(runtimeHints).satisfies(hasValidTypeName(FileAppender.class));
}
@Test
void implicitModelClassAndSetterParametersAreRegisteredForReflection() {
ImplicitModel implicit = new ImplicitModel();
implicit.setTag("encoder");
Model model = new Model();
model.getSubModels().add(implicit);
TestGenerationContext generationContext = applyContribution(model);
RuntimeHints runtimeHints = generationContext.getRuntimeHints();
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(PatternLayoutEncoder.class))
.accepts(runtimeHints);
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Layout.class)).accepts(runtimeHints);
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Charset.class)).accepts(runtimeHints);
assertThat(runtimeHints).satisfies(hasValidTypeName(PatternLayoutEncoder.class));
assertThat(runtimeHints).satisfies(hasValidTypeName(Layout.class));
assertThat(runtimeHints).satisfies(hasValidTypeName(Charset.class));
}
@Test
void componentModelReferencingImportedClassNameIsRegisteredForReflection() {
ImportModel importModel = new ImportModel();
importModel.setClassName(SizeAndTimeBasedRollingPolicy.class.getName());
ComponentModel component = new ComponentModel();
component.setClassName(SizeAndTimeBasedRollingPolicy.class.getSimpleName());
Model model = new Model();
model.getSubModels().addAll(List.of(importModel, component));
TestGenerationContext generationContext = applyContribution(model);
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(SizeAndTimeBasedRollingPolicy.class))
.accepts(generationContext.getRuntimeHints());
assertThat(generationContext.getRuntimeHints())
.satisfies(hasValidTypeName(SizeAndTimeBasedRollingPolicy.class));
}
@Test
void typeFromParentsSetterIsRegisteredForReflection() {
ImplicitModel implementation = new ImplicitModel();
implementation.setTag("implementation");
ComponentModel component = new ComponentModel();
component.setClassName(Outer.class.getName());
component.getSubModels().add(implementation);
TestGenerationContext generationContext = applyContribution(component);
RuntimeHints runtimeHints = generationContext.getRuntimeHints();
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Outer.class)).accepts(runtimeHints);
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Implementation.class))
.accepts(runtimeHints);
assertThat(runtimeHints).satisfies(hasValidTypeName(Outer.class));
assertThat(runtimeHints).satisfies(hasValidTypeName(Implementation.class));
}
@Test
void typeFromParentsDefaultClassAnnotatedSetterIsRegisteredForReflection() {
ImplicitModel contract = new ImplicitModel();
contract.setTag("contract");
ComponentModel component = new ComponentModel();
component.setClassName(OuterWithDefaultClass.class.getName());
component.getSubModels().add(contract);
TestGenerationContext generationContext = applyContribution(component);
RuntimeHints runtimeHints = generationContext.getRuntimeHints();
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(OuterWithDefaultClass.class))
.accepts(runtimeHints);
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Implementation.class))
.accepts(runtimeHints);
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(BaseImplementation.Details.class))
.accepts(runtimeHints);
assertThat(runtimeHints).satisfies(hasValidTypeName(OuterWithDefaultClass.class));
assertThat(runtimeHints).satisfies(hasValidTypeName(Implementation.class));
assertThat(runtimeHints).satisfies(hasValidTypeName(BaseImplementation.Details.class));
}
@Test
void componentTypesOfArraysAreRegisteredForReflection() {
ComponentModel component = new ComponentModel();
component.setClassName(ArrayParameters.class.getName());
TestGenerationContext generationContext = applyContribution(component);
RuntimeHints runtimeHints = generationContext.getRuntimeHints();
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(InetSocketAddress.class))
.accepts(runtimeHints);
assertThat(runtimeHints).satisfies(hasValidTypeName(InetSocketAddress.class));
assertThat(runtimeHints).satisfies(hasValidTypeName(ArrayParameters.class));
}
@Test
void placeholdersInComponentClassAttributeAreReplaced() {
ComponentModel component = new ComponentModel();
component.setClassName("${VARIABLE_CLASS_NAME}");
TestGenerationContext generationContext = applyContribution(component,
(context) -> context.putProperty("VARIABLE_CLASS_NAME", Outer.class.getName()));
RuntimeHints runtimeHints = generationContext.getRuntimeHints();
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Outer.class)).accepts(runtimeHints);
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Implementation.class))
.accepts(runtimeHints);
assertThat(runtimeHints).satisfies(hasValidTypeName(Outer.class));
assertThat(runtimeHints).satisfies(hasValidTypeName(Implementation.class));
}
private Predicate<RuntimeHints> invokePublicConstructorsOf(String name) {
return RuntimeHintsPredicates.reflection()
.onType(TypeReference.of(name))
.withMemberCategory(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
}
private Predicate<RuntimeHints> invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Class<?> type) {
return RuntimeHintsPredicates.reflection()
.onType(TypeReference.of(type))
.withMemberCategories(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS);
}
private Consumer<RuntimeHints> hasValidTypeName(Class<?> type) {
return (runtimeHints) -> assertThat(runtimeHints.reflection().getTypeHint(type)).extracting(TypeHint::getType)
.extracting(TypeReference::getName)
.isEqualTo(type.getName());
}
private Properties load(InputStreamSource source) {
try (InputStream inputStream = source.getInputStream()) {
Properties properties = new Properties();
properties.load(inputStream);
return properties;
}
catch (IOException ex) {
throw new RuntimeException(ex);
}
}
private Condition<InMemoryGeneratedFiles> resource(String name) {
return new Condition<>((files) -> files.getGeneratedFile(Kind.RESOURCE, name) != null,
"has a resource named '%s'", name);
}
private TestGenerationContext applyContribution(Model model) {
return this.applyContribution(model, (context) -> {
});
}
private TestGenerationContext applyContribution(Model model, Consumer<LoggerContext> contextCustomizer) {
TestGenerationContext generationContext = new TestGenerationContext();
applyContribution(model, contextCustomizer, generationContext);
return generationContext;
}
private void applyContribution(Model model, TestGenerationContext generationContext) {
applyContribution(model, (context) -> {
}, generationContext);
}
private void applyContribution(Model model, Consumer<LoggerContext> contextCustomizer,
TestGenerationContext generationContext) {
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
contextCustomizer.accept(context);
SpringBootJoranConfigurator configurator = new SpringBootJoranConfigurator(
new LoggingInitializationContext(null));
configurator.setContext(context);
withSystemProperty(AbstractAotProcessor.AOT_PROCESSING, "true", () -> configurator.processModel(model));
LogbackConfigurationAotContribution contribution = (LogbackConfigurationAotContribution) context
.getObject(BeanFactoryInitializationAotContribution.class.getName());
contribution.applyTo(generationContext, mock(BeanFactoryInitializationCode.class));
}
private String[] namesOf(Class<?>... types) {
return Stream.of(types).map(Class::getName).toArray(String[]::new);
}
private void withSystemProperty(String name, String value, Runnable action) {
System.setProperty(name, value);
try {
action.run();
}
finally {
System.clearProperty(name);
}
}
public static class Outer {
public void setImplementation(Implementation implementation) {
}
}
public static class OuterWithDefaultClass {
@DefaultClass(Implementation.class)
public void setContract(Contract contract) {
}
}
public static class BaseImplementation implements Contract {
public void setDetails(Details details) {
}
public static final class Details {
}
}
public static class Implementation extends BaseImplementation {
}
public interface Contract {
}
public static class ArrayParameters {
public void addDestinations(InetSocketAddress... addresses) {
}
}
}
Domain
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free