Skip to content

Commit 9b0253e

Browse files
scordiosbrannen
andcommitted
Skip runtime hint registration for constraint with missing dependencies
Prior to this commit, AOT processing for bean validation failed with a NoClassDefFoundError for constraints with missing dependencies. With this commit, the processing no longer fails, and a warning is logged instead. See gh-33940 Closes gh-33949 Co-authored-by: Sam Brannen <sam.brannen@broadcom.com>
1 parent f3753e6 commit 9b0253e

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

spring-context/src/main/java/org/springframework/validation/beanvalidation/BeanValidationBeanRegistrationAotProcessor.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -127,18 +127,19 @@ private static void processAheadOfTime(Class<?> clazz, Set<Class<?>> visitedClas
127127
try {
128128
descriptor = validator.getConstraintsForClass(clazz);
129129
}
130-
catch (RuntimeException ex) {
130+
catch (RuntimeException | LinkageError ex) {
131+
String className = clazz.getName();
131132
if (KotlinDetector.isKotlinType(clazz) && ex instanceof ArrayIndexOutOfBoundsException) {
132133
// See https://hibernate.atlassian.net/browse/HV-1796 and https://youtrack.jetbrains.com/issue/KT-40857
133-
logger.warn("Skipping validation constraint hint inference for class " + clazz +
134+
logger.warn("Skipping validation constraint hint inference for class " + className +
134135
" due to an ArrayIndexOutOfBoundsException at validator level");
135136
}
136137
else if (ex instanceof TypeNotPresentException) {
137138
logger.debug("Skipping validation constraint hint inference for class " +
138-
clazz + " due to a TypeNotPresentException at validator level: " + ex.getMessage());
139+
className + " due to a TypeNotPresentException at validator level: " + ex.getMessage());
139140
}
140141
else {
141-
logger.warn("Skipping validation constraint hint inference for class " + clazz, ex);
142+
logger.warn("Skipping validation constraint hint inference for class " + className, ex);
142143
}
143144
return;
144145
}

spring-context/src/test/java/org/springframework/validation/beanvalidation/BeanValidationBeanRegistrationAotProcessorTests.java

+36
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
4545
import org.springframework.beans.factory.support.RegisteredBean;
4646
import org.springframework.beans.factory.support.RootBeanDefinition;
47+
import org.springframework.core.OverridingClassLoader;
4748
import org.springframework.lang.Nullable;
4849

4950
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
@@ -134,6 +135,14 @@ void shouldProcessRecursiveGenericsWithoutInfiniteRecursion(Class<?> beanClass)
134135
.withMemberCategory(MemberCategory.DECLARED_FIELDS)).accepts(this.generationContext.getRuntimeHints());
135136
}
136137

138+
@Test // gh-33940
139+
void shouldSkipConstraintWithMissingDependency() throws Exception {
140+
FilteringClassLoader classLoader = new FilteringClassLoader(getClass().getClassLoader());
141+
Class<?> beanClass = classLoader.loadClass(ConstraintWithMissingDependency.class.getName());
142+
process(beanClass);
143+
assertThat(this.generationContext.getRuntimeHints().reflection().typeHints()).isEmpty();
144+
}
145+
137146
private void process(Class<?> beanClass) {
138147
BeanRegistrationAotContribution contribution = createContribution(beanClass);
139148
if (contribution != null) {
@@ -269,4 +278,31 @@ static class BeanWithRecursiveOptional {
269278
Optional<BeanWithRecursiveOptional> optional;
270279
}
271280

281+
static class ConstraintWithMissingDependency {
282+
283+
private final Filtered filtered = new Filtered();
284+
}
285+
286+
static class Filtered {}
287+
288+
static class FilteringClassLoader extends OverridingClassLoader {
289+
290+
FilteringClassLoader(ClassLoader parent) {
291+
super(parent);
292+
}
293+
294+
@Override
295+
protected boolean isEligibleForOverriding(String className) {
296+
return className.startsWith(BeanValidationBeanRegistrationAotProcessorTests.class.getName());
297+
}
298+
299+
@Override
300+
protected Class<?> loadClassForOverriding(String name) throws ClassNotFoundException {
301+
if (name.contains("Filtered")) {
302+
throw new NoClassDefFoundError(name);
303+
}
304+
return super.loadClassForOverriding(name);
305+
}
306+
}
307+
272308
}

0 commit comments

Comments
 (0)