Skip to content

Commit 33081ff

Browse files
committed
add ApplicationStartingEvent (thrown just before managed and web services startup);
fix stubs rest early startup causing problims with jersey registrations in application run
1 parent 7df5891 commit 33081ff

9 files changed

Lines changed: 148 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
- (BREAKING) deprecated targetMain(): replaced with targetApp()
4343
- (BREAKING) StubRest default status declaration removed as not useful
4444
(required status could be declared now with the new request builder)
45+
* Add guicey event ApplicationStartingEvent thrown just before managed and web services startup
46+
* Fix stubs rest too early startup, causing problems with jersey registrations in application run method
4547

4648
### 7.2.1 (2025-05-12)
4749
* Fix NoClassDefFoundError on guicey startup due to junit classes leak into core (#428)

dropwizard-guicey/src/main/java/ru/vyarus/dropwizard/guice/module/lifecycle/GuiceyLifecycle.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,29 @@ public enum GuiceyLifecycle {
154154
* This point is before
155155
* {@link io.dropwizard.core.Application#run(
156156
* io.dropwizard.core.Configuration, io.dropwizard.core.setup.Environment)}. Ideal point for jersey and jetty
157-
* listeners installation (with shortcut event methods).
157+
* listeners installation (with shortcut event methods). To run after application run use
158+
* {@link #ApplicationStarting}.
158159
*/
159160
ApplicationRun(ApplicationRunEvent.class),
160161

161162
// -- Application.run()
162163

164+
/**
165+
* Called after complete application configuration ({@link io.dropwizard.core.Application#run(
166+
* io.dropwizard.core.Configuration, io.dropwizard.core.setup.Environment)} called), but before lifecycle
167+
* startup (before managed objects run). Actually the same as jetty lifecycle started event
168+
* ({@link org.eclipse.jetty.util.component.LifeCycle.Listener#lifeCycleStarting(
169+
* org.eclipse.jetty.util.component.LifeCycle)}.
170+
* <p>
171+
* May be used as for additional services startup (after all initializations), executed before "started" point,
172+
* often used for reporting. As an example, sub rest use this event to run jersey context after initialization.
173+
* This event also will be fired in guicey tests ({@link ru.vyarus.dropwizard.guice.test.jupiter.TestGuiceyApp}
174+
* which does not start the web part).
175+
* <p>
176+
* NOTE: jersey context is not started yet!
177+
*/
178+
ApplicationStarting(ApplicationStartingEvent.class),
179+
163180
/**
164181
* Jersey context starting. At this point jersey is starting and jetty is only initializing. Since that point
165182
* jersey {@link org.glassfish.jersey.internal.inject.InjectionManager} is accessible.

dropwizard-guicey/src/main/java/ru/vyarus/dropwizard/guice/module/lifecycle/GuiceyLifecycleAdapter.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import ru.vyarus.dropwizard.guice.module.lifecycle.event.configuration.ManualExtensionsValidatedEvent;
1515
import ru.vyarus.dropwizard.guice.module.lifecycle.event.jersey.ApplicationShutdownEvent;
1616
import ru.vyarus.dropwizard.guice.module.lifecycle.event.jersey.ApplicationStartedEvent;
17+
import ru.vyarus.dropwizard.guice.module.lifecycle.event.jersey.ApplicationStartingEvent;
1718
import ru.vyarus.dropwizard.guice.module.lifecycle.event.jersey.ApplicationStoppedEvent;
1819
import ru.vyarus.dropwizard.guice.module.lifecycle.event.jersey.JerseyConfigurationEvent;
1920
import ru.vyarus.dropwizard.guice.module.lifecycle.event.jersey.JerseyExtensionsInstalledByEvent;
@@ -100,6 +101,9 @@ public void onEvent(final GuiceyLifecycleEvent event) {
100101
case ApplicationRun:
101102
applicationRun((ApplicationRunEvent) event);
102103
break;
104+
case ApplicationStarting:
105+
applicationStarting((ApplicationStartingEvent) event);
106+
break;
103107
case JerseyConfiguration:
104108
jerseyConfiguration((JerseyConfigurationEvent) event);
105109
break;
@@ -335,6 +339,20 @@ protected void applicationRun(final ApplicationRunEvent event) {
335339
// empty
336340
}
337341

342+
/**
343+
* Called after complete application configuration ({@link io.dropwizard.core.Application#run(
344+
* io.dropwizard.core.Configuration, io.dropwizard.core.setup.Environment)} called), but before lifecycle
345+
* startup (before managed objects run). Actually the same as jetty lifecycle started event
346+
* ({@link org.eclipse.jetty.util.component.LifeCycle.Listener#lifeCycleStarting(
347+
* org.eclipse.jetty.util.component.LifeCycle)}.
348+
*
349+
* @param event event object
350+
* @see GuiceyLifecycle#ApplicationStarting
351+
*/
352+
protected void applicationStarting(final ApplicationStartingEvent event) {
353+
// empty
354+
}
355+
338356
/**
339357
* Jersey context starting. At this point jersey and jetty is only initializing. Guicey jersey configuration
340358
* is not yer performed. Since that point jersey {@link org.glassfish.jersey.internal.inject.InjectionManager}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package ru.vyarus.dropwizard.guice.module.lifecycle.event.jersey;
2+
3+
import ru.vyarus.dropwizard.guice.module.lifecycle.GuiceyLifecycle;
4+
import ru.vyarus.dropwizard.guice.module.lifecycle.event.JerseyPhaseEvent;
5+
import ru.vyarus.dropwizard.guice.module.lifecycle.internal.EventsContext;
6+
7+
/**
8+
* Called after complete application configuration ({@link io.dropwizard.core.Application#run(
9+
* io.dropwizard.core.Configuration, io.dropwizard.core.setup.Environment)} called), but before lifecycle startup
10+
* (before managed objects run). Actually the same as jetty lifecycle started event
11+
* ({@link org.eclipse.jetty.util.component.LifeCycle.Listener#lifeCycleStarting(
12+
* org.eclipse.jetty.util.component.LifeCycle)}.
13+
* <p>
14+
* May be used as for additional services startup (after all initializations), executed before "started" point,
15+
* often used for reporting. As an example, sub rest use this event to run jersey context after initialization.
16+
* This event also will be fired in guicey tests ({@link ru.vyarus.dropwizard.guice.test.jupiter.TestGuiceyApp}
17+
* which does not start the web part).
18+
*
19+
* @author Vyacheslav Rusakov
20+
* @since 16.10.2025
21+
*/
22+
public class ApplicationStartingEvent extends JerseyPhaseEvent {
23+
24+
/**
25+
* Create event.
26+
*
27+
* @param context even context
28+
*/
29+
public ApplicationStartingEvent(final EventsContext context) {
30+
super(GuiceyLifecycle.ApplicationStarting, context);
31+
}
32+
}

dropwizard-guicey/src/main/java/ru/vyarus/dropwizard/guice/module/lifecycle/internal/LifecycleSupport.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import ru.vyarus.dropwizard.guice.module.lifecycle.event.configuration.ManualExtensionsValidatedEvent;
3939
import ru.vyarus.dropwizard.guice.module.lifecycle.event.jersey.ApplicationShutdownEvent;
4040
import ru.vyarus.dropwizard.guice.module.lifecycle.event.jersey.ApplicationStartedEvent;
41+
import ru.vyarus.dropwizard.guice.module.lifecycle.event.jersey.ApplicationStartingEvent;
4142
import ru.vyarus.dropwizard.guice.module.lifecycle.event.jersey.ApplicationStoppedEvent;
4243
import ru.vyarus.dropwizard.guice.module.lifecycle.event.jersey.JerseyConfigurationEvent;
4344
import ru.vyarus.dropwizard.guice.module.lifecycle.event.jersey.JerseyExtensionsInstalledByEvent;
@@ -225,6 +226,7 @@ public void initialized() {
225226
* @param configurationTree parsed configuration
226227
* @param environment environment
227228
*/
229+
@SuppressWarnings("checkstyle:AnonInnerLength")
228230
public void runPhase(final Configuration configuration,
229231
final ConfigurationTree configurationTree,
230232
final Environment environment) {
@@ -234,6 +236,11 @@ public void runPhase(final Configuration configuration,
234236
broadcast(new BeforeRunEvent(context));
235237
// fire after complete initialization (final meta-event)
236238
environment.lifecycle().addEventListener(new LifeCycle.Listener() {
239+
@Override
240+
public void lifeCycleStarting(LifeCycle event) {
241+
applicationStarting();
242+
}
243+
237244
@Override
238245
public void lifeCycleStarted(final LifeCycle event) {
239246
applicationStarted();
@@ -354,6 +361,13 @@ public void applicationRun() {
354361
broadcast(new ApplicationRunEvent(context));
355362
}
356363

364+
/**
365+
* Application starting (application run method is called but neither managed nor jersey context not started).
366+
*/
367+
private void applicationStarting() {
368+
broadcast(new ApplicationStartingEvent(context));
369+
}
370+
357371
/**
358372
* Jersey configuration started.
359373
*

dropwizard-guicey/src/main/java/ru/vyarus/dropwizard/guice/test/rest/RestStubsHook.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import ru.vyarus.dropwizard.guice.module.context.info.ItemInfo;
1313
import ru.vyarus.dropwizard.guice.module.installer.feature.jersey.ResourceInstaller;
1414
import ru.vyarus.dropwizard.guice.module.lifecycle.GuiceyLifecycle;
15-
import ru.vyarus.dropwizard.guice.module.lifecycle.event.run.ApplicationRunEvent;
15+
import ru.vyarus.dropwizard.guice.module.lifecycle.event.jersey.ApplicationStartingEvent;
1616
import ru.vyarus.dropwizard.guice.test.rest.support.GuiceyJerseyTest;
1717

1818
import java.util.Collections;
@@ -104,11 +104,12 @@ public void configure(final GuiceBundle.Builder builder) throws Exception {
104104
// to indicate)
105105
.disable(Disables.webExtension().and(Disables.jerseyExtension().negate()))
106106

107-
// started with listeners to run before application startup event, which is widely used for
108-
// reporting
107+
// started just before lifecycle startup (even if managed beans processing will be disabled,
108+
// lifecycle events will work). Important to run before ApplicationStarted even which is often
109+
// used by reporters
109110
.listen(event -> {
110-
if (event.getType().equals(GuiceyLifecycle.ApplicationRun)) {
111-
final ApplicationRunEvent evt = (ApplicationRunEvent) event;
111+
if (event.getType().equals(GuiceyLifecycle.ApplicationStarting)) {
112+
final ApplicationStartingEvent evt = (ApplicationStartingEvent) event;
112113

113114
// manual registration required to reproduce production environment
114115
registerDropwizardExtensions(evt.getEnvironment(),

dropwizard-guicey/src/test/groovy/ru/vyarus/dropwizard/guice/debug/StartupDiagnosticTest.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ void testGuiceyRunReport() {
9696
"\t\t\t\tGuicey time : 111 ms \n" +
9797
"\t\t\t\t\tInstallers time : 111 ms \n" +
9898
"\t\t\t\t\tListeners time : 111 ms \n" +
99+
"\t\t\t\t\t\tApplicationStartingEvent : 111 ms \n" +
99100
"\t\t\t\t\t\tApplicationStartedEvent : 111 ms");
100101

101102
Assertions.assertThat(out).contains("Application shutdown time: \n" +
@@ -177,6 +178,7 @@ void testDwRunReport() {
177178
"\t\t\t\t\tGuicey time : 111 ms \n" +
178179
"\t\t\t\t\t\tInstallers time : 111 ms \n" +
179180
"\t\t\t\t\t\tListeners time : 111 ms \n" +
181+
"\t\t\t\t\t\t\tApplicationStartingEvent : 111 ms \n" +
180182
"\t\t\t\t\t\t\tJerseyConfigurationEvent : 111 ms \n" +
181183
"\t\t\t\t\t\t\tJerseyExtensionsInstalledByEvent : 111 ms \n" +
182184
"\t\t\t\t\t\t\tJerseyExtensionsInstalledEvent : 111 ms \n" +
@@ -244,8 +246,6 @@ void testRestStubsRunReport() {
244246
"\t\t\t\t\tExtensions installation : 111 ms \n" +
245247
"\t\t\t\tInjector creation : 111 ms \n");
246248

247-
248-
// NOTE: jersey events here because rest stub runs at rnu phase
249249
Assertions.assertThat(out).contains("\t\t\t\tListeners time : 111 ms \n" +
250250
"\t\t\t\t\tBeforeRunEvent : 111 ms \n" +
251251
"\t\t\t\t\tBundlesStartedEvent : 111 ms \n" +
@@ -255,9 +255,6 @@ void testRestStubsRunReport() {
255255
"\t\t\t\t\tExtensionsInstalledByEvent : 111 ms \n" +
256256
"\t\t\t\t\tExtensionsInstalledEvent : 111 ms \n" +
257257
"\t\t\t\t\tApplicationRunEvent : 111 ms \n" +
258-
"\t\t\t\t\tJerseyConfigurationEvent : 111 ms \n" +
259-
"\t\t\t\t\tJerseyExtensionsInstalledByEvent : 111 ms \n" +
260-
"\t\t\t\t\tJerseyExtensionsInstalledEvent : 111 ms \n" +
261258
"\n" +
262259
"\t\tWeb server startup : 111 ms \n" +
263260
"\t\t\tLifecycle simulation time : 111 ms \n" +
@@ -267,6 +264,10 @@ void testRestStubsRunReport() {
267264
"\t\t\t\tGuicey time : 111 ms \n" +
268265
"\t\t\t\t\tInstallers time : 111 ms \n" +
269266
"\t\t\t\t\tListeners time : 111 ms \n" +
267+
"\t\t\t\t\t\tApplicationStartingEvent : 111 ms \n" +
268+
"\t\t\t\t\t\tJerseyConfigurationEvent : 111 ms \n" +
269+
"\t\t\t\t\t\tJerseyExtensionsInstalledByEvent : 111 ms \n" +
270+
"\t\t\t\t\t\tJerseyExtensionsInstalledEvent : 111 ms \n" +
270271
"\t\t\t\t\t\tApplicationStartedEvent : 111 ms");
271272

272273
Assertions.assertThat(out).contains("Application shutdown time: \n" +

dropwizard-guicey/src/test/groovy/ru/vyarus/dropwizard/guice/lifecycle/EventsConsistencyTest.groovy

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,11 @@ class EventsConsistencyTest extends AbstractTest {
287287
assert !event.getExtensions().isEmpty()
288288
}
289289

290+
@Override
291+
protected void applicationStarting(ApplicationStartingEvent event) {
292+
injectorChecks(event)
293+
}
294+
290295
@Override
291296
protected void applicationStarted(ApplicationStartedEvent event) {
292297
jerseyCheck(event)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package ru.vyarus.dropwizard.guice.test.rest;
2+
3+
import io.dropwizard.core.Application;
4+
import io.dropwizard.core.Configuration;
5+
import io.dropwizard.core.setup.Bootstrap;
6+
import io.dropwizard.core.setup.Environment;
7+
import org.junit.jupiter.api.Test;
8+
import ru.vyarus.dropwizard.guice.GuiceBundle;
9+
import ru.vyarus.dropwizard.guice.test.TestSupport;
10+
import ru.vyarus.dropwizard.guice.test.rest.support.Resource1;
11+
12+
import static org.assertj.core.api.Assertions.assertThat;
13+
14+
/**
15+
* @author Vyacheslav Rusakov
16+
* @since 16.10.2025
17+
*/
18+
public class ApplicationRunCompatibilityTest {
19+
@Test
20+
void testSimpleRun() throws Exception {
21+
final RestStubsHook rest = RestStubsHook.builder()
22+
.disableDropwizardExceptionMappers(true)
23+
.build();
24+
TestSupport.build(App.class)
25+
.hooks(rest)
26+
.runCore(injector -> {
27+
28+
assertThat(injector.getInstance(Environment.class).jersey()
29+
.getResourceConfig().isRegistered(Resource1.class)).isTrue();
30+
return null;
31+
});
32+
33+
}
34+
35+
public static class App extends Application<Configuration> {
36+
37+
@Override
38+
public void initialize(Bootstrap<Configuration> bootstrap) {
39+
bootstrap.addBundle(GuiceBundle.builder().build());
40+
}
41+
42+
@Override
43+
public void run(Configuration configuration, Environment environment) throws Exception {
44+
environment.jersey().register(Resource1.class);
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)