Skip to content

ShellAvailability target not registered with AOT processing #747

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
dashaun opened this issue May 21, 2023 · 3 comments
Closed

ShellAvailability target not registered with AOT processing #747

dashaun opened this issue May 21, 2023 · 3 comments
Labels
branch/3.0.x Issue for a branch for/backport For backporting type/bug Is a bug report
Milestone

Comments

@dashaun
Copy link

dashaun commented May 21, 2023

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 [email protected]/java.lang.reflect.Method.acquireMethodAccessor(Method.java:76)
        at [email protected]/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 [email protected]/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
        at [email protected]/java.util.HashMap$EntrySpliterator.forEachRemaining(HashMap.java:1850)
        at [email protected]/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
        at [email protected]/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
        at [email protected]/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
        at [email protected]/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at [email protected]/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
        at org.springframework.shell.standard.commands.GroupsInfoModel.lambda$of$4(GroupsInfoModel.java:75)
        at [email protected]/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
        at [email protected]/java.util.TreeMap$EntrySpliterator.forEachRemaining(TreeMap.java:3287)
        at [email protected]/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
        at [email protected]/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
        at [email protected]/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
        at [email protected]/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at [email protected]/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 [email protected]/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.

@github-actions github-actions bot added the status/need-triage Team needs to triage and take a first look label May 21, 2023
dashaun added a commit to dashaun/spring-shell-bug that referenced this issue May 21, 2023
@dashaun
Copy link
Author

dashaun commented May 21, 2023

As I was creating the issue, its something related to the @ShellAvailability

@dashaun dashaun changed the title AOT processing results in broken build since Spring Boot 3.0.6 AOT processing with ShellAvailability results in broken build since Spring Boot 3.0.6 May 21, 2023
@jvalkeal
Copy link
Contributor

Thank reporting this. I'll take a look.

@jvalkeal
Copy link
Contributor

Workaround is to give a hint like:

	@Reflective
	public Availability pomFile() {

On a shell level we need to add integration to native side so that these are automatically discovered and registered.

@jvalkeal jvalkeal added type/bug Is a bug report and removed status/need-triage Team needs to triage and take a first look labels May 25, 2023
@jvalkeal jvalkeal added this to the 3.1.x milestone May 25, 2023
@jvalkeal jvalkeal changed the title AOT processing with ShellAvailability results in broken build since Spring Boot 3.0.6 ShellAvailability target not registered with AOT processing May 28, 2023
@jvalkeal jvalkeal added for/backport For backporting branch/3.0.x Issue for a branch labels May 31, 2023
@jvalkeal jvalkeal modified the milestones: 3.1.x, 3.1.1 May 31, 2023
jvalkeal added a commit that referenced this issue Jun 1, 2023
- Annotate ShellComponent with @Reflective and use custom
  AvailabilityReflectiveProcessor to find possible method
  targets returning Availability.
- Backport #747
- Fixes #758
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
branch/3.0.x Issue for a branch for/backport For backporting type/bug Is a bug report
Projects
None yet
Development

No branches or pull requests

2 participants