Skip to content

ShellAvailability target not registered with AOT processing #747

Closed
@dashaun

Description

@dashaun

I noticed this when upgrading to Spring Boot 3.0.6 or 3.0.7, the build process works, but when I run the native image it fails.

I'm using sdkman installed GraalVM with identifier 22.3.2.r17-grl

Steps to reproduce:

#Create a simple Spring Shell application with Spring Initializr using dependencies native,spring-shell
curl https://start.spring.io/starter.tgz -d dependencies=native,spring-shell -d javaVersion=17 -d bootVersion=3.0.7 -d type=maven-project | tar -xzf - || exit

Add a custom prompt component to the class:

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

}

@ShellComponent
class BugExample {
	private final static File POM_FILE = new File("./pom.xml");

	@ShellMethod("Hello")
	@ShellMethodAvailability("pomFile")
	public String hello(@ShellOption(defaultValue = "World") String version) {

		return String.format("Hello, %s", version);
	}

	public Availability pomFile() {
		return POM_FILE.exists() ? Availability.available()
				: Availability.unavailable(String.format("%s does not exist", POM_FILE.getName()));
	}
	
}

Optionally, replace the application.properties with application.yaml

logging:
  level:
    root: 'off'
    
spring:
  main:
    banner-mode: 'off'
    web-application-type: 'NONE'
  shell:
    history:
      enabled: 'false'

Build the native image:

./mvnw -Pnative clean native:compile -DskipTests

Run the image:

./target/demo help

With 3.0.5 I get the expected result

This is the result:

Exception in thread "main" com.oracle.svm.core.jdk.UnsupportedFeatureError: Runtime reflection is not supported for public org.springframework.shell.Availability com.example.demo.BugExample.pomFile()
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:89)
        at java.base@17.0.7/java.lang.reflect.Method.acquireMethodAccessor(Method.java:76)
        at java.base@17.0.7/java.lang.reflect.Method.invoke(Method.java:566)
        at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:281)
        at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:265)
        at org.springframework.shell.standard.StandardMethodTargetRegistrar.lambda$findAvailabilityIndicator$8(StandardMethodTargetRegistrar.java:331)
        at org.springframework.shell.command.CommandRegistration$DefaultCommandRegistration.getAvailability(CommandRegistration.java:1237)
        at org.springframework.shell.standard.commands.CommandInfoModel.of(CommandInfoModel.java:80)
        at org.springframework.shell.standard.commands.GroupsInfoModel.lambda$of$3(GroupsInfoModel.java:74)
        at java.base@17.0.7/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
        at java.base@17.0.7/java.util.HashMap$EntrySpliterator.forEachRemaining(HashMap.java:1850)
        at java.base@17.0.7/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
        at java.base@17.0.7/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
        at java.base@17.0.7/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
        at java.base@17.0.7/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.base@17.0.7/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
        at org.springframework.shell.standard.commands.GroupsInfoModel.lambda$of$4(GroupsInfoModel.java:75)
        at java.base@17.0.7/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
        at java.base@17.0.7/java.util.TreeMap$EntrySpliterator.forEachRemaining(TreeMap.java:3287)
        at java.base@17.0.7/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
        at java.base@17.0.7/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
        at java.base@17.0.7/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
        at java.base@17.0.7/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.base@17.0.7/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
        at org.springframework.shell.standard.commands.GroupsInfoModel.of(GroupsInfoModel.java:78)
        at org.springframework.shell.standard.commands.Help.renderCommands(Help.java:129)
        at org.springframework.shell.standard.commands.Help.help(Help.java:84)
        at java.base@17.0.7/java.lang.reflect.Method.invoke(Method.java:568)
        at org.springframework.shell.command.invocation.InvocableShellMethod.doInvoke(InvocableShellMethod.java:306)
        at org.springframework.shell.command.invocation.InvocableShellMethod.invoke(InvocableShellMethod.java:232)
        at org.springframework.shell.command.CommandExecution$DefaultCommandExecution.evaluate(CommandExecution.java:222)
        at org.springframework.shell.Shell.evaluate(Shell.java:246)
        at org.springframework.shell.Shell.run(Shell.java:158)
        at org.springframework.shell.jline.NonInteractiveShellRunner.run(NonInteractiveShellRunner.java:129)
        at org.springframework.shell.DefaultShellApplicationRunner.run(DefaultShellApplicationRunner.java:65)
        at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:760)
        at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:750)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:317)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1304)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1293)
        at com.example.demo.DemoApplication.main(DemoApplication.java:17)

I've created an example repository here.

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