diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrar.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrar.java index 07e4f8299bdf..bc291a02ec34 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrar.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrar.java @@ -39,11 +39,7 @@ import org.springframework.boot.context.properties.bind.JavaBeanBinder.BeanProperties; import org.springframework.boot.context.properties.bind.JavaBeanBinder.BeanProperty; import org.springframework.core.KotlinDetector; -import org.springframework.core.KotlinReflectionParameterNameDiscoverer; -import org.springframework.core.ParameterNameDiscoverer; -import org.springframework.core.PrioritizedParameterNameDiscoverer; import org.springframework.core.ResolvableType; -import org.springframework.core.StandardReflectionParameterNameDiscoverer; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; @@ -92,12 +88,8 @@ public void registerHints(RuntimeHints hints, ClassLoader classLoader) { * @param hints the hints contributed so far for the deployment unit */ public void registerHints(RuntimeHints hints) { - Set> compiledWithoutParameters = new HashSet<>(); for (Bindable bindable : this.bindables) { - new Processor(bindable, compiledWithoutParameters).process(hints.reflection()); - } - if (!compiledWithoutParameters.isEmpty()) { - throw new MissingParametersCompilerArgumentException(compiledWithoutParameters); + new Processor(bindable).process(hints.reflection()); } } @@ -144,18 +136,7 @@ public static BindableRuntimeHintsRegistrar forBindables(Bindable... bindable /** * Processor used to register the hints. */ - private final class Processor { - - private static final ParameterNameDiscoverer parameterNameDiscoverer; - - static { - PrioritizedParameterNameDiscoverer discoverer = new PrioritizedParameterNameDiscoverer(); - if (KotlinDetector.isKotlinReflectPresent()) { - discoverer.addDiscoverer(new KotlinReflectionParameterNameDiscoverer()); - } - discoverer.addDiscoverer(new StandardReflectionParameterNameDiscoverer()); - parameterNameDiscoverer = discoverer; - } + private static final class Processor { private final Class type; @@ -165,21 +146,17 @@ private final class Processor { private final Set> seen; - private final Set> compiledWithoutParameters; - - Processor(Bindable bindable, Set> compiledWithoutParameters) { - this(bindable, false, new HashSet<>(), compiledWithoutParameters); + Processor(Bindable bindable) { + this(bindable, false, new HashSet<>()); } - private Processor(Bindable bindable, boolean nestedType, Set> seen, - Set> compiledWithoutParameters) { + private Processor(Bindable bindable, boolean nestedType, Set> seen) { this.type = bindable.getType().getRawClass(); this.bindConstructor = (bindable.getBindMethod() != BindMethod.JAVA_BEAN) ? BindConstructorProvider.DEFAULT.getBindConstructor(bindable.getType().resolve(), nestedType) : null; this.bean = JavaBeanBinder.BeanProperties.of(bindable); this.seen = seen; - this.compiledWithoutParameters = compiledWithoutParameters; } void process(ReflectionHints hints) { @@ -198,7 +175,6 @@ else if (this.bean != null && !this.bean.getProperties().isEmpty()) { private void handleConstructor(ReflectionHints hints) { if (this.bindConstructor != null) { - verifyParameterNamesAreAvailable(); if (KotlinDetector.isKotlinType(this.bindConstructor.getDeclaringClass())) { KotlinDelegate.handleConstructor(hints, this.bindConstructor); } @@ -213,13 +189,6 @@ private void handleConstructor(ReflectionHints hints) { .ifPresent((constructor) -> hints.registerConstructor(constructor, ExecutableMode.INVOKE)); } - private void verifyParameterNamesAreAvailable() { - String[] parameterNames = parameterNameDiscoverer.getParameterNames(this.bindConstructor); - if (parameterNames == null) { - this.compiledWithoutParameters.add(this.bindConstructor.getDeclaringClass()); - } - } - private boolean hasNoParameters(Constructor candidate) { return candidate.getParameterCount() == 0; } @@ -268,7 +237,7 @@ else if (isNestedType(propertyName, propertyClass)) { } private void processNested(Class type, ReflectionHints hints) { - new Processor(Bindable.of(type), true, this.seen, this.compiledWithoutParameters).process(hints); + new Processor(Bindable.of(type), true, this.seen).process(hints); } private Class getComponentClass(ResolvableType type) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MissingParametersCompilerArgumentException.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MissingParametersCompilerArgumentException.java deleted file mode 100644 index a8028280af99..000000000000 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MissingParametersCompilerArgumentException.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2012-2022 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.boot.context.properties.bind; - -import java.util.Set; - -/** - * Exception thrown to indicate that a class has not been compiled with - * {@code -parameters}. - * - * @author Andy Wilkinson - */ -class MissingParametersCompilerArgumentException extends RuntimeException { - - MissingParametersCompilerArgumentException(Set> faultyClasses) { - super(message(faultyClasses)); - } - - private static String message(Set> faultyClasses) { - StringBuilder message = new StringBuilder(String.format( - "Constructor binding in a native image requires compilation with -parameters but the following classes were compiled without it:%n")); - for (Class faultyClass : faultyClasses) { - message.append(String.format("\t%s%n", faultyClass.getName())); - } - return message.toString(); - } - -} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrarTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrarTests.java index 5cc460d485a9..6b87bca4365f 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrarTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrarTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -24,6 +24,7 @@ import java.util.Map; import java.util.function.Consumer; +import org.apache.tomcat.jdbc.pool.PoolProperties; import org.junit.jupiter.api.Test; import org.springframework.aot.hint.ExecutableHint; @@ -41,9 +42,11 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.EnvironmentAware; +import org.springframework.core.StandardReflectionParameterNameDiscoverer; import org.springframework.core.env.Environment; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; /** * Tests for {@link BindableRuntimeHintsRegistrar}. @@ -279,6 +282,16 @@ void registerHintsWhenHasComplexNestedProperties() { .satisfies(javaBeanBinding(ComplexNestedProperties.class, "getSimple")); } + @Test + void registerHintsDoesNotThrowWhenParameterInformationForConstructorBindingIsNotAvailable() + throws NoSuchMethodException, SecurityException { + Constructor constructor = PoolProperties.InterceptorProperty.class.getConstructor(String.class, + String.class); + String[] parameterNames = new StandardReflectionParameterNameDiscoverer().getParameterNames(constructor); + assertThat(parameterNames).isNull(); + assertThatNoException().isThrownBy(() -> registerHints(PoolProperties.class)); + } + private Consumer javaBeanBinding(Class type, String... expectedMethods) { return javaBeanBinding(type, type.getDeclaredConstructors()[0], expectedMethods); }