Skip to content

In a native image, configuration property binding fails when the target has package-private getters and setters #35397

@wilkinsona

Description

@wilkinsona

BindableRuntimeHintsRegistrar does not generate reflection hints to allow package-private getters and setters to be invoked. Previously, this resulted in such methods being silently ignored. It has now started failing due to Framework adding a query all methods hint for every bean. This allows the binder to find the package-private methods but a failure then occurs when it tries to invoke them.

One example of this failing can be found in Spring Cloud:

Caused by: com.oracle.svm.core.jdk.UnsupportedFeatureError: Runtime reflection is not supported for java.util.Map org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscoveryProperties.getInstances()
	at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:89) ~[na:na]
	at java.base@17.0.5/java.lang.reflect.Method.acquireMethodAccessor(Method.java:71) ~[cloud-gateway:na]
	at java.base@17.0.5/java.lang.reflect.Method.invoke(Method.java:566) ~[cloud-gateway:na]
	at org.springframework.boot.context.properties.bind.JavaBeanBinder$BeanProperty.lambda$getValue$0(JavaBeanBinder.java:357) ~[na:na]
	at org.springframework.boot.context.properties.bind.MapBinder.getExistingIfPossible(MapBinder.java:110) ~[na:na]

The getters and setters on SimpleReactiveDiscoveryProperties look like this:

	public Flux<ServiceInstance> getInstances(String service) {
		return Flux.fromIterable(instances.getOrDefault(service, emptyList()));
	}

	Map<String, List<DefaultServiceInstance>> getInstances() {
		return instances;
	}

	public void setInstances(Map<String, List<DefaultServiceInstance>> instances) {
		this.instances = instances;
	}

	public DefaultServiceInstance getLocal() {
		return this.local;
	}

	public int getOrder() {
		return this.order;
	}

	public void setOrder(int order) {
		this.order = order;
	}

The map binder tries to call getInstances() so that it can merge any existing values with those being bound. This call now fails. Previously, the getInstances() method would not have been found so any existing values would have been overwritten.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions