Skip to content

Commit 61980df

Browse files
committed
Update SpringBootJoranConfigurator to use proper GraalVM format for inner class
Prior to this commit, the generated name for inner class had a wrong format <package>.<parent>.<child> (canonical name). GraalVM expects $ to separate the parent from the inner class. This commit updates SpringBootJoranConfigurator to generate an appropriate format for a class name. Specifically, an inner class should be separated by a dollar sign, not a dot. See spring-projectsgh-44016 Signed-off-by: Dmytro Nosan <[email protected]>
1 parent c09c454 commit 61980df

File tree

2 files changed

+43
-10
lines changed

2 files changed

+43
-10
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringBootJoranConfigurator.java

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -231,12 +231,12 @@ private Set<Class<? extends Serializable>> serializationTypes(Model model) {
231231
return modelClasses;
232232
}
233233

234-
private Set<String> reflectionTypes(Model model) {
234+
private Set<Class<?>> reflectionTypes(Model model) {
235235
return reflectionTypes(model, () -> null);
236236
}
237237

238-
private Set<String> reflectionTypes(Model model, Supplier<Object> parent) {
239-
Set<String> reflectionTypes = new HashSet<>();
238+
private Set<Class<?>> reflectionTypes(Model model, Supplier<Object> parent) {
239+
Set<Class<?>> reflectionTypes = new HashSet<>();
240240
Class<?> componentType = determineType(model, parent);
241241
if (componentType != null) {
242242
processComponent(componentType, reflectionTypes);
@@ -306,23 +306,22 @@ private Object instantiate(Class<?> type) {
306306
}
307307
}
308308

309-
private void processComponent(Class<?> componentType, Set<String> reflectionTypes) {
309+
private void processComponent(Class<?> componentType, Set<Class<?>> reflectionTypes) {
310310
BeanDescription beanDescription = this.modelInterpretationContext.getBeanDescriptionCache()
311311
.getBeanDescription(componentType);
312312
reflectionTypes.addAll(parameterTypesNames(beanDescription.getPropertyNameToAdder().values()));
313313
reflectionTypes.addAll(parameterTypesNames(beanDescription.getPropertyNameToSetter().values()));
314-
reflectionTypes.add(componentType.getCanonicalName());
314+
reflectionTypes.add(componentType);
315315
}
316316

317-
private Collection<String> parameterTypesNames(Collection<Method> methods) {
317+
private Collection<Class<?>> parameterTypesNames(Collection<Method> methods) {
318318
return methods.stream()
319319
.filter((method) -> !method.getDeclaringClass().equals(ContextAware.class)
320320
&& !method.getDeclaringClass().equals(ContextAwareBase.class))
321321
.map(Method::getParameterTypes)
322322
.flatMap(Stream::of)
323323
.filter((type) -> !type.isPrimitive() && !type.equals(String.class))
324324
.map((type) -> type.isArray() ? type.getComponentType() : type)
325-
.map(Class::getName)
326325
.toList();
327326
}
328327

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackConfigurationAotContributionTests.java

+36-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
2323
import java.util.ArrayList;
2424
import java.util.List;
2525
import java.util.Map;
26+
import java.util.Optional;
2627
import java.util.Properties;
2728
import java.util.function.Consumer;
2829
import java.util.function.Predicate;
@@ -54,6 +55,7 @@
5455
import org.springframework.aot.hint.MemberCategory;
5556
import org.springframework.aot.hint.RuntimeHints;
5657
import org.springframework.aot.hint.SerializationHints;
58+
import org.springframework.aot.hint.TypeHint;
5759
import org.springframework.aot.hint.TypeReference;
5860
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
5961
import org.springframework.aot.test.generate.TestGenerationContext;
@@ -214,6 +216,14 @@ void typeFromParentsDefaultClassAnnotatedSetterIsRegisteredForReflection() {
214216
.accepts(generationContext.getRuntimeHints());
215217
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Implementation.class))
216218
.accepts(generationContext.getRuntimeHints());
219+
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(BaseImplementation.Details.class))
220+
.accepts(generationContext.getRuntimeHints());
221+
222+
assertThat(hasValidNestedTypeName(OuterWithDefaultClass.class)).accepts(generationContext.getRuntimeHints());
223+
assertThat(hasValidNestedTypeName(Implementation.class)).accepts(generationContext.getRuntimeHints());
224+
assertThat(hasValidNestedTypeName(BaseImplementation.Details.class))
225+
.accepts(generationContext.getRuntimeHints());
226+
217227
}
218228

219229
@Test
@@ -250,6 +260,16 @@ private Predicate<RuntimeHints> invokePublicConstructorsAndInspectAndInvokePubli
250260
MemberCategory.INVOKE_PUBLIC_METHODS);
251261
}
252262

263+
private Predicate<RuntimeHints> hasValidNestedTypeName(Class<?> type) {
264+
return (runtimeHints) -> {
265+
String name = Optional.ofNullable(runtimeHints.reflection().getTypeHint(type))
266+
.map(TypeHint::getType)
267+
.map(TypeReference::getName)
268+
.orElse("");
269+
return name.equals(type.getEnclosingClass().getName() + "$" + type.getSimpleName());
270+
};
271+
}
272+
253273
private Properties load(InputStreamSource source) {
254274
try (InputStream inputStream = source.getInputStream()) {
255275
Properties properties = new Properties();
@@ -323,7 +343,21 @@ public void setContract(Contract contract) {
323343

324344
}
325345

326-
public static class Implementation implements Contract {
346+
public static class BaseImplementation implements Contract {
347+
348+
private Details details;
349+
350+
public void setDetails(Details details) {
351+
this.details = details;
352+
}
353+
354+
public static final class Details {
355+
356+
}
357+
358+
}
359+
360+
public static class Implementation extends BaseImplementation {
327361

328362
}
329363

0 commit comments

Comments
 (0)