Skip to content

Commit

Permalink
Remove detection of missing parameter information
Browse files Browse the repository at this point in the history
There are some cases where false positives of the detection prevent
compiling an application to native which otherwise would run perfectly
fine in a native image.

Closes gh-40051
  • Loading branch information
mhalbritter committed Apr 23, 2024
1 parent 3e5d6c9 commit b50b0e8
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 80 deletions.
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Class<?>> 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());
}
}

Expand Down Expand Up @@ -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;

Expand All @@ -165,21 +146,17 @@ private final class Processor {

private final Set<Class<?>> seen;

private final Set<Class<?>> compiledWithoutParameters;

Processor(Bindable<?> bindable, Set<Class<?>> compiledWithoutParameters) {
this(bindable, false, new HashSet<>(), compiledWithoutParameters);
Processor(Bindable<?> bindable) {
this(bindable, false, new HashSet<>());
}

private Processor(Bindable<?> bindable, boolean nestedType, Set<Class<?>> seen,
Set<Class<?>> compiledWithoutParameters) {
private Processor(Bindable<?> bindable, boolean nestedType, Set<Class<?>> 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) {
Expand All @@ -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);
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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) {
Expand Down

This file was deleted.

@@ -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.
Expand All @@ -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;
Expand All @@ -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}.
Expand Down Expand Up @@ -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<TypeHint> javaBeanBinding(Class<?> type, String... expectedMethods) {
return javaBeanBinding(type, type.getDeclaredConstructors()[0], expectedMethods);
}
Expand Down

0 comments on commit b50b0e8

Please sign in to comment.