Skip to content

Commit 2518f9f

Browse files
committed
Update SpringBootJoranConfigurator to use proper GraalVM format
Before this commit, the generated name for the 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 gh-44016 Signed-off-by: Dmytro Nosan <[email protected]>
1 parent c09c454 commit 2518f9f

File tree

2 files changed

+65
-10
lines changed

2 files changed

+65
-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

+58-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;
@@ -158,6 +160,11 @@ void componentModelClassAndSetterParametersAreRegisteredForReflection() {
158160
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(
159161
TimeBasedFileNamingAndTriggeringPolicy.class))
160162
.accepts(generationContext.getRuntimeHints());
163+
164+
assertThat(hasValidTypeName(SizeAndTimeBasedRollingPolicy.class)).accepts(generationContext.getRuntimeHints());
165+
assertThat(hasValidTypeName(FileSize.class)).accepts(generationContext.getRuntimeHints());
166+
assertThat(hasValidTypeName(FileAppender.class)).accepts(generationContext.getRuntimeHints());
167+
161168
}
162169

163170
@Test
@@ -173,6 +180,10 @@ void implicitModelClassAndSetterParametersAreRegisteredForReflection() {
173180
.accepts(generationContext.getRuntimeHints());
174181
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Charset.class))
175182
.accepts(generationContext.getRuntimeHints());
183+
184+
assertThat(hasValidTypeName(PatternLayoutEncoder.class)).accepts(generationContext.getRuntimeHints());
185+
assertThat(hasValidTypeName(Layout.class)).accepts(generationContext.getRuntimeHints());
186+
assertThat(hasValidTypeName(Charset.class)).accepts(generationContext.getRuntimeHints());
176187
}
177188

178189
@Test
@@ -186,6 +197,8 @@ void componentModelReferencingImportedClassNameIsRegisteredForReflection() {
186197
TestGenerationContext generationContext = applyContribution(model);
187198
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(SizeAndTimeBasedRollingPolicy.class))
188199
.accepts(generationContext.getRuntimeHints());
200+
201+
assertThat(hasValidTypeName(SizeAndTimeBasedRollingPolicy.class)).accepts(generationContext.getRuntimeHints());
189202
}
190203

191204
@Test
@@ -200,6 +213,10 @@ void typeFromParentsSetterIsRegisteredForReflection() {
200213
.accepts(generationContext.getRuntimeHints());
201214
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Implementation.class))
202215
.accepts(generationContext.getRuntimeHints());
216+
217+
assertThat(hasValidTypeName(Outer.class)).accepts(generationContext.getRuntimeHints());
218+
assertThat(hasValidTypeName(Implementation.class)).accepts(generationContext.getRuntimeHints());
219+
203220
}
204221

205222
@Test
@@ -214,6 +231,13 @@ void typeFromParentsDefaultClassAnnotatedSetterIsRegisteredForReflection() {
214231
.accepts(generationContext.getRuntimeHints());
215232
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Implementation.class))
216233
.accepts(generationContext.getRuntimeHints());
234+
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(BaseImplementation.Details.class))
235+
.accepts(generationContext.getRuntimeHints());
236+
237+
assertThat(hasValidTypeName(OuterWithDefaultClass.class)).accepts(generationContext.getRuntimeHints());
238+
assertThat(hasValidTypeName(Implementation.class)).accepts(generationContext.getRuntimeHints());
239+
assertThat(hasValidTypeName(BaseImplementation.Details.class)).accepts(generationContext.getRuntimeHints());
240+
217241
}
218242

219243
@Test
@@ -223,6 +247,10 @@ void componentTypesOfArraysAreRegisteredForReflection() {
223247
TestGenerationContext generationContext = applyContribution(component);
224248
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(InetSocketAddress.class))
225249
.accepts(generationContext.getRuntimeHints());
250+
251+
assertThat(hasValidTypeName(InetSocketAddress.class)).accepts(generationContext.getRuntimeHints());
252+
assertThat(hasValidTypeName(ArrayParameters.class)).accepts(generationContext.getRuntimeHints());
253+
226254
}
227255

228256
@Test
@@ -235,6 +263,10 @@ void placeholdersInComponentClassAttributeAreReplaced() {
235263
.accepts(generationContext.getRuntimeHints());
236264
assertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Implementation.class))
237265
.accepts(generationContext.getRuntimeHints());
266+
267+
assertThat(hasValidTypeName(Outer.class)).accepts(generationContext.getRuntimeHints());
268+
assertThat(hasValidTypeName(Implementation.class)).accepts(generationContext.getRuntimeHints());
269+
238270
}
239271

240272
private Predicate<RuntimeHints> invokePublicConstructorsOf(String name) {
@@ -250,6 +282,16 @@ private Predicate<RuntimeHints> invokePublicConstructorsAndInspectAndInvokePubli
250282
MemberCategory.INVOKE_PUBLIC_METHODS);
251283
}
252284

285+
private Predicate<RuntimeHints> hasValidTypeName(Class<?> type) {
286+
return (runtimeHints) -> {
287+
String name = Optional.ofNullable(runtimeHints.reflection().getTypeHint(type))
288+
.map(TypeHint::getType)
289+
.map(TypeReference::getName)
290+
.orElse("");
291+
return type.getTypeName().equals(name);
292+
};
293+
}
294+
253295
private Properties load(InputStreamSource source) {
254296
try (InputStream inputStream = source.getInputStream()) {
255297
Properties properties = new Properties();
@@ -323,7 +365,21 @@ public void setContract(Contract contract) {
323365

324366
}
325367

326-
public static class Implementation implements Contract {
368+
public static class BaseImplementation implements Contract {
369+
370+
private Details details;
371+
372+
public void setDetails(Details details) {
373+
this.details = details;
374+
}
375+
376+
public static final class Details {
377+
378+
}
379+
380+
}
381+
382+
public static class Implementation extends BaseImplementation {
327383

328384
}
329385

0 commit comments

Comments
 (0)