Skip to content

Enhance and fix @Startup annotation to make it simpler to listen to startup events #33908

@FroMage

Description

@FroMage

Description

I was annoyed to keep writing @Observes StartupEvent evt methods, and was going to ask to add a @Startup annotation I can put on my startup method, only to be surprised it exists!

But when I tried it, I got an NPE:

@ApplicationScoped
public class StartupJob {
    @Startup
    public void start()  {
    }
}
2023-06-08 14:25:07,445 ERROR [io.qua.dep.dev.IsolatedDevModeMain] (Aesh InputStream Reader) Failed to start quarkus: io.quarkus.dev.appstate.ApplicationStartException: java.lang.RuntimeException: Failed to start quarkus
	at io.quarkus.dev.appstate.ApplicationStateNotification.waitForApplicationStart(ApplicationStateNotification.java:58)
	at io.quarkus.runner.bootstrap.StartupActionImpl.runMainClass(StartupActionImpl.java:123)
	at io.quarkus.deployment.dev.IsolatedDevModeMain.restartApp(IsolatedDevModeMain.java:222)
	at io.quarkus.deployment.dev.IsolatedDevModeMain.restartCallback(IsolatedDevModeMain.java:203)
	at io.quarkus.deployment.dev.RuntimeUpdatesProcessor.doScan(RuntimeUpdatesProcessor.java:541)
	at io.quarkus.deployment.console.ConsoleStateManager.forceRestart(ConsoleStateManager.java:141)
	at io.quarkus.deployment.console.ConsoleStateManager.lambda$installBuiltins$0(ConsoleStateManager.java:98)
	at io.quarkus.deployment.console.ConsoleStateManager$1.accept(ConsoleStateManager.java:73)
	at io.quarkus.deployment.console.ConsoleStateManager$1.accept(ConsoleStateManager.java:46)
	at io.quarkus.deployment.console.AeshConsole.lambda$setup$1(AeshConsole.java:275)
	at org.aesh.terminal.EventDecoder.accept(EventDecoder.java:118)
	at org.aesh.terminal.EventDecoder.accept(EventDecoder.java:31)
	at org.aesh.terminal.io.Decoder.write(Decoder.java:133)
	at org.aesh.readline.tty.terminal.TerminalConnection.openBlocking(TerminalConnection.java:216)
	at org.aesh.readline.tty.terminal.TerminalConnection.openBlocking(TerminalConnection.java:203)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.RuntimeException: Failed to start quarkus
	at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
	at io.quarkus.runtime.Application.start(Application.java:101)
	at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:111)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:71)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:44)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:124)
	at io.quarkus.runner.GeneratedMain.main(Unknown Source)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at io.quarkus.runner.bootstrap.StartupActionImpl$1.run(StartupActionImpl.java:104)
	... 1 more
Caused by: java.lang.NullPointerException
	at java.base/java.util.Objects.requireNonNull(Objects.java:208)
	at io.quarkus.arc.impl.ArcContainerImpl.instance(ArcContainerImpl.java:294)
	at util.StartupJob_Observer_Synthetic_eb3e38591e0df9bc32072fd7c88688131df7a86f.notify(Unknown Source)
	at io.quarkus.arc.impl.EventImpl$Notifier.notifyObservers(EventImpl.java:346)
	at io.quarkus.arc.impl.EventImpl$Notifier.notify(EventImpl.java:328)
	at io.quarkus.arc.impl.EventImpl.fire(EventImpl.java:82)
	at io.quarkus.arc.runtime.ArcRecorder.fireLifecycleEvent(ArcRecorder.java:155)
	at io.quarkus.arc.runtime.ArcRecorder.handleLifecycleEvents(ArcRecorder.java:106)
	at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy_0(Unknown Source)
	at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy(Unknown Source)
	... 13 more

Also, I tried it without the @ApplicationScoped and it silently did not call my method. Could we do like we do in RESTEasy Reactive and auto-add the @ApplicationScoped annotation to the bean we generate for the method? Or, whatever, but just Make It Work™ ;)

Would you be open to supporting optional parameters like we do for RESTEasy Reactive filter methods, or build steps, so for example if I want to know what the LaunchMode is, I can write it like this?

public class StartupJob {
    @Startup
    public void start(LaunchMode mode)  {
    }
}

I think that could be super neat.

Implementation ideas

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/arcIssue related to ARC (dependency injection)kind/enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions