From 06382720607a84b28f3c330d12a5a77aca37168b Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Tue, 25 Mar 2025 12:02:35 -0400 Subject: [PATCH 01/21] changes for upgrade to dw 2.1, jersey > 2.25 --- .build-jdk11 | 0 pom.xml | 123 ++++--- .../AllowUnknownFieldsObjectMapper.java | 5 +- .../guicier/DropwizardAwareModule.java | 2 +- .../dropwizard/guicier/DropwizardModule.java | 62 ++-- .../dropwizard/guicier/GuiceBundle.java | 132 +++---- .../guicier/JerseyGuicierModule.java | 79 ++++- .../guicier/bridge/BindingUtils.java | 219 ++++++++++++ .../bridge/GuiceComponentProvider.java | 61 ++++ .../bridge/GuiceInjectionResolver.java | 52 +++ .../bridge/InjectionManagerProvider.java | 28 ++ ...ssfish.jersey.server.spi.ComponentProvider | 1 + .../dropwizard/guicier/GuiceBundleTest.java | 321 +++++++++--------- .../dropwizard/guicier/HK2LinkerTest.java | 100 +++--- .../guicier/InjectedIntegrationTest.java | 103 +++--- .../guicier/InjectedResourcesTest.java | 37 +- .../guicier/objects/ExplicitDAO.java | 11 +- .../guicier/objects/ExplicitResource.java | 29 +- .../guicier/objects/HK2ContextBindings.java | 9 +- .../guicier/objects/InjectedHealthCheck.java | 12 +- .../guicier/objects/InjectedManaged.java | 16 +- .../guicier/objects/InjectedProvider.java | 3 +- .../InjectedServerLifecycleListener.java | 8 +- .../guicier/objects/InjectedTask.java | 22 +- .../guicier/objects/InstanceManaged.java | 11 +- .../objects/JerseyContextResource.java | 11 +- .../guicier/objects/ProvidedHealthCheck.java | 8 +- .../guicier/objects/ProvidedManaged.java | 11 +- .../guicier/objects/ProvidedProvider.java | 3 +- .../ProvidedServerLifecycleListener.java | 4 +- .../guicier/objects/ProvidedTask.java | 19 +- .../guicier/objects/ProviderManaged.java | 11 +- .../objects/ProviderManagedProvider.java | 16 +- .../guicier/objects/TestApplication.java | 25 +- .../guicier/objects/TestModule.java | 103 +++--- 35 files changed, 1007 insertions(+), 650 deletions(-) delete mode 100644 .build-jdk11 create mode 100644 src/main/java/com/hubspot/dropwizard/guicier/bridge/BindingUtils.java create mode 100644 src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceComponentProvider.java create mode 100644 src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceInjectionResolver.java create mode 100644 src/main/java/com/hubspot/dropwizard/guicier/bridge/InjectionManagerProvider.java create mode 100644 src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ComponentProvider diff --git a/.build-jdk11 b/.build-jdk11 deleted file mode 100644 index e69de29..0000000 diff --git a/pom.xml b/pom.xml index d64090b..441ed5a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,58 +5,68 @@ com.hubspot basepom - 25.5 + 61.7 com.hubspot.dropwizard dropwizard-guicier - 1.3.5.3-SNAPSHOT - - - scm:git:git@github.com:HubSpot/dropwizard-guicier.git - scm:git:git@github.com:HubSpot/dropwizard-guicier.git - git@github.com:HubSpot/dropwizard-guicier.git - HEAD - - - - - hgschmie - Henning Schmiedehausen - henning@schmiedehausen.org - -8 - - + 2.1.0-SNAPSHOT - true - 3.9.1 - 4.0.2 - 2.5.0-b32 - 2.9.9 - 2.9.9.3 - 2.25.1 - 9.4.19.v20190610 - 1.3.5 + 2.1.12 + 4.2.25 + 2.6.1 + 2.16.2 + ${dep.jackson.version} + 2.41 + 9.4.53.v20231009 + + 11 - com.google.code.findbugs - jsr305 - 3.0.2 + ch.qos.logback + logback-access + ${dep.logback.version} + + + jakarta.servlet + jakarta.servlet-api + 4.0.4 + + + jakarta.ws.rs + jakarta.ws.rs-api + 2.1.6 + + + org.eclipse.jetty + jetty-server + ${dep.jetty.version} + + + javax.servlet + javax.servlet-api + + + + + org.glassfish.hk2 + guice-bridge + ${dep.hk2.version} + + + org.glassfish.jersey.inject + jersey-hk2 + ${dep.jersey2.version} - - - com.squarespace.jersey2-guice - jersey2-guice-impl - com.google.inject guice @@ -77,14 +87,6 @@ com.google.guava guava - - javax.servlet - javax.servlet-api - - - javax.ws.rs - javax.ws.rs-api - org.slf4j slf4j-api @@ -101,10 +103,6 @@ io.dropwizard dropwizard-lifecycle - - io.dropwizard - dropwizard-jackson - io.dropwizard dropwizard-jersey @@ -115,20 +113,32 @@ io.dropwizard.metrics - metrics-core + metrics-healthchecks - io.dropwizard.metrics - metrics-healthchecks + org.glassfish.jersey.core + jersey-common org.glassfish.jersey.core jersey-server + + org.glassfish.jersey.inject + jersey-hk2 + org.glassfish.hk2 hk2-api + + org.glassfish.hk2 + hk2-utils + + + org.glassfish.hk2 + guice-bridge + com.fasterxml.jackson.core jackson-databind @@ -137,10 +147,18 @@ org.eclipse.jetty jetty-server + + jakarta.servlet + jakarta.servlet-api + + + jakarta.ws.rs + jakarta.ws.rs-api + - junit - junit + org.junit.jupiter + junit-jupiter-api test @@ -165,4 +183,3 @@ - diff --git a/src/main/java/com/hubspot/dropwizard/guicier/AllowUnknownFieldsObjectMapper.java b/src/main/java/com/hubspot/dropwizard/guicier/AllowUnknownFieldsObjectMapper.java index b7bb4c5..32ad71f 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/AllowUnknownFieldsObjectMapper.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/AllowUnknownFieldsObjectMapper.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; - import io.dropwizard.setup.Bootstrap; /** @@ -17,7 +16,9 @@ private AllowUnknownFieldsObjectMapper(ObjectMapper source) { } public static void applyTo(Bootstrap bootstrap) { - bootstrap.setObjectMapper(new AllowUnknownFieldsObjectMapper(bootstrap.getObjectMapper())); + bootstrap.setObjectMapper( + new AllowUnknownFieldsObjectMapper(bootstrap.getObjectMapper()) + ); } @Override diff --git a/src/main/java/com/hubspot/dropwizard/guicier/DropwizardAwareModule.java b/src/main/java/com/hubspot/dropwizard/guicier/DropwizardAwareModule.java index 3082d2c..336a1eb 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/DropwizardAwareModule.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/DropwizardAwareModule.java @@ -4,12 +4,12 @@ import static com.google.common.base.Preconditions.checkState; import com.google.inject.Module; - import io.dropwizard.Configuration; import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Environment; public abstract class DropwizardAwareModule implements Module { + private volatile Bootstrap bootstrap = null; private volatile C configuration = null; private volatile Environment environment = null; diff --git a/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java b/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java index 59b6d92..3596a63 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java @@ -11,16 +11,16 @@ import io.dropwizard.lifecycle.ServerLifecycleListener; import io.dropwizard.servlets.tasks.Task; import io.dropwizard.setup.Environment; +import java.lang.reflect.Type; +import javax.ws.rs.Path; +import javax.ws.rs.ext.Provider; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.model.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.Path; -import javax.ws.rs.ext.Provider; -import java.lang.reflect.Type; - public class DropwizardModule implements Module { + private static final Logger LOG = LoggerFactory.getLogger(DropwizardModule.class); private final Environment environment; @@ -31,28 +31,31 @@ public DropwizardModule(Environment environment) { @Override public void configure(final Binder binder) { - binder.bindListener(Matchers.any(), new ProvisionListener() { - @Override - public void onProvision(ProvisionInvocation provision) { - Object obj = provision.provision(); - - if (obj instanceof Managed) { - handle((Managed) obj); - } + binder.bindListener( + Matchers.any(), + new ProvisionListener() { + @Override + public void onProvision(ProvisionInvocation provision) { + Object obj = provision.provision(); + + if (obj instanceof Managed) { + handle((Managed) obj); + } - if (obj instanceof Task) { - handle((Task) obj); - } + if (obj instanceof Task) { + handle((Task) obj); + } - if (obj instanceof HealthCheck) { - handle((HealthCheck) obj); - } + if (obj instanceof HealthCheck) { + handle((HealthCheck) obj); + } - if (obj instanceof ServerLifecycleListener) { - handle((ServerLifecycleListener) obj); + if (obj instanceof ServerLifecycleListener) { + handle((ServerLifecycleListener) obj); + } } } - }); + ); } public void register(Injector injector) { @@ -70,13 +73,18 @@ private void handle(Task task) { } private void handle(HealthCheck healthcheck) { - environment.healthChecks().register(healthcheck.getClass().getSimpleName(), healthcheck); + environment + .healthChecks() + .register(healthcheck.getClass().getSimpleName(), healthcheck); LOG.info("Added guice injected health check: {}", healthcheck.getClass().getName()); } private void handle(ServerLifecycleListener serverLifecycleListener) { environment.lifecycle().addServerLifecycleListener(serverLifecycleListener); - LOG.info("Added guice injected server lifecycle listener: {}", serverLifecycleListener.getClass().getName()); + LOG.info( + "Added guice injected server lifecycle listener: {}", + serverLifecycleListener.getClass().getName() + ); } private void registerResourcesAndProviders(ResourceConfig config, Injector injector) { @@ -91,14 +99,16 @@ private void registerResourcesAndProviders(ResourceConfig config, Injector injec } else if (isResourceClass(c)) { // Jersey rejects resources that it doesn't think are acceptable // Including abstract classes and interfaces, even if there is a valid Guice binding. - if(Resource.isAcceptable(c)) { + if (Resource.isAcceptable(c)) { LOG.info("Registering {} as a root resource class", c.getName()); config.register(c); } else { - LOG.warn("Class {} was not registered as a resource; bind a concrete implementation instead", c.getName()); + LOG.warn( + "Class {} was not registered as a resource; bind a concrete implementation instead", + c.getName() + ); } } - } } injector = injector.getParent(); diff --git a/src/main/java/com/hubspot/dropwizard/guicier/GuiceBundle.java b/src/main/java/com/hubspot/dropwizard/guicier/GuiceBundle.java index 214599b..ca75c62 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/GuiceBundle.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/GuiceBundle.java @@ -2,14 +2,6 @@ import static com.google.common.base.Preconditions.checkNotNull; -import java.lang.reflect.Field; -import java.util.Arrays; - -import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.hk2.internal.ServiceLocatorFactoryImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.google.common.collect.ImmutableSet; import com.google.inject.Binder; import com.google.inject.Guice; @@ -19,21 +11,24 @@ import com.google.inject.servlet.GuiceFilter; import com.google.inject.servlet.GuiceServletContextListener; import com.google.inject.servlet.ServletModule; -import com.squarespace.jersey2.guice.JerseyGuiceModule; -import com.squarespace.jersey2.guice.JerseyGuiceUtils; - import io.dropwizard.Configuration; import io.dropwizard.ConfiguredBundle; import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Environment; +import java.util.Arrays; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author Henning P. Schmiedehausen */ public class GuiceBundle implements ConfiguredBundle { + private static final Logger LOG = LoggerFactory.getLogger(GuiceBundle.class); - public static Builder defaultBuilder(final Class configClass) { + public static Builder defaultBuilder( + final Class configClass + ) { return new Builder<>(configClass); } @@ -48,13 +43,15 @@ public static Builder defaultBuilder(final Class private Bootstrap bootstrap = null; private Injector injector = null; - private GuiceBundle(final Class configClass, - final ImmutableSet guiceModules, - final ImmutableSet> dropwizardAwareModules, - final Stage guiceStage, - final boolean allowUnknownFields, - final boolean enableGuiceEnforcer, - final InjectorFactory injectorFactory) { + private GuiceBundle( + final Class configClass, + final ImmutableSet guiceModules, + final ImmutableSet> dropwizardAwareModules, + final Stage guiceStage, + final boolean allowUnknownFields, + final boolean enableGuiceEnforcer, + final InjectorFactory injectorFactory + ) { this.configClass = configClass; this.guiceModules = guiceModules; @@ -82,46 +79,39 @@ public void run(final T configuration, final Environment environment) throws Exc } final DropwizardModule dropwizardModule = new DropwizardModule(environment); - // We assume that the next service locator will be the main application one - final String serviceLocatorName = getNextServiceLocatorName(); - ImmutableSet.Builder modulesBuilder = - ImmutableSet.builder() - .addAll(guiceModules) - .addAll(dropwizardAwareModules) - .add(new ServletModule()) - .add(dropwizardModule) - .add(new JerseyGuiceModule(serviceLocatorName)) - .add(new JerseyGuicierModule()) - .add(binder -> { - binder.bind(Environment.class).toInstance(environment); - binder.bind(configClass).toInstance(configuration); - }); + + ImmutableSet.Builder modulesBuilder = ImmutableSet + .builder() + .addAll(guiceModules) + .addAll(dropwizardAwareModules) + .add(new ServletModule()) + .add(dropwizardModule) + .add(new JerseyGuicierModule()) + .add(binder -> { + binder.bind(Environment.class).toInstance(environment); + binder.bind(configClass).toInstance(configuration); + }); if (enableGuiceEnforcer) { modulesBuilder.add(new GuiceEnforcerModule()); } this.injector = injectorFactory.create(guiceStage, modulesBuilder.build()); - JerseyGuiceUtils.install((name, parent) -> { - if (!name.startsWith("__HK2_")) { - return null; - } else if (serviceLocatorName.equals(name)) { - return injector.getInstance(ServiceLocator.class); - } else { - LOG.debug("Returning a new ServiceLocator for name '{}'", name); - return JerseyGuiceUtils.newServiceLocator(name, parent); - } - }); - dropwizardModule.register(injector); - environment.servlets().addFilter("Guice Filter", GuiceFilter.class).addMappingForUrlPatterns(null, false, "/*"); - environment.servlets().addServletListeners(new GuiceServletContextListener() { - - @Override - protected Injector getInjector() { - return injector; - } - }); + environment + .servlets() + .addFilter("Guice Filter", GuiceFilter.class) + .addMappingForUrlPatterns(null, false, "/*"); + environment + .servlets() + .addServletListeners( + new GuiceServletContextListener() { + @Override + protected Injector getInjector() { + return injector; + } + } + ); } public Injector getInjector() { @@ -129,6 +119,7 @@ public Injector getInjector() { } public static class GuiceEnforcerModule implements Module { + @Override public void configure(final Binder binder) { binder.disableCircularProxies(); @@ -139,9 +130,11 @@ public void configure(final Binder binder) { } public static class Builder { + private final Class configClass; private final ImmutableSet.Builder guiceModules = ImmutableSet.builder(); - private final ImmutableSet.Builder> dropwizardAwareModules = ImmutableSet.builder(); + private final ImmutableSet.Builder> dropwizardAwareModules = + ImmutableSet.builder(); private Stage guiceStage = Stage.PRODUCTION; private boolean allowUnknownFields = true; private boolean enableGuiceEnforcer = true; @@ -189,30 +182,15 @@ public final Builder injectorFactory(final InjectorFactory injectorFactory) { } public final GuiceBundle build() { - return new GuiceBundle<>(configClass, - guiceModules.build(), - dropwizardAwareModules.build(), - guiceStage, - allowUnknownFields, - enableGuiceEnforcer, - injectorFactory); - } - } - - private static String getNextServiceLocatorName() { - Class factoryClass = ServiceLocatorFactoryImpl.class; - try { - Field nameCountField = factoryClass.getDeclaredField("name_count"); - nameCountField.setAccessible(true); - int count = (int) nameCountField.get(null); - - Field namePrefixField = factoryClass.getDeclaredField("GENERATED_NAME_PREFIX"); - namePrefixField.setAccessible(true); - String prefix = (String) namePrefixField.get(null); - - return prefix + count; - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new RuntimeException(e); + return new GuiceBundle<>( + configClass, + guiceModules.build(), + dropwizardAwareModules.build(), + guiceStage, + allowUnknownFields, + enableGuiceEnforcer, + injectorFactory + ); } } } diff --git a/src/main/java/com/hubspot/dropwizard/guicier/JerseyGuicierModule.java b/src/main/java/com/hubspot/dropwizard/guicier/JerseyGuicierModule.java index 6b45137..551be7f 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/JerseyGuicierModule.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/JerseyGuicierModule.java @@ -1,49 +1,92 @@ package com.hubspot.dropwizard.guicier; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.servlet.RequestScoped; +import com.hubspot.dropwizard.guicier.bridge.InjectionManagerProvider; import javax.servlet.ServletConfig; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ResourceContext; +import javax.ws.rs.core.Application; import javax.ws.rs.core.Configuration; - -import org.glassfish.hk2.api.ServiceLocator; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Request; +import javax.ws.rs.core.SecurityContext; +import javax.ws.rs.core.UriInfo; +import javax.ws.rs.ext.Providers; +import org.glassfish.jersey.internal.inject.InjectionManager; import org.glassfish.jersey.server.ExtendedUriInfo; -import com.google.inject.Provides; -import com.google.inject.servlet.RequestScoped; -import com.squarespace.jersey2.guice.JerseyModule; - /** * This supplements the bindings provided in {@link com.squarespace.jersey2.guice.JerseyGuiceModule}. */ -public class JerseyGuicierModule extends JerseyModule { +public class JerseyGuicierModule extends AbstractModule { @Override - protected void configure() {} + protected void configure() { + bind(InjectionManager.class).toProvider(InjectionManagerProvider.class); + } + + @Provides + public Application providesApplication(InjectionManager injectionManager) { + return injectionManager.getInstance(Application.class); + } + + @Provides + public Providers providesProviders(InjectionManager injectionManager) { + return injectionManager.getInstance(Providers.class); + } + + @Provides + @RequestScoped + public UriInfo providesUriInfo(InjectionManager injectionManager) { + return injectionManager.getInstance(UriInfo.class); + } + + @Provides + @RequestScoped + public HttpHeaders providesHttpHeaders(InjectionManager injectionManager) { + return injectionManager.getInstance(HttpHeaders.class); + } + + @Provides + @RequestScoped + public SecurityContext providesSecurityContext(InjectionManager injectionManager) { + return injectionManager.getInstance(SecurityContext.class); + } + + @Provides + @RequestScoped + public Request providesRequest(InjectionManager injectionManager) { + return injectionManager.getInstance(Request.class); + } @Provides - public Configuration providesConfiguration(ServiceLocator serviceLocator) { - return serviceLocator.getService(Configuration.class); + public Configuration providesConfiguration(InjectionManager injectionManager) { + return injectionManager.getInstance(Configuration.class); } @Provides @RequestScoped - public ContainerRequestContext providesContainerRequestContext(ServiceLocator serviceLocator) { - return serviceLocator.getService(ContainerRequestContext.class); + public ContainerRequestContext providesContainerRequestContext( + InjectionManager injectionManager + ) { + return injectionManager.getInstance(ContainerRequestContext.class); } @Provides @RequestScoped - public ExtendedUriInfo providesExtendedUriInfo(ServiceLocator serviceLocator) { - return serviceLocator.getService(ExtendedUriInfo.class); + public ExtendedUriInfo providesExtendedUriInfo(InjectionManager injectionManager) { + return injectionManager.getInstance(ExtendedUriInfo.class); } @Provides - public ResourceContext providesResourceContext(ServiceLocator serviceLocator) { - return serviceLocator.getService(ResourceContext.class); + public ResourceContext providesResourceContext(InjectionManager injectionManager) { + return injectionManager.getInstance(ResourceContext.class); } @Provides - public ServletConfig providesServletConfig(ServiceLocator serviceLocator) { - return serviceLocator.getService(ServletConfig.class); + public ServletConfig providesServletConfig(InjectionManager injectionManager) { + return injectionManager.getInstance(ServletConfig.class); } } diff --git a/src/main/java/com/hubspot/dropwizard/guicier/bridge/BindingUtils.java b/src/main/java/com/hubspot/dropwizard/guicier/bridge/BindingUtils.java new file mode 100644 index 0000000..ace0844 --- /dev/null +++ b/src/main/java/com/hubspot/dropwizard/guicier/bridge/BindingUtils.java @@ -0,0 +1,219 @@ +package com.hubspot.dropwizard.guicier.bridge; + +import com.google.inject.BindingAnnotation; +import com.google.inject.Key; +import com.google.inject.internal.Nullability; +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import javax.annotation.Nullable; +import javax.inject.Qualifier; +import org.glassfish.hk2.utilities.reflection.ReflectionHelper; +import org.glassfish.jersey.internal.inject.Injectee; + +public class BindingUtils { + + /** + * Returns {@code true} if the given {@link Injectee} can be {@code null}. + * + * @see Optional + * @see Injectee#isOptional() + * @see Nullable + * @see com.google.inject.Inject#optional() + * @see Nullability#hasNullableAnnotation(Annotation[]) + */ + public static boolean isNullable(Injectee injectee) { + // HK2's optional + if (injectee.isOptional()) { + return true; + } + + // Guice's optional + AnnotatedElement element = injectee.getParent(); + if (isGuiceOptional(element)) { + return true; + } + + // Any @Nullable? + int position = injectee.getPosition(); + + if (element instanceof Field) { + return Nullability.hasNullableAnnotation(((Field) element).getAnnotations()); + } else if (element instanceof Method) { + Annotation annotations[][] = ((Method) element).getParameterAnnotations(); + return Nullability.hasNullableAnnotation(annotations[position]); + } else if (element instanceof Constructor) { + Annotation annotations[][] = ((Constructor) element).getParameterAnnotations(); + return Nullability.hasNullableAnnotation(annotations[position]); + } + + return false; + } + + /** + * Returns {@code true} if the given {@link AnnotatedElement} has a + * {@link com.google.inject.Inject} {@link Annotation} and it's marked + * as being optional. + * + * @see com.google.inject.Inject#optional() + */ + private static boolean isGuiceOptional(AnnotatedElement element) { + com.google.inject.Inject inject = element.getAnnotation( + com.google.inject.Inject.class + ); + + if (inject != null) { + return inject.optional(); + } + + return false; + } + + /** + * Returns {@code true} if the {@link Injectee} has a HK2 SPI + * {@link org.jvnet.hk2.annotations.Contract} annotation. + * + * @see org.jvnet.hk2.annotations.Contract + */ + public static boolean isHk2Contract(Injectee injectee) { + Type type = injectee.getRequiredType(); + return isContact(type, org.jvnet.hk2.annotations.Contract.class); + } + + /** + * Returns {@code true} if the {@link Injectee} has a Jersey SPI + * {@link org.glassfish.jersey.spi.Contract} annotation. + * + * @see org.glassfish.jersey.spi.Contract + */ + public static boolean isJerseyContract(Injectee injectee) { + Type type = injectee.getRequiredType(); + return isContact(type, org.glassfish.jersey.spi.Contract.class); + } + + private static boolean isContact( + Type type, + Class annotationType + ) { + if (type instanceof Class) { + return ((Class) type).isAnnotationPresent(annotationType); + } + + if (type instanceof ParameterizedType) { + Type rawType = ((ParameterizedType) type).getRawType(); + return isContact(rawType, annotationType); + } + + return false; + } + + /** + * Creates and returns a {@link Key} from the given {@link Injectee}. + */ + public static Key toKey(Injectee injectee) { + Type type = injectee.getRequiredType(); + Set qualifiers = getQualifiers(injectee); + return newKey(type, qualifiers); + } + + /** + * Creates and returns a {@link Key} for the given {@link Type} and {@link Set} of {@link Annotation}s. + */ + private static Key newKey(Type type, Set qualifiers) { + if (qualifiers.isEmpty()) { + return Key.get(type); + } + + // There can be only one qualifier. + if (qualifiers.size() == 1) { + for (Annotation first : qualifiers) { + return Key.get(type, first); + } + } + + return null; + } + + /** + * NOTE: There can be only one {@link Annotation} that is a {@link Qualifier} or {@link BindingAnnotation}. + * They're the same but HK2 does not know about {@link BindingAnnotation}. + * + * @see Qualifier + * @see BindingAnnotation + * @see javax.inject.Named + * @see com.google.inject.name.Named + */ + private static Set getQualifiers(Injectee injectee) { + // JSR 330's @Qualifier + Set qualifiers = injectee.getRequiredQualifiers(); + if (!qualifiers.isEmpty()) { + return qualifiers; + } + + AnnotatedElement element = injectee.getParent(); + int position = injectee.getPosition(); + + // Guice's @BindingAnnotation is the same as @Qualifier + Annotation annotation = getBindingAnnotation(element, position); + if (annotation != null) { + return Collections.singleton(annotation); + } + + return Collections.emptySet(); + } + + /** + * Returns a {@link BindingAnnotation} for the given {@link AnnotatedElement} and position. + */ + private static Annotation getBindingAnnotation(AnnotatedElement element, int position) { + if (element instanceof Field) { + return getBindingAnnotation(((Field) element).getAnnotations()); + } + + if (element instanceof Method) { + Annotation annotations[][] = ((Method) element).getParameterAnnotations(); + return getBindingAnnotation(annotations[position]); + } + + if (element instanceof Constructor) { + Annotation annotations[][] = ((Constructor) element).getParameterAnnotations(); + return getBindingAnnotation(annotations[position]); + } + + return null; + } + + /** + * Returns the first {@link Annotation} from the given array that + * is a {@link BindingAnnotation}. + * + * @see BindingAnnotation + */ + private static Annotation getBindingAnnotation(Annotation[] annotations) { + for (Annotation annotation : annotations) { + Class type = annotation.annotationType(); + if (type.isAnnotationPresent(BindingAnnotation.class)) { + return annotation; + } + } + + return null; + } + + /** + * @see ReflectionHelper#getNameFromAllQualifiers(Set, AnnotatedElement) + */ + public static String getNameFromAllQualifiers( + Set qualifiers, + AnnotatedElement element + ) { + return ReflectionHelper.getNameFromAllQualifiers(qualifiers, element); + } +} diff --git a/src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceComponentProvider.java b/src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceComponentProvider.java new file mode 100644 index 0000000..6c72fb7 --- /dev/null +++ b/src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceComponentProvider.java @@ -0,0 +1,61 @@ +package com.hubspot.dropwizard.guicier.bridge; + +import com.google.inject.Injector; +import java.util.Set; +import javax.servlet.ServletContext; +import org.glassfish.jersey.inject.hk2.ImmediateHk2InjectionManager; +import org.glassfish.jersey.internal.inject.Bindings; +import org.glassfish.jersey.internal.inject.InjectionManager; +import org.glassfish.jersey.server.spi.ComponentProvider; +import org.jvnet.hk2.guice.bridge.api.GuiceBridge; +import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GuiceComponentProvider implements ComponentProvider { + + private static final Logger LOG = LoggerFactory.getLogger(GuiceComponentProvider.class); + + private volatile Injector guiceInjector; + + @Override + public void initialize(InjectionManager injectionManager) { + InjectionManagerProvider.set(injectionManager); + + ServletContext sc = injectionManager.getInstance(ServletContext.class); + if (sc != null) { + guiceInjector = (Injector) sc.getAttribute(Injector.class.getName()); + } + + if (guiceInjector == null) { + LOG.error("Failed to lookup guice injector from servlet context"); + return; + } + + // initialize HK2 guice-bridge + ImmediateHk2InjectionManager hk2InjectionManager = + (ImmediateHk2InjectionManager) injectionManager; + GuiceBridge + .getGuiceBridge() + .initializeGuiceBridge(hk2InjectionManager.getServiceLocator()); + GuiceIntoHK2Bridge guiceBridge = injectionManager.getInstance( + GuiceIntoHK2Bridge.class + ); + guiceBridge.bridgeGuiceInjector(guiceInjector); + + injectionManager.register( + Bindings.injectionResolver(new GuiceInjectionResolver(guiceInjector)) + ); + injectionManager.register(Bindings.service(guiceInjector).to(Injector.class)); + + LOG.debug("Guice Component Provider initialized"); + } + + @Override + public boolean bind(Class component, Set> providerContracts) { + return false; + } + + @Override + public void done() {} +} diff --git a/src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceInjectionResolver.java b/src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceInjectionResolver.java new file mode 100644 index 0000000..68e684a --- /dev/null +++ b/src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceInjectionResolver.java @@ -0,0 +1,52 @@ +package com.hubspot.dropwizard.guicier.bridge; + +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.Key; +import javax.inject.Singleton; +import org.glassfish.jersey.internal.inject.Injectee; +import org.glassfish.jersey.internal.inject.InjectionResolver; + +@Singleton +public class GuiceInjectionResolver implements InjectionResolver { + + private final Injector injector; + + public GuiceInjectionResolver(Injector injector) { + this.injector = injector; + } + + @Override + public Object resolve(Injectee injectee) { + Key key = BindingUtils.toKey(injectee); + + Object instance = injector.getInstance(key); + + if (instance == null) { + if (BindingUtils.isNullable(injectee)) { + return null; + } + + throw new RuntimeException( + "There was no object available for injection at " + injectee + ); + } + + return instance; + } + + @Override + public boolean isConstructorParameterIndicator() { + return true; + } + + @Override + public boolean isMethodParameterIndicator() { + return false; + } + + @Override + public Class getAnnotation() { + return Inject.class; + } +} diff --git a/src/main/java/com/hubspot/dropwizard/guicier/bridge/InjectionManagerProvider.java b/src/main/java/com/hubspot/dropwizard/guicier/bridge/InjectionManagerProvider.java new file mode 100644 index 0000000..2e7396e --- /dev/null +++ b/src/main/java/com/hubspot/dropwizard/guicier/bridge/InjectionManagerProvider.java @@ -0,0 +1,28 @@ +package com.hubspot.dropwizard.guicier.bridge; + +import com.google.common.base.Preconditions; +import java.util.concurrent.atomic.AtomicReference; +import javax.inject.Inject; +import javax.inject.Provider; +import org.glassfish.jersey.internal.inject.InjectionManager; + +public class InjectionManagerProvider implements Provider { + + private static final AtomicReference INJECTION_MANAGER_REF = + new AtomicReference<>(); + + @Inject + public InjectionManagerProvider() {} + + public static void set(InjectionManager injectionManager) { + INJECTION_MANAGER_REF.set(injectionManager); + } + + @Override + public InjectionManager get() { + return Preconditions.checkNotNull( + INJECTION_MANAGER_REF.get(), + "InjectionManager not set" + ); + } +} diff --git a/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ComponentProvider b/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ComponentProvider new file mode 100644 index 0000000..7406ded --- /dev/null +++ b/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ComponentProvider @@ -0,0 +1 @@ +com.hubspot.dropwizard.guicier.bridge.GuiceComponentProvider diff --git a/src/test/java/com/hubspot/dropwizard/guicier/GuiceBundleTest.java b/src/test/java/com/hubspot/dropwizard/guicier/GuiceBundleTest.java index edafdcc..2e3fc0d 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/GuiceBundleTest.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/GuiceBundleTest.java @@ -1,29 +1,7 @@ package com.hubspot.dropwizard.guicier; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.*; -import java.util.Set; -import java.util.function.Function; - -import javax.servlet.ServletException; - -import com.hubspot.dropwizard.guicier.objects.InstanceManaged; -import com.hubspot.dropwizard.guicier.objects.ProvidedHealthCheck; -import com.hubspot.dropwizard.guicier.objects.ProvidedManaged; -import com.hubspot.dropwizard.guicier.objects.ProvidedProvider; -import com.hubspot.dropwizard.guicier.objects.ProvidedServerLifecycleListener; -import com.hubspot.dropwizard.guicier.objects.ProvidedTask; -import com.hubspot.dropwizard.guicier.objects.ProviderManaged; -import org.glassfish.hk2.api.ServiceLocator; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -import com.codahale.metrics.MetricRegistry; -import com.fasterxml.jackson.databind.ObjectMapper; import com.google.inject.Injector; import com.hubspot.dropwizard.guicier.objects.ExplicitResource; import com.hubspot.dropwizard.guicier.objects.InjectedHealthCheck; @@ -31,149 +9,168 @@ import com.hubspot.dropwizard.guicier.objects.InjectedProvider; import com.hubspot.dropwizard.guicier.objects.InjectedServerLifecycleListener; import com.hubspot.dropwizard.guicier.objects.InjectedTask; -import com.hubspot.dropwizard.guicier.objects.TestModule; -import com.squarespace.jersey2.guice.JerseyGuiceUtils; - +import com.hubspot.dropwizard.guicier.objects.InstanceManaged; +import com.hubspot.dropwizard.guicier.objects.ProvidedHealthCheck; +import com.hubspot.dropwizard.guicier.objects.ProvidedManaged; +import com.hubspot.dropwizard.guicier.objects.ProvidedProvider; +import com.hubspot.dropwizard.guicier.objects.ProvidedServerLifecycleListener; +import com.hubspot.dropwizard.guicier.objects.ProvidedTask; +import com.hubspot.dropwizard.guicier.objects.ProviderManaged; +import com.hubspot.dropwizard.guicier.objects.TestApplication; import io.dropwizard.Configuration; -import io.dropwizard.jackson.Jackson; -import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Environment; +import io.dropwizard.testing.ResourceHelpers; +import io.dropwizard.testing.junit5.DropwizardAppExtension; +import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; +import java.util.Set; +import java.util.function.Function; +import javax.servlet.ServletException; +import org.glassfish.jersey.internal.inject.InjectionManager; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(DropwizardExtensionsSupport.class) public class GuiceBundleTest { - private Environment environment; - private GuiceBundle guiceBundle; - - @After - public void tearDown() { - JerseyGuiceUtils.reset(); - } - - @Before - public void setUp() throws Exception { - ObjectMapper objectMapper = Jackson.newObjectMapper(); - environment = new Environment("test env", objectMapper, null, new MetricRegistry(), null); - guiceBundle = GuiceBundle.defaultBuilder(Configuration.class) - .modules(new TestModule()) - .build(); - Bootstrap bootstrap = mock(Bootstrap.class); - when(bootstrap.getObjectMapper()).thenReturn(objectMapper); - guiceBundle.initialize(bootstrap); - guiceBundle.run(new Configuration(), environment); - } - - @Test - public void createsInjectorWhenInit() throws ServletException { - Injector injector = guiceBundle.getInjector(); - assertThat(injector).isNotNull(); - } - - @Test - public void serviceLocatorIsAvaliable () throws ServletException { - ServiceLocator serviceLocator = guiceBundle.getInjector().getInstance(ServiceLocator.class); - assertThat(serviceLocator).isNotNull(); - } - - @Test - public void itAddsBoundManaged() { - InjectedManaged injectedManaged = guiceBundle.getInjector().getInstance(InjectedManaged.class); - assertThat(environment.lifecycle().getManagedObjects()) - .extracting("managed") - .containsOnlyOnce(injectedManaged); - } - - @Test - public void itAddsInstanceManaged() { - InstanceManaged instanceManaged = guiceBundle.getInjector().getInstance(InstanceManaged.class); - assertThat(environment.lifecycle().getManagedObjects()) - .extracting("managed") - .containsOnlyOnce(instanceManaged); - } - - @Test - public void itAddsProviderManagedSingleton() { - ProviderManaged providerManaged = guiceBundle.getInjector().getInstance(ProviderManaged.class); - assertThat(environment.lifecycle().getManagedObjects()) - .extracting("managed") - .containsOnlyOnce(providerManaged); - } - - @Test - public void itAddsBoundTask() { - InjectedTask injectedTask = guiceBundle.getInjector().getInstance(InjectedTask.class); - assertThat(environment.admin()) - .extracting("tasks") - .flatExtracting("tasks") - .containsOnlyOnce(injectedTask); - } - - @Test - public void itAddsBoundHealthCheck() { - assertThat(environment.healthChecks().getNames()) - .containsOnlyOnce(InjectedHealthCheck.class.getSimpleName()); - } - - @Test - public void itAddsBoundServerLifecycleListener() { - InjectedServerLifecycleListener injectedServerLifecycleListener = - guiceBundle.getInjector().getInstance(InjectedServerLifecycleListener.class); - assertThat(environment.lifecycle()) - .extracting(Function.identity()) - .flatExtracting("lifecycleListeners") - .extracting("listener") - .containsOnlyOnce(injectedServerLifecycleListener); - } - - @Test - public void itAddsBoundProvider() { - Set> components = environment.jersey().getResourceConfig().getClasses(); - assertThat(components).containsOnlyOnce(InjectedProvider.class); - } - - @Test - public void itAddsBoundResource() { - Set> resourceClasses = environment.jersey().getResourceConfig().getClasses(); - assertThat(resourceClasses).containsOnlyOnce(ExplicitResource.class); - } - - @Test - public void itAddsProvidedManaged() { - ProvidedManaged providedManaged = guiceBundle.getInjector().getInstance(ProvidedManaged.class); - assertThat(environment.lifecycle().getManagedObjects()) - .extracting("managed") - .containsOnlyOnce(providedManaged); - } - - @Test - public void itAddsProvidedTask() { - ProvidedTask providedTask = guiceBundle.getInjector().getInstance(ProvidedTask.class); - assertThat(environment.admin()) - .extracting("tasks") - .flatExtracting("tasks") - .containsOnlyOnce(providedTask); - } - - @Test - public void itAddsProvidedHealthCheck() { - assertThat(environment.healthChecks().getNames()) - .containsOnlyOnce(ProvidedHealthCheck.class.getSimpleName()); - } - - @Test - public void itAddsProvidedServerLifecycleListener() { - ProvidedServerLifecycleListener providedServerLifecycleListener = - guiceBundle.getInjector().getInstance(ProvidedServerLifecycleListener.class); - assertThat(environment.lifecycle()) - .extracting(Function.identity()) - .flatExtracting("lifecycleListeners") - .extracting("listener") - .containsOnlyOnce(providedServerLifecycleListener); - } - - @Test - public void itAddsProvidedProvider() { - Set> components = environment.jersey().getResourceConfig().getClasses(); - assertThat(components).containsOnlyOnce(ProvidedProvider.class); - } + private static DropwizardAppExtension EXT = new DropwizardAppExtension<>( + TestApplication.class, + ResourceHelpers.resourceFilePath("test-config.yml") + ); + + private Environment environment; + private GuiceBundle guiceBundle; + + @BeforeEach + public void setup() { + TestApplication testApplication = EXT.getApplication(); + this.guiceBundle = testApplication.getGuiceBundle(); + this.environment = EXT.getEnvironment(); + } + + @Test + public void createsInjectorWhenInit() throws ServletException { + Injector injector = guiceBundle.getInjector(); + assertThat(injector).isNotNull(); + } + + @Test + public void serviceLocatorIsAvailable() throws ServletException { + InjectionManager injectionManager = guiceBundle + .getInjector() + .getInstance(InjectionManager.class); + assertThat(injectionManager).isNotNull(); + } + + @Test + public void itAddsBoundManaged() { + InjectedManaged injectedManaged = guiceBundle + .getInjector() + .getInstance(InjectedManaged.class); + assertThat(environment.lifecycle().getManagedObjects()) + .extracting("managed") + .containsOnlyOnce(injectedManaged); + } + + @Test + public void itAddsInstanceManaged() { + InstanceManaged instanceManaged = guiceBundle + .getInjector() + .getInstance(InstanceManaged.class); + assertThat(environment.lifecycle().getManagedObjects()) + .extracting("managed") + .containsOnlyOnce(instanceManaged); + } + + @Test + public void itAddsProviderManagedSingleton() { + ProviderManaged providerManaged = guiceBundle + .getInjector() + .getInstance(ProviderManaged.class); + assertThat(environment.lifecycle().getManagedObjects()) + .extracting("managed") + .containsOnlyOnce(providerManaged); + } + + @Test + public void itAddsBoundTask() { + InjectedTask injectedTask = guiceBundle.getInjector().getInstance(InjectedTask.class); + assertThat(environment.admin()) + .extracting("tasks") + .flatExtracting("tasks") + .containsOnlyOnce(injectedTask); + } + + @Test + public void itAddsBoundHealthCheck() { + assertThat(environment.healthChecks().getNames()) + .containsOnlyOnce(InjectedHealthCheck.class.getSimpleName()); + } + + @Test + public void itAddsBoundServerLifecycleListener() { + InjectedServerLifecycleListener injectedServerLifecycleListener = guiceBundle + .getInjector() + .getInstance(InjectedServerLifecycleListener.class); + assertThat(environment.lifecycle()) + .extracting(Function.identity()) + .flatExtracting("lifecycleListeners") + .extracting("listener") + .containsOnlyOnce(injectedServerLifecycleListener); + } + + @Test + public void itAddsBoundProvider() { + Set> components = environment.jersey().getResourceConfig().getClasses(); + assertThat(components).containsOnlyOnce(InjectedProvider.class); + } + + @Test + public void itAddsBoundResource() { + Set> resourceClasses = environment.jersey().getResourceConfig().getClasses(); + assertThat(resourceClasses).containsOnlyOnce(ExplicitResource.class); + } + + @Test + public void itAddsProvidedManaged() { + ProvidedManaged providedManaged = guiceBundle + .getInjector() + .getInstance(ProvidedManaged.class); + assertThat(environment.lifecycle().getManagedObjects()) + .extracting("managed") + .containsOnlyOnce(providedManaged); + } + + @Test + public void itAddsProvidedTask() { + ProvidedTask providedTask = guiceBundle.getInjector().getInstance(ProvidedTask.class); + assertThat(environment.admin()) + .extracting("tasks") + .flatExtracting("tasks") + .containsOnlyOnce(providedTask); + } + + @Test + public void itAddsProvidedHealthCheck() { + assertThat(environment.healthChecks().getNames()) + .containsOnlyOnce(ProvidedHealthCheck.class.getSimpleName()); + } + + @Test + public void itAddsProvidedServerLifecycleListener() { + ProvidedServerLifecycleListener providedServerLifecycleListener = guiceBundle + .getInjector() + .getInstance(ProvidedServerLifecycleListener.class); + assertThat(environment.lifecycle()) + .extracting(Function.identity()) + .flatExtracting("lifecycleListeners") + .extracting("listener") + .containsOnlyOnce(providedServerLifecycleListener); + } + + @Test + public void itAddsProvidedProvider() { + Set> components = environment.jersey().getResourceConfig().getClasses(); + assertThat(components).containsOnlyOnce(ProvidedProvider.class); + } } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/HK2LinkerTest.java b/src/test/java/com/hubspot/dropwizard/guicier/HK2LinkerTest.java index 0d7b63c..8c260d5 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/HK2LinkerTest.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/HK2LinkerTest.java @@ -1,71 +1,59 @@ package com.hubspot.dropwizard.guicier; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.*; -import javax.servlet.ServletException; - -import org.glassfish.hk2.api.ServiceLocator; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Test; - -import com.codahale.metrics.MetricRegistry; -import com.fasterxml.jackson.databind.ObjectMapper; import com.google.inject.Binding; import com.google.inject.Injector; import com.google.inject.Key; import com.hubspot.dropwizard.guicier.objects.ExplicitResource; import com.hubspot.dropwizard.guicier.objects.HK2ContextBindings; -import com.hubspot.dropwizard.guicier.objects.TestModule; -import com.squarespace.jersey2.guice.JerseyGuiceUtils; - +import com.hubspot.dropwizard.guicier.objects.TestApplication; import io.dropwizard.Configuration; -import io.dropwizard.jackson.Jackson; -import io.dropwizard.setup.Bootstrap; -import io.dropwizard.setup.Environment; +import io.dropwizard.testing.ResourceHelpers; +import io.dropwizard.testing.junit5.DropwizardAppExtension; +import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; +import javax.servlet.ServletException; +import org.glassfish.jersey.internal.inject.InjectionManager; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +@ExtendWith(DropwizardExtensionsSupport.class) public class HK2LinkerTest { - private Injector injector; - private ServiceLocator serviceLocator; - - @Before - public void setup() throws Exception { - ObjectMapper objectMapper = Jackson.newObjectMapper(); - Environment environment = new Environment("test env", objectMapper, null, new MetricRegistry(), null); - GuiceBundle guiceBundle = GuiceBundle.defaultBuilder(Configuration.class) - .modules(new TestModule()) - .build(); - Bootstrap bootstrap = mock(Bootstrap.class); - when(bootstrap.getObjectMapper()).thenReturn(objectMapper); - guiceBundle.initialize(bootstrap); - guiceBundle.run(new Configuration(), environment); - - injector = guiceBundle.getInjector(); - serviceLocator = injector.getInstance(ServiceLocator.class); - } - - @AfterClass - public static void tearDown() { - JerseyGuiceUtils.reset(); - } - - @Test - public void explicitGuiceBindingsAreBridgedToHk2() throws ServletException { - ExplicitResource resource = serviceLocator.createAndInitialize(ExplicitResource.class); - - assertThat(resource).isNotNull(); - assertThat(resource.getDAO()).isNotNull(); - } - - @Test - public void contextBindingsAreBridgedToGuice() { - for (Class clazz : HK2ContextBindings.SET) { - Binding binding = injector.getExistingBinding(Key.get(clazz)); - assertThat(binding) - .as("%s has a Guice binding", clazz.getName()) - .isNotNull(); - } + private static final DropwizardAppExtension EXT = + new DropwizardAppExtension<>( + TestApplication.class, + ResourceHelpers.resourceFilePath("test-config.yml") + ); + + private Injector injector; + private InjectionManager injectionManager; + + @BeforeEach + public void setup() { + TestApplication testApplication = EXT.getApplication(); + GuiceBundle guiceBundle = testApplication.getGuiceBundle(); + + injector = guiceBundle.getInjector(); + injectionManager = injector.getInstance(InjectionManager.class); + } + + @Test + public void explicitGuiceBindingsAreBridgedToHk2() throws ServletException { + ExplicitResource resource = injectionManager.createAndInitialize( + ExplicitResource.class + ); + + assertThat(resource).isNotNull(); + assertThat(resource.getDAO()).isNotNull(); + } + + @Test + public void contextBindingsAreBridgedToGuice() { + for (Class clazz : HK2ContextBindings.SET) { + Binding binding = injector.getExistingBinding(Key.get(clazz)); + assertThat(binding).as("%s has a Guice binding", clazz.getName()).isNotNull(); } + } } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java b/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java index a863faa..8250eba 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java @@ -2,71 +2,56 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.io.File; - -import javax.ws.rs.client.Client; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; - -import com.google.common.io.Resources; import com.hubspot.dropwizard.guicier.objects.HK2ContextBindings; import com.hubspot.dropwizard.guicier.objects.TestApplication; -import com.squarespace.jersey2.guice.JerseyGuiceUtils; - import io.dropwizard.Configuration; -import io.dropwizard.client.JerseyClientBuilder; -import io.dropwizard.testing.junit.DropwizardAppRule; +import io.dropwizard.testing.ResourceHelpers; +import io.dropwizard.testing.junit5.DropwizardAppExtension; +import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; +import javax.ws.rs.client.Client; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +@ExtendWith(DropwizardExtensionsSupport.class) public class InjectedIntegrationTest { - @ClassRule - public static final DropwizardAppRule RULE = - new DropwizardAppRule<>(TestApplication.class, resourceFilePath("test-config.yml")); - - protected static Client client; - - @BeforeClass - public static void setUp() { - client = new JerseyClientBuilder(RULE.getEnvironment()).build("test client"); + private static final DropwizardAppExtension EXT = + new DropwizardAppExtension<>( + TestApplication.class, + ResourceHelpers.resourceFilePath("test-config.yml") + ); + + protected static Client client; + + @BeforeAll + public static void setUp() { + client = EXT.client(); + } + + @Test + public void shouldGetExplicitMessage() { + String message = client + .target(getUri("/explicit/message")) + .request() + .get(String.class); + assertThat(message).isEqualTo("this DAO was bound explicitly"); + } + + @Test + public void hk2ContextBindingsAreResolvableInGuice() { + for (Class clazz : HK2ContextBindings.SET) { + boolean resolvable = client + .target(getUri("/jersey-context/is-resolvable-by-guice")) + .queryParam("className", clazz.getName()) + .request() + .get(Boolean.class); + assertThat(resolvable).as("%s is resolvable by Guice", clazz.getName()).isTrue(); } + } - @AfterClass - public static void tearDown() { - JerseyGuiceUtils.reset(); - } - - public static String resourceFilePath(String resourceClassPathLocation) { - try { - return new File(Resources.getResource(resourceClassPathLocation).toURI()).getAbsolutePath(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Test - public void shouldGetExplicitMessage() { - String message = client.target(getUri("/explicit/message")).request().get(String.class); - assertThat(message).isEqualTo("this DAO was bound explicitly"); - } - - @Test - public void hk2ContextBindingsAreResolvableInGuice() { - for (Class clazz : HK2ContextBindings.SET) { - boolean resolvable = client.target(getUri("/jersey-context/is-resolvable-by-guice")) - .queryParam("className", clazz.getName()) - .request() - .get(Boolean.class); - assertThat(resolvable) - .as("%s is resolvable by Guice", clazz.getName()) - .isTrue(); - } - } - - private static String getUri(String path) { - String domain = "http://localhost:" + RULE.getLocalPort(); - return domain + (path.startsWith("/") ? "" : "/") + path; - } + private static String getUri(String path) { + String domain = "http://localhost:" + EXT.getLocalPort(); + return domain + (path.startsWith("/") ? "" : "/") + path; + } } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/InjectedResourcesTest.java b/src/test/java/com/hubspot/dropwizard/guicier/InjectedResourcesTest.java index 14530ee..e5ed093 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/InjectedResourcesTest.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/InjectedResourcesTest.java @@ -2,36 +2,31 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.junit.ClassRule; -import org.junit.Test; - -import com.squarespace.jersey2.guice.JerseyGuiceUtils; - import com.hubspot.dropwizard.guicier.objects.ExplicitDAO; import com.hubspot.dropwizard.guicier.objects.ExplicitResource; -import io.dropwizard.testing.junit.ResourceTestRule; +import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; +import io.dropwizard.testing.junit5.ResourceExtension; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; /** * this test is created to address to Null Pointer Exceptions in JerseyTest.teardown() related to ServiceLocator * See: https://github.com/dropwizard/dropwizard/issues/828 and http://permalink.gmane.org/gmane.comp.java.dropwizard.devel/376 */ +@ExtendWith(DropwizardExtensionsSupport.class) public class InjectedResourcesTest { - static { - JerseyGuiceUtils.reset(); - } - - @ClassRule - public static final ResourceTestRule resources = ResourceTestRule.builder() - .addResource(new ExplicitResource(new ExplicitDAO())) - .build(); + private static final ResourceExtension EXT = ResourceExtension + .builder() + .addResource(new ExplicitResource(new ExplicitDAO())) + .build(); - @Test - public void shouldGetExplicitMessage() { - // when - String message = resources.client().target("/explicit/message").request().get(String.class); + @Test + public void shouldGetExplicitMessage() { + // when + String message = EXT.client().target("/explicit/message").request().get(String.class); - // then - assertThat(message).isEqualTo("this DAO was bound explicitly"); - } + // then + assertThat(message).isEqualTo("this DAO was bound explicitly"); + } } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/ExplicitDAO.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/ExplicitDAO.java index 847bbee..05dc48c 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/ExplicitDAO.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/ExplicitDAO.java @@ -4,11 +4,10 @@ public class ExplicitDAO { - @Inject - public ExplicitDAO() {} - - public String getMessage() { - return "this DAO was bound explicitly"; - } + @Inject + public ExplicitDAO() {} + public String getMessage() { + return "this DAO was bound explicitly"; + } } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/ExplicitResource.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/ExplicitResource.java index cbb6bea..b4f0790 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/ExplicitResource.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/ExplicitResource.java @@ -2,30 +2,29 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import com.google.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; -import com.google.inject.Inject; - @Path("/explicit") @Produces(APPLICATION_JSON) public class ExplicitResource { - private final ExplicitDAO dao; - @Inject - public ExplicitResource(ExplicitDAO dao) { - this.dao = dao; - } + private final ExplicitDAO dao; - @GET - @Path("/message") - public String getMessage () { - return dao.getMessage(); - } + @Inject + public ExplicitResource(ExplicitDAO dao) { + this.dao = dao; + } - public ExplicitDAO getDAO() { - return dao; - } + @GET + @Path("/message") + public String getMessage() { + return dao.getMessage(); + } + public ExplicitDAO getDAO() { + return dao; + } } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/HK2ContextBindings.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/HK2ContextBindings.java index f4ca93c..4b74a79 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/HK2ContextBindings.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/HK2ContextBindings.java @@ -1,7 +1,7 @@ package com.hubspot.dropwizard.guicier.objects; +import com.google.common.collect.ImmutableSet; import java.util.Set; - import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; @@ -14,12 +14,10 @@ import javax.ws.rs.core.SecurityContext; import javax.ws.rs.core.UriInfo; import javax.ws.rs.ext.Providers; - import org.glassfish.jersey.server.ExtendedUriInfo; -import com.google.common.collect.ImmutableSet; - public class HK2ContextBindings { + // This list comes from https://stackoverflow.com/a/35868654 public static final Set> SET = ImmutableSet.of( Application.class, @@ -36,7 +34,8 @@ public class HK2ContextBindings { ServletContext.class, UriInfo.class, // Jersey-specific - ExtendedUriInfo.class); + ExtendedUriInfo.class + ); private HK2ContextBindings() { throw new AssertionError(); diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedHealthCheck.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedHealthCheck.java index 0902fa2..9d36387 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedHealthCheck.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedHealthCheck.java @@ -5,11 +5,11 @@ public class InjectedHealthCheck extends HealthCheck { - @Inject - InjectedHealthCheck() {} + @Inject + InjectedHealthCheck() {} - @Override - protected Result check() throws Exception { - return Result.healthy(); - } + @Override + protected Result check() throws Exception { + return Result.healthy(); + } } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedManaged.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedManaged.java index 6f7138e..6ad7a3e 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedManaged.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedManaged.java @@ -2,21 +2,17 @@ import com.google.inject.Inject; import com.google.inject.Singleton; - import io.dropwizard.lifecycle.Managed; @Singleton public class InjectedManaged implements Managed { - @Inject - InjectedManaged() {} - - @Override - public void start() throws Exception { - } + @Inject + InjectedManaged() {} - @Override - public void stop() throws Exception { + @Override + public void start() throws Exception {} - } + @Override + public void stop() throws Exception {} } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedProvider.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedProvider.java index 734d55c..09a329d 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedProvider.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedProvider.java @@ -1,8 +1,7 @@ package com.hubspot.dropwizard.guicier.objects; -import javax.ws.rs.ext.Provider; - import com.google.inject.Inject; +import javax.ws.rs.ext.Provider; @Provider public class InjectedProvider { diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedServerLifecycleListener.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedServerLifecycleListener.java index 79a65e1..a733a01 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedServerLifecycleListener.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedServerLifecycleListener.java @@ -1,11 +1,9 @@ package com.hubspot.dropwizard.guicier.objects; -import org.eclipse.jetty.server.Server; - import com.google.inject.Inject; import com.google.inject.Singleton; - import io.dropwizard.lifecycle.ServerLifecycleListener; +import org.eclipse.jetty.server.Server; @Singleton public class InjectedServerLifecycleListener implements ServerLifecycleListener { @@ -14,7 +12,5 @@ public class InjectedServerLifecycleListener implements ServerLifecycleListener InjectedServerLifecycleListener() {} @Override - public void serverStarted(Server server) { - - } + public void serverStarted(Server server) {} } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedTask.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedTask.java index 56ec86d..ba54598 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedTask.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/InjectedTask.java @@ -1,24 +1,22 @@ package com.hubspot.dropwizard.guicier.objects; -import java.io.PrintWriter; - -import com.google.common.collect.ImmutableMultimap; import com.google.inject.Inject; import com.google.inject.Singleton; import com.google.inject.name.Named; - import io.dropwizard.servlets.tasks.Task; +import java.io.PrintWriter; +import java.util.List; +import java.util.Map; @Singleton public class InjectedTask extends Task { - @Inject - protected InjectedTask(@Named("TestTaskName") String name) { - super(name); - } - - @Override - public void execute(ImmutableMultimap immutableMultimap, PrintWriter printWriter) throws Exception { + @Inject + protected InjectedTask(@Named("TestTaskName") String name) { + super(name); + } - } + @Override + public void execute(Map> parameters, PrintWriter output) + throws Exception {} } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/InstanceManaged.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/InstanceManaged.java index 1a6a3dd..afd3516 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/InstanceManaged.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/InstanceManaged.java @@ -3,11 +3,10 @@ import io.dropwizard.lifecycle.Managed; public class InstanceManaged implements Managed { - @Override - public void start() { - } - @Override - public void stop() { - } + @Override + public void start() {} + + @Override + public void stop() {} } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/JerseyContextResource.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/JerseyContextResource.java index f44a154..7fcd5d0 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/JerseyContextResource.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/JerseyContextResource.java @@ -2,18 +2,18 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import com.google.inject.ConfigurationException; +import com.google.inject.Inject; +import com.google.inject.Injector; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; -import com.google.inject.ConfigurationException; -import com.google.inject.Inject; -import com.google.inject.Injector; - @Path("/jersey-context") @Produces(APPLICATION_JSON) public class JerseyContextResource { + private final Injector injector; @Inject @@ -23,7 +23,8 @@ public JerseyContextResource(Injector injector) { @GET @Path("/is-resolvable-by-guice") - public boolean isResolvableByGuice(@QueryParam("className") String className) throws ClassNotFoundException { + public boolean isResolvableByGuice(@QueryParam("className") String className) + throws ClassNotFoundException { Class clazz = Class.forName(className); try { return injector.getInstance(clazz) != null; diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedHealthCheck.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedHealthCheck.java index 9ad773d..7d40509 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedHealthCheck.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedHealthCheck.java @@ -4,8 +4,8 @@ public class ProvidedHealthCheck extends HealthCheck { - @Override - protected Result check() { - return Result.healthy(); - } + @Override + protected Result check() { + return Result.healthy(); + } } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedManaged.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedManaged.java index ed19f65..8d0e9da 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedManaged.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedManaged.java @@ -4,12 +4,9 @@ public class ProvidedManaged implements Managed { - @Override - public void start() { - } + @Override + public void start() {} - @Override - public void stop() { - - } + @Override + public void stop() {} } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedProvider.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedProvider.java index 3ff0ca8..999cff4 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedProvider.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedProvider.java @@ -3,5 +3,4 @@ import javax.ws.rs.ext.Provider; @Provider -public class ProvidedProvider { -} +public class ProvidedProvider {} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedServerLifecycleListener.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedServerLifecycleListener.java index 6ad4865..75cd2cc 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedServerLifecycleListener.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedServerLifecycleListener.java @@ -6,7 +6,5 @@ public class ProvidedServerLifecycleListener implements ServerLifecycleListener { @Override - public void serverStarted(Server server) { - - } + public void serverStarted(Server server) {} } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedTask.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedTask.java index a84645f..446b128 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedTask.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/ProvidedTask.java @@ -1,18 +1,17 @@ package com.hubspot.dropwizard.guicier.objects; -import java.io.PrintWriter; - -import com.google.common.collect.ImmutableMultimap; import io.dropwizard.servlets.tasks.Task; +import java.io.PrintWriter; +import java.util.List; +import java.util.Map; public class ProvidedTask extends Task { - public ProvidedTask(String name) { - super(name); - } - - @Override - public void execute(ImmutableMultimap immutableMultimap, PrintWriter printWriter) { + public ProvidedTask(String name) { + super(name); + } - } + @Override + public void execute(Map> parameters, PrintWriter output) + throws Exception {} } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/ProviderManaged.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/ProviderManaged.java index 49c0dd1..2dddb3f 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/ProviderManaged.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/ProviderManaged.java @@ -3,11 +3,10 @@ import io.dropwizard.lifecycle.Managed; public class ProviderManaged implements Managed { - @Override - public void start() { - } - @Override - public void stop() { - } + @Override + public void start() {} + + @Override + public void stop() {} } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/ProviderManagedProvider.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/ProviderManagedProvider.java index b1cfd57..53dafd8 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/ProviderManagedProvider.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/ProviderManagedProvider.java @@ -4,12 +4,12 @@ import javax.inject.Provider; public class ProviderManagedProvider implements Provider { - @Inject - public ProviderManagedProvider() { - } - - @Override - public ProviderManaged get() { - return new ProviderManaged(); - } + + @Inject + public ProviderManagedProvider() {} + + @Override + public ProviderManaged get() { + return new ProviderManaged(); + } } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestApplication.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestApplication.java index 4770db3..85d1d31 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestApplication.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestApplication.java @@ -1,7 +1,6 @@ package com.hubspot.dropwizard.guicier.objects; import com.hubspot.dropwizard.guicier.GuiceBundle; - import io.dropwizard.Application; import io.dropwizard.Configuration; import io.dropwizard.setup.Bootstrap; @@ -9,16 +8,20 @@ public class TestApplication extends Application { - @Override - public void initialize(final Bootstrap bootstrap) { - final GuiceBundle jersey2GuiceBundle = GuiceBundle.defaultBuilder(Configuration.class) - .modules(new TestModule()) - .build(); - bootstrap.addBundle(jersey2GuiceBundle); - } + private GuiceBundle guiceBundle; + + public GuiceBundle getGuiceBundle() { + return guiceBundle; + } - @Override - public void run(Configuration configuration, Environment environment) throws Exception { + @Override + public void initialize(final Bootstrap bootstrap) { + this.guiceBundle = + GuiceBundle.defaultBuilder(Configuration.class).modules(new TestModule()).build(); + bootstrap.addBundle(guiceBundle); + } - } + @Override + public void run(Configuration configuration, Environment environment) + throws Exception {} } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java index ce4be69..fc1f43c 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java @@ -1,61 +1,62 @@ package com.hubspot.dropwizard.guicier.objects; -import javax.inject.Singleton; - import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.Scopes; import com.google.inject.name.Named; import com.google.inject.name.Names; +import javax.inject.Singleton; public class TestModule extends AbstractModule { - @Override - protected void configure() { - bind(ExplicitDAO.class); - bindConstant().annotatedWith(Names.named("TestTaskName")).to("injected task"); - bindConstant().annotatedWith(Names.named("ProvidedTaskName")).to("provided task"); - - bind(InstanceManaged.class).toInstance(new InstanceManaged()); - bind(ProviderManaged.class).toProvider(ProviderManagedProvider.class).in(Scopes.SINGLETON); - - bind(InjectedManaged.class).asEagerSingleton(); - bind(InjectedTask.class).asEagerSingleton(); - bind(InjectedHealthCheck.class).asEagerSingleton(); - bind(InjectedServerLifecycleListener.class).asEagerSingleton(); - - bind(InjectedProvider.class); - - bind(ExplicitResource.class); - bind(JerseyContextResource.class); - } - - @Provides - @Singleton - public ProvidedManaged provideManaged() { - return new ProvidedManaged(); - } - - @Provides - @Singleton - public ProvidedTask provideTask(@Named("ProvidedTaskName") String name) { - return new ProvidedTask(name); - } - - @Provides - @Singleton - public ProvidedHealthCheck provideHealthCheck() { - return new ProvidedHealthCheck(); - } - - @Provides - @Singleton - public ProvidedServerLifecycleListener provideServerLifecycleListener() { - return new ProvidedServerLifecycleListener(); - } - - @Provides - public ProvidedProvider provideProvider() { - return new ProvidedProvider(); - } -} + @Override + protected void configure() { + bind(ExplicitDAO.class); + bindConstant().annotatedWith(Names.named("TestTaskName")).to("injected task"); + bindConstant().annotatedWith(Names.named("ProvidedTaskName")).to("provided task"); + + bind(InstanceManaged.class).toInstance(new InstanceManaged()); + bind(ProviderManaged.class) + .toProvider(ProviderManagedProvider.class) + .in(Scopes.SINGLETON); + + bind(InjectedManaged.class).asEagerSingleton(); + bind(InjectedTask.class).asEagerSingleton(); + bind(InjectedHealthCheck.class).asEagerSingleton(); + bind(InjectedServerLifecycleListener.class).asEagerSingleton(); + + bind(InjectedProvider.class); + + bind(ExplicitResource.class); + bind(JerseyContextResource.class); + } + + @Provides + @Singleton + public ProvidedManaged provideManaged() { + return new ProvidedManaged(); + } + + @Provides + @Singleton + public ProvidedTask provideTask(@Named("ProvidedTaskName") String name) { + return new ProvidedTask(name); + } + + @Provides + @Singleton + public ProvidedHealthCheck provideHealthCheck() { + return new ProvidedHealthCheck(); + } + + @Provides + @Singleton + public ProvidedServerLifecycleListener provideServerLifecycleListener() { + return new ProvidedServerLifecycleListener(); + } + + @Provides + public ProvidedProvider provideProvider() { + return new ProvidedProvider(); + } +} From a00499bcc850e301da09fc2f0b7fdbd58e8150a9 Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Tue, 25 Mar 2025 12:11:33 -0400 Subject: [PATCH 02/21] use ephemeral port in tests --- src/test/resources/test-config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/test-config.yml b/src/test/resources/test-config.yml index fcf8aaf..e2852c0 100644 --- a/src/test/resources/test-config.yml +++ b/src/test/resources/test-config.yml @@ -4,4 +4,4 @@ server: adminContextPath: /admin connector: type: http - port: 9999 + port: 0 From 0789b3f9c647380e970962e087c74e5bb1b2d5f9 Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Tue, 25 Mar 2025 12:42:13 -0400 Subject: [PATCH 03/21] use managed deps from basepom --- pom.xml | 129 +++++++++++++++++--------------------------------------- 1 file changed, 39 insertions(+), 90 deletions(-) diff --git a/pom.xml b/pom.xml index 441ed5a..e782b48 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.hubspot basepom - 61.7 + 1.0-js-manage-jerseydeps-SNAPSHOT com.hubspot.dropwizard @@ -25,75 +25,26 @@ 11 - - - - ch.qos.logback - logback-access - ${dep.logback.version} - - - jakarta.servlet - jakarta.servlet-api - 4.0.4 - - - jakarta.ws.rs - jakarta.ws.rs-api - 2.1.6 - - - org.eclipse.jetty - jetty-server - ${dep.jetty.version} - - - javax.servlet - javax.servlet-api - - - - - org.glassfish.hk2 - guice-bridge - ${dep.hk2.version} - - - org.glassfish.jersey.inject - jersey-hk2 - ${dep.jersey2.version} - - - - - com.google.inject - guice - - - com.google.inject.extensions - guice-servlet + com.fasterxml.jackson.core + jackson-databind com.google.code.findbugs annotations - - javax.inject - javax.inject - com.google.guava guava - org.slf4j - slf4j-api + com.google.inject + guice - io.dropwizard - dropwizard-servlets + com.google.inject.extensions + guice-servlet io.dropwizard @@ -101,64 +52,72 @@ io.dropwizard - dropwizard-lifecycle + dropwizard-jersey io.dropwizard - dropwizard-jersey + dropwizard-jetty io.dropwizard - dropwizard-jetty + dropwizard-lifecycle + + + io.dropwizard + dropwizard-servlets io.dropwizard.metrics metrics-healthchecks - org.glassfish.jersey.core - jersey-common + jakarta.servlet + jakarta.servlet-api - org.glassfish.jersey.core - jersey-server + jakarta.ws.rs + jakarta.ws.rs-api - org.glassfish.jersey.inject - jersey-hk2 + javax.inject + javax.inject + + + org.eclipse.jetty + jetty-server org.glassfish.hk2 - hk2-api + guice-bridge org.glassfish.hk2 - hk2-utils + hk2-api org.glassfish.hk2 - guice-bridge + hk2-utils - com.fasterxml.jackson.core - jackson-databind + org.glassfish.jersey.core + jersey-common - org.eclipse.jetty - jetty-server + org.glassfish.jersey.core + jersey-server - jakarta.servlet - jakarta.servlet-api + org.glassfish.jersey.inject + jersey-hk2 - jakarta.ws.rs - jakarta.ws.rs-api + org.slf4j + slf4j-api - org.junit.jupiter - junit-jupiter-api + io.dropwizard + dropwizard-testing test @@ -167,18 +126,8 @@ test - org.mockito - mockito-core - test - - - io.dropwizard - dropwizard-testing - test - - - io.dropwizard - dropwizard-client + org.junit.jupiter + junit-jupiter-api test From a574557b13fd2263915c7fe3abb9a0f8cf5a5018 Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Wed, 26 Mar 2025 23:34:44 -0400 Subject: [PATCH 04/21] switch to InjectionManagerFactory --- pom.xml | 4 + .../dropwizard/guicier/DropwizardModule.java | 2 + .../guicier/JerseyGuicierModule.java | 7 +- .../bridge/GuiceComponentProvider.java | 61 ------------- .../bridge/GuiceInjectionResolver.java | 52 ----------- .../{bridge => injection}/BindingUtils.java | 10 +-- .../BridgedGuiceInjectionManagerFactory.java | 58 ++++++++++++ .../injection/GuiceInjectionResolver.java | 89 +++++++++++++++++++ .../InjectionManagerProvider.java | 2 +- .../guicier/injection/InjectorProvider.java | 21 +++++ ...ey.internal.inject.InjectionManagerFactory | 1 + ...ssfish.jersey.server.spi.ComponentProvider | 1 - .../guicier/InjectedIntegrationTest.java | 25 ++++-- .../guicier/objects/TestModule.java | 2 + .../guicier/objects/TestValueParam.java | 11 +++ .../objects/TestValueParamFeature.java | 31 +++++++ .../objects/TestValueParamProvider.java | 29 ++++++ 17 files changed, 276 insertions(+), 130 deletions(-) delete mode 100644 src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceComponentProvider.java delete mode 100644 src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceInjectionResolver.java rename src/main/java/com/hubspot/dropwizard/guicier/{bridge => injection}/BindingUtils.java (95%) create mode 100644 src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java create mode 100644 src/main/java/com/hubspot/dropwizard/guicier/injection/GuiceInjectionResolver.java rename src/main/java/com/hubspot/dropwizard/guicier/{bridge => injection}/InjectionManagerProvider.java (93%) create mode 100644 src/main/java/com/hubspot/dropwizard/guicier/injection/InjectorProvider.java create mode 100644 src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory delete mode 100644 src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ComponentProvider create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/objects/TestValueParam.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/objects/TestValueParamFeature.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/objects/TestValueParamProvider.java diff --git a/pom.xml b/pom.xml index e782b48..8322f52 100644 --- a/pom.xml +++ b/pom.xml @@ -70,6 +70,10 @@ io.dropwizard.metrics metrics-healthchecks + + jakarta.annotation + jakarta.annotation-api + jakarta.servlet jakarta.servlet-api diff --git a/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java b/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java index 3596a63..695bc8c 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java @@ -7,6 +7,7 @@ import com.google.inject.Module; import com.google.inject.matcher.Matchers; import com.google.inject.spi.ProvisionListener; +import com.hubspot.dropwizard.guicier.injection.InjectorProvider; import io.dropwizard.lifecycle.Managed; import io.dropwizard.lifecycle.ServerLifecycleListener; import io.dropwizard.servlets.tasks.Task; @@ -60,6 +61,7 @@ public void onProvision(ProvisionInvocation provision) { public void register(Injector injector) { registerResourcesAndProviders(environment.jersey().getResourceConfig(), injector); + InjectorProvider.set(injector); } private void handle(Managed managed) { diff --git a/src/main/java/com/hubspot/dropwizard/guicier/JerseyGuicierModule.java b/src/main/java/com/hubspot/dropwizard/guicier/JerseyGuicierModule.java index 551be7f..931dabf 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/JerseyGuicierModule.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/JerseyGuicierModule.java @@ -2,8 +2,9 @@ import com.google.inject.AbstractModule; import com.google.inject.Provides; +import com.google.inject.Scopes; import com.google.inject.servlet.RequestScoped; -import com.hubspot.dropwizard.guicier.bridge.InjectionManagerProvider; +import com.hubspot.dropwizard.guicier.injection.InjectionManagerProvider; import javax.servlet.ServletConfig; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ResourceContext; @@ -24,7 +25,9 @@ public class JerseyGuicierModule extends AbstractModule { @Override protected void configure() { - bind(InjectionManager.class).toProvider(InjectionManagerProvider.class); + bind(InjectionManager.class) + .toProvider(InjectionManagerProvider.class) + .in(Scopes.NO_SCOPE); } @Provides diff --git a/src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceComponentProvider.java b/src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceComponentProvider.java deleted file mode 100644 index 6c72fb7..0000000 --- a/src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceComponentProvider.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.hubspot.dropwizard.guicier.bridge; - -import com.google.inject.Injector; -import java.util.Set; -import javax.servlet.ServletContext; -import org.glassfish.jersey.inject.hk2.ImmediateHk2InjectionManager; -import org.glassfish.jersey.internal.inject.Bindings; -import org.glassfish.jersey.internal.inject.InjectionManager; -import org.glassfish.jersey.server.spi.ComponentProvider; -import org.jvnet.hk2.guice.bridge.api.GuiceBridge; -import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class GuiceComponentProvider implements ComponentProvider { - - private static final Logger LOG = LoggerFactory.getLogger(GuiceComponentProvider.class); - - private volatile Injector guiceInjector; - - @Override - public void initialize(InjectionManager injectionManager) { - InjectionManagerProvider.set(injectionManager); - - ServletContext sc = injectionManager.getInstance(ServletContext.class); - if (sc != null) { - guiceInjector = (Injector) sc.getAttribute(Injector.class.getName()); - } - - if (guiceInjector == null) { - LOG.error("Failed to lookup guice injector from servlet context"); - return; - } - - // initialize HK2 guice-bridge - ImmediateHk2InjectionManager hk2InjectionManager = - (ImmediateHk2InjectionManager) injectionManager; - GuiceBridge - .getGuiceBridge() - .initializeGuiceBridge(hk2InjectionManager.getServiceLocator()); - GuiceIntoHK2Bridge guiceBridge = injectionManager.getInstance( - GuiceIntoHK2Bridge.class - ); - guiceBridge.bridgeGuiceInjector(guiceInjector); - - injectionManager.register( - Bindings.injectionResolver(new GuiceInjectionResolver(guiceInjector)) - ); - injectionManager.register(Bindings.service(guiceInjector).to(Injector.class)); - - LOG.debug("Guice Component Provider initialized"); - } - - @Override - public boolean bind(Class component, Set> providerContracts) { - return false; - } - - @Override - public void done() {} -} diff --git a/src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceInjectionResolver.java b/src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceInjectionResolver.java deleted file mode 100644 index 68e684a..0000000 --- a/src/main/java/com/hubspot/dropwizard/guicier/bridge/GuiceInjectionResolver.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.hubspot.dropwizard.guicier.bridge; - -import com.google.inject.Inject; -import com.google.inject.Injector; -import com.google.inject.Key; -import javax.inject.Singleton; -import org.glassfish.jersey.internal.inject.Injectee; -import org.glassfish.jersey.internal.inject.InjectionResolver; - -@Singleton -public class GuiceInjectionResolver implements InjectionResolver { - - private final Injector injector; - - public GuiceInjectionResolver(Injector injector) { - this.injector = injector; - } - - @Override - public Object resolve(Injectee injectee) { - Key key = BindingUtils.toKey(injectee); - - Object instance = injector.getInstance(key); - - if (instance == null) { - if (BindingUtils.isNullable(injectee)) { - return null; - } - - throw new RuntimeException( - "There was no object available for injection at " + injectee - ); - } - - return instance; - } - - @Override - public boolean isConstructorParameterIndicator() { - return true; - } - - @Override - public boolean isMethodParameterIndicator() { - return false; - } - - @Override - public Class getAnnotation() { - return Inject.class; - } -} diff --git a/src/main/java/com/hubspot/dropwizard/guicier/bridge/BindingUtils.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java similarity index 95% rename from src/main/java/com/hubspot/dropwizard/guicier/bridge/BindingUtils.java rename to src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java index ace0844..00cec8a 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/bridge/BindingUtils.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java @@ -1,4 +1,4 @@ -package com.hubspot.dropwizard.guicier.bridge; +package com.hubspot.dropwizard.guicier.injection; import com.google.inject.BindingAnnotation; import com.google.inject.Key; @@ -84,7 +84,7 @@ private static boolean isGuiceOptional(AnnotatedElement element) { */ public static boolean isHk2Contract(Injectee injectee) { Type type = injectee.getRequiredType(); - return isContact(type, org.jvnet.hk2.annotations.Contract.class); + return hasTypeAnnotation(type, org.jvnet.hk2.annotations.Contract.class); } /** @@ -95,10 +95,10 @@ public static boolean isHk2Contract(Injectee injectee) { */ public static boolean isJerseyContract(Injectee injectee) { Type type = injectee.getRequiredType(); - return isContact(type, org.glassfish.jersey.spi.Contract.class); + return hasTypeAnnotation(type, org.glassfish.jersey.spi.Contract.class); } - private static boolean isContact( + public static boolean hasTypeAnnotation( Type type, Class annotationType ) { @@ -108,7 +108,7 @@ private static boolean isContact( if (type instanceof ParameterizedType) { Type rawType = ((ParameterizedType) type).getRawType(); - return isContact(rawType, annotationType); + return hasTypeAnnotation(rawType, annotationType); } return false; diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java new file mode 100644 index 0000000..578983e --- /dev/null +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java @@ -0,0 +1,58 @@ +package com.hubspot.dropwizard.guicier.injection; + +import com.google.inject.Injector; +import javax.annotation.Priority; +import javax.ws.rs.ConstrainedTo; +import javax.ws.rs.RuntimeType; +import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory; +import org.glassfish.jersey.inject.hk2.ImmediateHk2InjectionManager; +import org.glassfish.jersey.internal.inject.Bindings; +import org.glassfish.jersey.internal.inject.InjectionManager; +import org.glassfish.jersey.internal.inject.InjectionManagerFactory; +import org.jvnet.hk2.guice.bridge.api.GuiceBridge; +import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Priority(15) +@ConstrainedTo(RuntimeType.SERVER) +public class BridgedGuiceInjectionManagerFactory implements InjectionManagerFactory { + + private static final Logger LOG = LoggerFactory.getLogger( + BridgedGuiceInjectionManagerFactory.class + ); + + @Override + public InjectionManager create(Object parent) { + ImmediateHk2InjectionManager injectionManager = + (ImmediateHk2InjectionManager) new Hk2InjectionManagerFactory().create(parent); + + Injector guiceInjector = new InjectorProvider().get(); + + if (guiceInjector == null) { + throw new IllegalStateException( + "Failed to lookup guice injector from servlet context" + ); + } + + // initialize HK2 guice-bridge + GuiceBridge + .getGuiceBridge() + .initializeGuiceBridge(injectionManager.getServiceLocator()); + GuiceIntoHK2Bridge guiceBridge = injectionManager.getInstance( + GuiceIntoHK2Bridge.class + ); + guiceBridge.bridgeGuiceInjector(guiceInjector); + + injectionManager.register( + Bindings.injectionResolver( + new GuiceInjectionResolver(guiceInjector, injectionManager.getServiceLocator()) + ) + ); + injectionManager.register(Bindings.service(guiceInjector).to(Injector.class)); + + LOG.info("Guice Component Provider initialized"); + InjectionManagerProvider.set(injectionManager); + return injectionManager; + } +} diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/GuiceInjectionResolver.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/GuiceInjectionResolver.java new file mode 100644 index 0000000..f8f76f9 --- /dev/null +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/GuiceInjectionResolver.java @@ -0,0 +1,89 @@ +package com.hubspot.dropwizard.guicier.injection; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +import javax.inject.Singleton; + +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.hk2.utilities.reflection.ParameterizedTypeImpl; +import org.glassfish.jersey.internal.inject.Injectee; +import org.glassfish.jersey.internal.inject.InjectionResolver; + +import com.google.inject.ConfigurationException; +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Provider; + +@Singleton +public class GuiceInjectionResolver implements InjectionResolver { + + private final Injector injector; + private final ServiceLocator serviceLocator; + + public GuiceInjectionResolver(Injector injector, ServiceLocator serviceLocator) { + this.injector = injector; + this.serviceLocator = serviceLocator; + } + + @Override + public Object resolve(Injectee injectee) { + Key key = BindingUtils.toKey(injectee); + + Object instance = null; + try { + instance = injector.getInstance(key); + } catch (ConfigurationException e) { + /* fallback to jersey hk2 injector */ + } + + if (instance == null) { + Type t = injectee.getRequiredType(); + boolean wrapProvider = false; + if (t instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) t; + if (pt.getRawType().equals(Provider.class)) { + t = + new ParameterizedTypeImpl( + javax.inject.Provider.class, + pt.getActualTypeArguments() + ); + wrapProvider = true; + } + } + instance = serviceLocator.getService(t); + if (instance != null && wrapProvider) { + javax.inject.Provider jaxProvider = (javax.inject.Provider) instance; + return (Provider) jaxProvider::get; + } + } + + if (instance == null) { + if (BindingUtils.isNullable(injectee)) { + return null; + } + + throw new RuntimeException( + "There was no object available for injection at " + injectee + ); + } + + return instance; + } + + @Override + public boolean isConstructorParameterIndicator() { + return true; + } + + @Override + public boolean isMethodParameterIndicator() { + return false; + } + + @Override + public Class getAnnotation() { + return Inject.class; + } +} diff --git a/src/main/java/com/hubspot/dropwizard/guicier/bridge/InjectionManagerProvider.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProvider.java similarity index 93% rename from src/main/java/com/hubspot/dropwizard/guicier/bridge/InjectionManagerProvider.java rename to src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProvider.java index 2e7396e..9b45022 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/bridge/InjectionManagerProvider.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProvider.java @@ -1,4 +1,4 @@ -package com.hubspot.dropwizard.guicier.bridge; +package com.hubspot.dropwizard.guicier.injection; import com.google.common.base.Preconditions; import java.util.concurrent.atomic.AtomicReference; diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectorProvider.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectorProvider.java new file mode 100644 index 0000000..9d6fded --- /dev/null +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectorProvider.java @@ -0,0 +1,21 @@ +package com.hubspot.dropwizard.guicier.injection; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.inject.Injector; +import java.util.concurrent.atomic.AtomicReference; +import javax.inject.Provider; + +public class InjectorProvider implements Provider { + + private static final AtomicReference REF = new AtomicReference<>(); + + public static void set(Injector injector) { + REF.set(injector); + } + + @Override + public Injector get() { + return checkNotNull(REF.get(), "Guice Injector not set"); + } +} diff --git a/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory b/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory new file mode 100644 index 0000000..aa50640 --- /dev/null +++ b/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory @@ -0,0 +1 @@ +com.hubspot.dropwizard.guicier.injection.BridgedGuiceInjectionManagerFactory diff --git a/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ComponentProvider b/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ComponentProvider deleted file mode 100644 index 7406ded..0000000 --- a/src/main/resources/META-INF/services/org.glassfish.jersey.server.spi.ComponentProvider +++ /dev/null @@ -1 +0,0 @@ -com.hubspot.dropwizard.guicier.bridge.GuiceComponentProvider diff --git a/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java b/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java index 8250eba..a89be85 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java @@ -9,6 +9,7 @@ import io.dropwizard.testing.junit5.DropwizardAppExtension; import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; import javax.ws.rs.client.Client; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -40,14 +41,22 @@ public void shouldGetExplicitMessage() { @Test public void hk2ContextBindingsAreResolvableInGuice() { - for (Class clazz : HK2ContextBindings.SET) { - boolean resolvable = client - .target(getUri("/jersey-context/is-resolvable-by-guice")) - .queryParam("className", clazz.getName()) - .request() - .get(Boolean.class); - assertThat(resolvable).as("%s is resolvable by Guice", clazz.getName()).isTrue(); - } + Assertions.assertAll( + HK2ContextBindings.SET + .stream() + .map(clazz -> + () -> { + boolean resolvable = client + .target(getUri("/jersey-context/is-resolvable-by-guice")) + .queryParam("className", clazz.getName()) + .request() + .get(Boolean.class); + assertThat(resolvable) + .as("%s is resolvable by Guice", clazz.getName()) + .isTrue(); + } + ) + ); } private static String getUri(String path) { diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java index fc1f43c..df2ba4d 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java @@ -29,6 +29,8 @@ protected void configure() { bind(ExplicitResource.class); bind(JerseyContextResource.class); + + bind(TestValueParamFeature.class); } @Provides diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestValueParam.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestValueParam.java new file mode 100644 index 0000000..e90085d --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestValueParam.java @@ -0,0 +1,11 @@ +package com.hubspot.dropwizard.guicier.objects; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestValueParam { +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestValueParamFeature.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestValueParamFeature.java new file mode 100644 index 0000000..27cd916 --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestValueParamFeature.java @@ -0,0 +1,31 @@ +package com.hubspot.dropwizard.guicier.objects; + +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.ws.rs.core.Feature; +import javax.ws.rs.core.FeatureContext; +import javax.ws.rs.ext.Provider; +import org.glassfish.hk2.utilities.binding.AbstractBinder; +import org.glassfish.jersey.server.spi.internal.ValueParamProvider; + +@Provider +public class TestValueParamFeature implements Feature { + + @Inject + public TestValueParamFeature() {} + + @Override + public boolean configure(FeatureContext context) { + context.register( + new AbstractBinder() { + @Override + protected void configure() { + bind(TestValueParamProvider.class) + .to(ValueParamProvider.class) + .in(Singleton.class); + } + } + ); + return true; + } +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestValueParamProvider.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestValueParamProvider.java new file mode 100644 index 0000000..c7cbd2d --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestValueParamProvider.java @@ -0,0 +1,29 @@ +package com.hubspot.dropwizard.guicier.objects; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import java.util.function.Function; +import org.glassfish.jersey.model.Parameter.Source; +import org.glassfish.jersey.server.ContainerRequest; +import org.glassfish.jersey.server.internal.inject.AbstractValueParamProvider; +import org.glassfish.jersey.server.internal.inject.MultivaluedParameterExtractorProvider; +import org.glassfish.jersey.server.model.Parameter; + +public class TestValueParamProvider extends AbstractValueParamProvider { + + @Inject + TestValueParamProvider( + Provider extractorProvider + ) { + super(extractorProvider, Source.UNKNOWN); + } + + @Override + protected Function createValueProvider(Parameter parameter) { + if (!parameter.isAnnotationPresent(TestValueParam.class)) { + return null; + } + + return request -> "testparam"; + } +} From 2239d930c114ebceff591bb2a0d7b8deadf5abec Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Thu, 27 Mar 2025 09:29:15 -0400 Subject: [PATCH 05/21] formatting --- .../guicier/injection/GuiceInjectionResolver.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/GuiceInjectionResolver.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/GuiceInjectionResolver.java index f8f76f9..42d9b90 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/GuiceInjectionResolver.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/GuiceInjectionResolver.java @@ -1,21 +1,18 @@ package com.hubspot.dropwizard.guicier.injection; +import com.google.inject.ConfigurationException; +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Provider; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; - import javax.inject.Singleton; - import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.hk2.utilities.reflection.ParameterizedTypeImpl; import org.glassfish.jersey.internal.inject.Injectee; import org.glassfish.jersey.internal.inject.InjectionResolver; -import com.google.inject.ConfigurationException; -import com.google.inject.Inject; -import com.google.inject.Injector; -import com.google.inject.Key; -import com.google.inject.Provider; - @Singleton public class GuiceInjectionResolver implements InjectionResolver { From 09008328a6dacbee19fcc3a0431531c665973e51 Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Thu, 27 Mar 2025 16:24:32 -0400 Subject: [PATCH 06/21] link jersey InjectionManager to guice InjectionManagerProvider in a jax-rs Feature, support guice Provider injection --- .../dropwizard/guicier/GuiceBundle.java | 3 +- .../guicier/injection/BindingUtils.java | 29 +++++++ .../BridgedGuiceInjectionManagerFactory.java | 1 - .../injection/GuiceInjectionResolver.java | 31 +++---- .../injection/InjectionManagerProvider.java | 28 +++++-- .../InjectionManagerProviderFeature.java | 31 +++++++ .../guicier/InjectedIntegrationTest.java | 8 ++ .../dropwizard/guicier/StashesTest.java | 80 ++++++++++++++++++ .../EmptyCtorGoogleInjectResource.java | 21 +++++ .../dropwizard/guicier/objects/Stashed.java | 15 ++++ .../objects/StashedValueFactoryProvider.java | 35 ++++++++ .../guicier/objects/StashedValueFeature.java | 31 +++++++ .../guicier/objects/StashesTestModule.java | 21 +++++ .../guicier/objects/StashesTestResource.java | 82 +++++++++++++++++++ .../guicier/objects/TestModule.java | 5 ++ 15 files changed, 390 insertions(+), 31 deletions(-) create mode 100644 src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProviderFeature.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/StashesTest.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/objects/EmptyCtorGoogleInjectResource.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/objects/Stashed.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/objects/StashedValueFactoryProvider.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/objects/StashedValueFeature.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/objects/StashesTestModule.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/objects/StashesTestResource.java diff --git a/src/main/java/com/hubspot/dropwizard/guicier/GuiceBundle.java b/src/main/java/com/hubspot/dropwizard/guicier/GuiceBundle.java index ca75c62..8cc0acc 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/GuiceBundle.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/GuiceBundle.java @@ -11,6 +11,7 @@ import com.google.inject.servlet.GuiceFilter; import com.google.inject.servlet.GuiceServletContextListener; import com.google.inject.servlet.ServletModule; +import com.hubspot.dropwizard.guicier.injection.InjectionManagerProviderFeature; import io.dropwizard.Configuration; import io.dropwizard.ConfiguredBundle; import io.dropwizard.setup.Bootstrap; @@ -90,6 +91,7 @@ public void run(final T configuration, final Environment environment) throws Exc .add(binder -> { binder.bind(Environment.class).toInstance(environment); binder.bind(configClass).toInstance(configuration); + binder.bind(InjectionManagerProviderFeature.class); }); if (enableGuiceEnforcer) { modulesBuilder.add(new GuiceEnforcerModule()); @@ -97,7 +99,6 @@ public void run(final T configuration, final Environment environment) throws Exc this.injector = injectorFactory.create(guiceStage, modulesBuilder.build()); dropwizardModule.register(injector); - environment .servlets() .addFilter("Guice Filter", GuiceFilter.class) diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java index 00cec8a..21b4c4d 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java @@ -2,6 +2,7 @@ import com.google.inject.BindingAnnotation; import com.google.inject.Key; +import com.google.inject.Provider; import com.google.inject.internal.Nullability; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; @@ -15,11 +16,39 @@ import java.util.Set; import javax.annotation.Nullable; import javax.inject.Qualifier; +import org.glassfish.hk2.utilities.reflection.ParameterizedTypeImpl; import org.glassfish.hk2.utilities.reflection.ReflectionHelper; import org.glassfish.jersey.internal.inject.Injectee; public class BindingUtils { + public static Optional translateGuiceProviderType(Injectee injectee) { + Type requiredType = injectee.getRequiredType(); + if (requiredType instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) requiredType; + if (parameterizedType.getRawType().equals(Provider.class)) { + return Optional.of( + new ParameterizedTypeImpl( + javax.inject.Provider.class, + parameterizedType.getActualTypeArguments() + ) + ); + } + } + return Optional.empty(); + } + + public static Provider javaxToGuiceProvider(Object instance) { + if (!(instance instanceof javax.inject.Provider)) { + throw new IllegalArgumentException( + "Given instance is not of type javax.inject.Provider: " + instance + ); + } + + javax.inject.Provider provider = (javax.inject.Provider) instance; + return provider::get; + } + /** * Returns {@code true} if the given {@link Injectee} can be {@code null}. * diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java index 578983e..69c3a78 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java @@ -52,7 +52,6 @@ public InjectionManager create(Object parent) { injectionManager.register(Bindings.service(guiceInjector).to(Injector.class)); LOG.info("Guice Component Provider initialized"); - InjectionManagerProvider.set(injectionManager); return injectionManager; } } diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/GuiceInjectionResolver.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/GuiceInjectionResolver.java index 42d9b90..faaba0f 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/GuiceInjectionResolver.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/GuiceInjectionResolver.java @@ -4,12 +4,10 @@ import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Key; -import com.google.inject.Provider; -import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.Optional; import javax.inject.Singleton; import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.hk2.utilities.reflection.ParameterizedTypeImpl; import org.glassfish.jersey.internal.inject.Injectee; import org.glassfish.jersey.internal.inject.InjectionResolver; @@ -36,23 +34,16 @@ public Object resolve(Injectee injectee) { } if (instance == null) { - Type t = injectee.getRequiredType(); - boolean wrapProvider = false; - if (t instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType) t; - if (pt.getRawType().equals(Provider.class)) { - t = - new ParameterizedTypeImpl( - javax.inject.Provider.class, - pt.getActualTypeArguments() - ); - wrapProvider = true; - } - } - instance = serviceLocator.getService(t); - if (instance != null && wrapProvider) { - javax.inject.Provider jaxProvider = (javax.inject.Provider) instance; - return (Provider) jaxProvider::get; + Optional translatedGuiceProviderType = + BindingUtils.translateGuiceProviderType(injectee); + + instance = + serviceLocator.getService( + translatedGuiceProviderType.orElse(injectee.getRequiredType()) + ); + + if (instance != null && translatedGuiceProviderType.isPresent()) { + return BindingUtils.javaxToGuiceProvider(instance); } } diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProvider.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProvider.java index 9b45022..19f0cc2 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProvider.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProvider.java @@ -1,27 +1,37 @@ package com.hubspot.dropwizard.guicier.injection; -import com.google.common.base.Preconditions; -import java.util.concurrent.atomic.AtomicReference; +import static com.google.common.base.Preconditions.checkNotNull; + +import io.dropwizard.setup.Environment; +import java.util.HashMap; +import java.util.Map; import javax.inject.Inject; import javax.inject.Provider; +import javax.inject.Singleton; +import javax.ws.rs.core.Application; import org.glassfish.jersey.internal.inject.InjectionManager; +@Singleton public class InjectionManagerProvider implements Provider { - private static final AtomicReference INJECTION_MANAGER_REF = - new AtomicReference<>(); + private static final Map INJECTION_MANAGERS_BY_APP = + new HashMap<>(); + + private final Application application; @Inject - public InjectionManagerProvider() {} + public InjectionManagerProvider(Environment environment) { + this.application = environment.jersey().getResourceConfig(); + } - public static void set(InjectionManager injectionManager) { - INJECTION_MANAGER_REF.set(injectionManager); + public static void set(Application application, InjectionManager injectionManager) { + INJECTION_MANAGERS_BY_APP.put(application, injectionManager); } @Override public InjectionManager get() { - return Preconditions.checkNotNull( - INJECTION_MANAGER_REF.get(), + return checkNotNull( + INJECTION_MANAGERS_BY_APP.get(application), "InjectionManager not set" ); } diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProviderFeature.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProviderFeature.java new file mode 100644 index 0000000..062c695 --- /dev/null +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProviderFeature.java @@ -0,0 +1,31 @@ +package com.hubspot.dropwizard.guicier.injection; + +import javax.inject.Inject; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Feature; +import javax.ws.rs.core.FeatureContext; +import javax.ws.rs.ext.Provider; +import org.glassfish.jersey.internal.inject.InjectionManager; + +/** + * This links the active InjectionManager to the Guice InjectionManagerProvider, + * to the active javax.ws.rs.core.Application, for use in the JerseyGuicierModule. + */ +@Provider +public class InjectionManagerProviderFeature implements Feature { + + private final InjectionManager injectionManager; + + @Inject + public InjectionManagerProviderFeature(InjectionManager injectionManager) { + this.injectionManager = injectionManager; + } + + @Override + public boolean configure(FeatureContext context) { + Application application = injectionManager.getInstance(Application.class); + InjectionManagerProvider.set(application, injectionManager); + + return true; + } +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java b/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java index a89be85..4eaee73 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java @@ -39,6 +39,14 @@ public void shouldGetExplicitMessage() { assertThat(message).isEqualTo("this DAO was bound explicitly"); } + @Test + public void emptyCtorGoogleInject() { + assertThat( + client.target(getUri("/empty-ctor-google-inject")).request().get(String.class) + ) + .isEqualTo("world"); + } + @Test public void hk2ContextBindingsAreResolvableInGuice() { Assertions.assertAll( diff --git a/src/test/java/com/hubspot/dropwizard/guicier/StashesTest.java b/src/test/java/com/hubspot/dropwizard/guicier/StashesTest.java new file mode 100644 index 0000000..88c38f3 --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/StashesTest.java @@ -0,0 +1,80 @@ +package com.hubspot.dropwizard.guicier; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.hubspot.dropwizard.guicier.objects.StashesTestModule; +import com.hubspot.dropwizard.guicier.objects.TestApplication; +import io.dropwizard.Configuration; +import io.dropwizard.testing.ResourceHelpers; +import io.dropwizard.testing.junit5.DropwizardAppExtension; +import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; +import javax.ws.rs.client.Client; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(DropwizardExtensionsSupport.class) +public class StashesTest { + + private static final DropwizardAppExtension EXT = + new DropwizardAppExtension<>( + TestApplication.class, + ResourceHelpers.resourceFilePath("test-config.yml") + ); + + private Client client; + + @BeforeEach + public void setup() { + this.client = EXT.client(); + } + + private int doGet(String path) { + return client + .target("http://localhost:" + EXT.getLocalPort() + "/stashes/" + path) + .request() + .get(int.class); + } + + @Test + public void itConstructorInjectsAStashedInt() { + assertThat(doGet("itConstructorInjectsAStashedInt")) + .isEqualTo(StashesTestModule.STASHED_INT_VALUE); + } + + @Test + public void itConstructorInjectsAStashedIntGuiceProvider() { + assertThat(doGet("itConstructorInjectsAStashedIntGuiceProvider")) + .isEqualTo(StashesTestModule.STASHED_INT_VALUE); + } + + @Test + public void itConstructorInjectsAStashedIntJavaxProvider() { + assertThat(doGet("itConstructorInjectsAStashedIntJavaxProvider")) + .isEqualTo(StashesTestModule.STASHED_INT_VALUE); + } + + @Test + public void itFieldInjectsAStashedInt() { + assertThat(doGet("itFieldInjectsAStashedInt")) + .isEqualTo(StashesTestModule.STASHED_INT_VALUE); + } + + @Test + public void itFieldInjectsAStashedIntGuiceProvider() { + assertThat(doGet("itFieldInjectsAStashedIntGuiceProvider")) + .isEqualTo(StashesTestModule.STASHED_INT_VALUE); + } + + @Test + public void itFieldInjectsAStashedIntJavaxProvider() { + assertThat(doGet("itFieldInjectsAStashedIntJavaxProvider")) + .isEqualTo(StashesTestModule.STASHED_INT_VALUE); + } + + @Test + public void itMethodInjectsAStashedInt() { + assertThat(doGet("itMethodInjectsAStashedInt")) + .isEqualTo(StashesTestModule.STASHED_INT_VALUE); + } +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/EmptyCtorGoogleInjectResource.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/EmptyCtorGoogleInjectResource.java new file mode 100644 index 0000000..f5816d6 --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/EmptyCtorGoogleInjectResource.java @@ -0,0 +1,21 @@ +package com.hubspot.dropwizard.guicier.objects; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + +import com.google.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; + +@Path("/empty-ctor-google-inject") +@Produces(APPLICATION_JSON) +public class EmptyCtorGoogleInjectResource { + + @Inject + public EmptyCtorGoogleInjectResource() {} + + @GET + public String hello() { + return "world"; + } +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/Stashed.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/Stashed.java new file mode 100644 index 0000000..9472d3e --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/Stashed.java @@ -0,0 +1,15 @@ +package com.hubspot.dropwizard.guicier.objects; + +import com.google.inject.BindingAnnotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import javax.inject.Qualifier; + +@Qualifier +@BindingAnnotation +@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER }) +@Retention(RetentionPolicy.RUNTIME) +public @interface Stashed { +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/StashedValueFactoryProvider.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/StashedValueFactoryProvider.java new file mode 100644 index 0000000..6c9d5c8 --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/StashedValueFactoryProvider.java @@ -0,0 +1,35 @@ +package com.hubspot.dropwizard.guicier.objects; + +import com.google.inject.Injector; +import com.google.inject.Key; +import java.util.function.Function; +import javax.inject.Inject; +import javax.inject.Provider; +import org.glassfish.jersey.model.Parameter.Source; +import org.glassfish.jersey.server.ContainerRequest; +import org.glassfish.jersey.server.internal.inject.AbstractValueParamProvider; +import org.glassfish.jersey.server.internal.inject.MultivaluedParameterExtractorProvider; +import org.glassfish.jersey.server.model.Parameter; + +public class StashedValueFactoryProvider extends AbstractValueParamProvider { + + private final Injector injector; + + @Inject + public StashedValueFactoryProvider( + Provider extractorProviderProvider, + Injector injector + ) { + super(extractorProviderProvider, Source.UNKNOWN); + this.injector = injector; + } + + @Override + protected Function createValueProvider(Parameter parameter) { + if (!parameter.isAnnotationPresent(Stashed.class)) { + return null; + } + + return request -> injector.getInstance(Key.get(parameter.getType(), Stashed.class)); + } +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/StashedValueFeature.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/StashedValueFeature.java new file mode 100644 index 0000000..43a08d1 --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/StashedValueFeature.java @@ -0,0 +1,31 @@ +package com.hubspot.dropwizard.guicier.objects; + +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.ws.rs.core.Feature; +import javax.ws.rs.core.FeatureContext; +import javax.ws.rs.ext.Provider; +import org.glassfish.hk2.utilities.binding.AbstractBinder; +import org.glassfish.jersey.server.spi.internal.ValueParamProvider; + +@Provider +public class StashedValueFeature implements Feature { + + @Inject + StashedValueFeature() {} + + @Override + public boolean configure(FeatureContext context) { + context.register( + new AbstractBinder() { + @Override + protected void configure() { + bind(StashedValueFactoryProvider.class) + .to(ValueParamProvider.class) + .in(Singleton.class); + } + } + ); + return true; + } +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/StashesTestModule.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/StashesTestModule.java new file mode 100644 index 0000000..e776be9 --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/StashesTestModule.java @@ -0,0 +1,21 @@ +package com.hubspot.dropwizard.guicier.objects; + +import com.google.inject.Binder; +import com.google.inject.Module; +import com.google.inject.Provides; + +public class StashesTestModule implements Module { + + public static final int STASHED_INT_VALUE = 42; + + @Override + public void configure(Binder binder) { + binder.bind(StashesTestResource.class); + } + + @Stashed + @Provides + public int providesStashedInt() { + return STASHED_INT_VALUE; + } +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/StashesTestResource.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/StashesTestResource.java new file mode 100644 index 0000000..3548ea4 --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/StashesTestResource.java @@ -0,0 +1,82 @@ +package com.hubspot.dropwizard.guicier.objects; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + +import com.google.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; + +@Path("/stashes") +@Produces(APPLICATION_JSON) +public class StashesTestResource { + + private final int stashedIntCtor; + private final com.google.inject.Provider stashedIntGuiceProviderCtor; + private final javax.inject.Provider stashedIntJavaxProviderCtor; + + @Inject + @Stashed + private int stashedIntField; + + @Inject + @Stashed + private com.google.inject.Provider stashedIntGuiceProviderField; + + @Inject + @Stashed + private javax.inject.Provider stashedIntJavaxProviderField; + + @Inject + public StashesTestResource( + @Stashed int stashedIntCtor, + @Stashed com.google.inject.Provider stashedIntGuiceProviderCtor, + @Stashed javax.inject.Provider stashedIntJavaxProviderCtor + ) { + this.stashedIntCtor = stashedIntCtor; + this.stashedIntGuiceProviderCtor = stashedIntGuiceProviderCtor; + this.stashedIntJavaxProviderCtor = stashedIntJavaxProviderCtor; + } + + @GET + @Path("/itConstructorInjectsAStashedInt") + public int itConstructorInjectsAStashedInt() { + return stashedIntCtor; + } + + @GET + @Path("/itConstructorInjectsAStashedIntGuiceProvider") + public Integer itConstructorInjectsAStashedIntGuiceProvider() { + return stashedIntGuiceProviderCtor.get(); + } + + @GET + @Path("/itConstructorInjectsAStashedIntJavaxProvider") + public Integer itConstructorInjectsAStashedIntJavaxProvider() { + return stashedIntJavaxProviderCtor.get(); + } + + @GET + @Path("/itFieldInjectsAStashedInt") + public int itFieldInjectsAStashedInt() { + return stashedIntField; + } + + @GET + @Path("/itFieldInjectsAStashedIntGuiceProvider") + public Integer itFieldInjectsAStashedIntGuiceProvider() { + return stashedIntGuiceProviderField.get(); + } + + @GET + @Path("/itFieldInjectsAStashedIntJavaxProvider") + public Integer itFieldInjectsAStashedIntJavaxProvider() { + return stashedIntJavaxProviderField.get(); + } + + @GET + @Path("/itMethodInjectsAStashedInt") + public int itMethodInjectsAStashedInt(@Stashed int stashedInt) { + return stashedInt; + } +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java index df2ba4d..d82bf06 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java @@ -31,6 +31,11 @@ protected void configure() { bind(JerseyContextResource.class); bind(TestValueParamFeature.class); + + bind(StashedValueFeature.class); + install(new StashesTestModule()); + + bind(EmptyCtorGoogleInjectResource.class); } @Provides From 83c0250ae2e77c13fbd685f84d9edd4d0d441015 Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Sat, 29 Mar 2025 22:22:40 -0400 Subject: [PATCH 07/21] quieter logging --- .../guicier/injection/BridgedGuiceInjectionManagerFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java index 69c3a78..0129f5d 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java @@ -51,7 +51,7 @@ public InjectionManager create(Object parent) { ); injectionManager.register(Bindings.service(guiceInjector).to(Injector.class)); - LOG.info("Guice Component Provider initialized"); + LOG.debug("Guice Component Provider initialized"); return injectionManager; } } From 6880076813f1299978017e828d26df3067c2075f Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Sat, 29 Mar 2025 22:26:19 -0400 Subject: [PATCH 08/21] set injector into provider first --- .../java/com/hubspot/dropwizard/guicier/DropwizardModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java b/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java index 695bc8c..b3031f9 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java @@ -60,8 +60,8 @@ public void onProvision(ProvisionInvocation provision) { } public void register(Injector injector) { - registerResourcesAndProviders(environment.jersey().getResourceConfig(), injector); InjectorProvider.set(injector); + registerResourcesAndProviders(environment.jersey().getResourceConfig(), injector); } private void handle(Managed managed) { From 8fc9ca2049f3f4b3dd3b5609ecbc1ded6150d4f8 Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Sun, 30 Mar 2025 09:48:24 -0400 Subject: [PATCH 09/21] add managed dep for jersey-hk2 --- pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pom.xml b/pom.xml index 8322f52..c377e21 100644 --- a/pom.xml +++ b/pom.xml @@ -25,6 +25,16 @@ 11 + + + + org.glassfish.jersey.inject + jersey-hk2 + ${dep.jersey2.version} + + + + com.fasterxml.jackson.core From 667e15aafdf91d9219b6b8f26ca6b62c3cdba147 Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Mon, 31 Mar 2025 12:33:19 -0400 Subject: [PATCH 10/21] fix aop interception by using guice-managed instances when bindings exist --- .../guicier/injection/BindingUtils.java | 13 +- .../BridgedGuiceInjectionManager.java | 62 +++++++++ .../BridgedGuiceInjectionManagerFactory.java | 2 +- .../injection/DelegatingInjectionManager.java | 127 ++++++++++++++++++ .../dropwizard/guicier/aop/AopTest.java | 42 ++++++ .../guicier/aop/AopTestApplication.java | 45 +++++++ .../dropwizard/guicier/aop/MyAnnotation.java | 12 ++ .../dropwizard/guicier/aop/MyInterceptor.java | 16 +++ .../dropwizard/guicier/aop/MyResource.java | 25 ++++ 9 files changed, 338 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManager.java create mode 100644 src/main/java/com/hubspot/dropwizard/guicier/injection/DelegatingInjectionManager.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/aop/AopTest.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/aop/AopTestApplication.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/aop/MyAnnotation.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/aop/MyInterceptor.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/aop/MyResource.java diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java index 21b4c4d..c66f3c1 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java @@ -1,9 +1,5 @@ package com.hubspot.dropwizard.guicier.injection; -import com.google.inject.BindingAnnotation; -import com.google.inject.Key; -import com.google.inject.Provider; -import com.google.inject.internal.Nullability; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; @@ -14,12 +10,19 @@ import java.util.Collections; import java.util.Optional; import java.util.Set; + import javax.annotation.Nullable; import javax.inject.Qualifier; + import org.glassfish.hk2.utilities.reflection.ParameterizedTypeImpl; import org.glassfish.hk2.utilities.reflection.ReflectionHelper; import org.glassfish.jersey.internal.inject.Injectee; +import com.google.inject.BindingAnnotation; +import com.google.inject.Key; +import com.google.inject.Provider; +import com.google.inject.internal.Nullability; + public class BindingUtils { public static Optional translateGuiceProviderType(Injectee injectee) { @@ -155,7 +158,7 @@ public static Key toKey(Injectee injectee) { /** * Creates and returns a {@link Key} for the given {@link Type} and {@link Set} of {@link Annotation}s. */ - private static Key newKey(Type type, Set qualifiers) { + public static Key newKey(Type type, Set qualifiers) { if (qualifiers.isEmpty()) { return Key.get(type); } diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManager.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManager.java new file mode 100644 index 0000000..4399395 --- /dev/null +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManager.java @@ -0,0 +1,62 @@ +package com.hubspot.dropwizard.guicier.injection; + +import static com.hubspot.dropwizard.guicier.injection.BindingUtils.newKey; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.Set; + +import org.glassfish.jersey.internal.inject.InjectionManager; + +import com.google.inject.Injector; +import com.google.inject.Key; + +/** + * InjectionManager which gets instances from Guice bindings first, falling back to delegate + */ +public class BridgedGuiceInjectionManager extends DelegatingInjectionManager { + + private final Injector guiceInjector; + + public BridgedGuiceInjectionManager(InjectionManager delegate, Injector guiceInjector) { + super(delegate); + this.guiceInjector = guiceInjector; + } + + @Override + public T getInstance(Class contractOrImpl, Annotation... qualifiers) { + T guiceInstance = getGuiceInstance(newKey(contractOrImpl, Set.of(qualifiers))); + return guiceInstance != null + ? guiceInstance + : super.getInstance(contractOrImpl, qualifiers); + } + + @Override + public T getInstance(Class contractOrImpl, String classAnalyzer) { + T guiceInstance = getGuiceInstance(newKey(contractOrImpl, Set.of())); + return guiceInstance != null + ? guiceInstance + : super.getInstance(contractOrImpl, classAnalyzer); + } + + @Override + public T getInstance(Class contractOrImpl) { + T guiceInstance = getGuiceInstance(newKey(contractOrImpl, Set.of())); + return guiceInstance != null ? guiceInstance : super.getInstance(contractOrImpl); + } + + @Override + public T getInstance(Type contractOrImpl) { + T guiceInstance = getGuiceInstance(newKey(contractOrImpl, Set.of())); + return guiceInstance != null ? guiceInstance : super.getInstance(contractOrImpl); + } + + @SuppressWarnings("unchecked") + private T getGuiceInstance(Key key) { + if (guiceInjector.getExistingBinding(key) == null) { + return null; + } + + return (T) guiceInjector.getInstance(key); + } +} diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java index 0129f5d..babc7d8 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java @@ -52,6 +52,6 @@ public InjectionManager create(Object parent) { injectionManager.register(Bindings.service(guiceInjector).to(Injector.class)); LOG.debug("Guice Component Provider initialized"); - return injectionManager; + return new BridgedGuiceInjectionManager(injectionManager, guiceInjector); } } diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/DelegatingInjectionManager.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/DelegatingInjectionManager.java new file mode 100644 index 0000000..477567b --- /dev/null +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/DelegatingInjectionManager.java @@ -0,0 +1,127 @@ +package com.hubspot.dropwizard.guicier.injection; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.List; +import org.glassfish.jersey.internal.inject.Binder; +import org.glassfish.jersey.internal.inject.Binding; +import org.glassfish.jersey.internal.inject.ForeignDescriptor; +import org.glassfish.jersey.internal.inject.InjectionManager; +import org.glassfish.jersey.internal.inject.ServiceHolder; + +public class DelegatingInjectionManager implements InjectionManager { + + private final InjectionManager delegate; + + public DelegatingInjectionManager(InjectionManager delegate) { + this.delegate = delegate; + } + + @Override + public void completeRegistration() { + delegate.completeRegistration(); + } + + @Override + public void shutdown() { + delegate.shutdown(); + } + + @Override + public boolean isShutdown() { + return delegate.isShutdown(); + } + + @Override + public void register(Binding binding) { + delegate.register(binding); + } + + @Override + public void register(Iterable descriptors) { + delegate.register(descriptors); + } + + @Override + public void register(Binder binder) { + delegate.register(binder); + } + + @Override + public void register(Object provider) throws IllegalArgumentException { + delegate.register(provider); + } + + @Override + public boolean isRegistrable(Class clazz) { + return delegate.isRegistrable(clazz); + } + + @Override + public T create(Class createMe) { + return delegate.create(createMe); + } + + @Override + public T createAndInitialize(Class createMe) { + return delegate.createAndInitialize(createMe); + } + + @Override + public List> getAllServiceHolders( + Class contractOrImpl, + Annotation... qualifiers + ) { + return delegate.getAllServiceHolders(contractOrImpl, qualifiers); + } + + @Override + public T getInstance(Class contractOrImpl, Annotation... qualifiers) { + return delegate.getInstance(contractOrImpl, qualifiers); + } + + @Override + public T getInstance(Class contractOrImpl, String classAnalyzer) { + return delegate.getInstance(contractOrImpl, classAnalyzer); + } + + @Override + public T getInstance(Class contractOrImpl) { + return delegate.getInstance(contractOrImpl); + } + + @Override + public T getInstance(Type contractOrImpl) { + return delegate.getInstance(contractOrImpl); + } + + @Override + public Object getInstance(ForeignDescriptor foreignDescriptor) { + return delegate.getInstance(foreignDescriptor); + } + + @Override + public ForeignDescriptor createForeignDescriptor(Binding binding) { + return delegate.createForeignDescriptor(binding); + } + + @Override + public List getAllInstances(Type contractOrImpl) { + return delegate.getAllInstances(contractOrImpl); + } + + @Override + public void inject(Object injectMe) { + delegate.inject(injectMe); + } + + @Override + public void inject(Object injectMe, String classAnalyzer) { + delegate.inject(injectMe, classAnalyzer); + } + + @Override + public void preDestroy(Object preDestroyMe) { + delegate.preDestroy(preDestroyMe); + } +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/aop/AopTest.java b/src/test/java/com/hubspot/dropwizard/guicier/aop/AopTest.java new file mode 100644 index 0000000..3ef0be3 --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/aop/AopTest.java @@ -0,0 +1,42 @@ +package com.hubspot.dropwizard.guicier.aop; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.dropwizard.Configuration; +import io.dropwizard.testing.ResourceHelpers; +import io.dropwizard.testing.junit5.DropwizardAppExtension; +import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; +import javax.ws.rs.client.Client; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(DropwizardExtensionsSupport.class) +public class AopTest { + + private static final DropwizardAppExtension EXT = + new DropwizardAppExtension<>( + AopTestApplication.class, + ResourceHelpers.resourceFilePath("test-config.yml") + ); + + protected static Client client; + protected static AopTestApplication app; + + @BeforeAll + public static void setUp() { + client = EXT.client(); + } + + @Test + public void itInterceptsMethod() { + String response = client + .target("http://localhost:" + EXT.getLocalPort() + MyResource.PATH) + .request() + .get(String.class); + assertThat(response).isEqualTo(MyResource.RESPONSE); + + AopTestApplication app = EXT.getApplication(); + assertThat(app.getInterceptor().counter.get()).isEqualTo(1); + } +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/aop/AopTestApplication.java b/src/test/java/com/hubspot/dropwizard/guicier/aop/AopTestApplication.java new file mode 100644 index 0000000..0d8578e --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/aop/AopTestApplication.java @@ -0,0 +1,45 @@ +package com.hubspot.dropwizard.guicier.aop; + +import com.google.inject.AbstractModule; +import com.google.inject.matcher.Matchers; +import com.hubspot.dropwizard.guicier.GuiceBundle; +import io.dropwizard.Application; +import io.dropwizard.Configuration; +import io.dropwizard.setup.Bootstrap; +import io.dropwizard.setup.Environment; + +public class AopTestApplication extends Application { + + private MyInterceptor interceptor = new MyInterceptor(); + + public MyInterceptor getInterceptor() { + return interceptor; + } + + @Override + public void initialize(Bootstrap bootstrap) { + bootstrap.addBundle( + GuiceBundle + .defaultBuilder(Configuration.class) + .modules( + new AbstractModule() { + @Override + protected void configure() { + bind(MyResource.class); + + bindInterceptor( + Matchers.any(), + Matchers.annotatedWith(MyAnnotation.class), + interceptor + ); + } + } + ) + .build() + ); + } + + @Override + public void run(Configuration configuration, Environment environment) + throws Exception {} +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/aop/MyAnnotation.java b/src/test/java/com/hubspot/dropwizard/guicier/aop/MyAnnotation.java new file mode 100644 index 0000000..9dfcb8a --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/aop/MyAnnotation.java @@ -0,0 +1,12 @@ +package com.hubspot.dropwizard.guicier.aop; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Target(METHOD) +@Retention(RUNTIME) +public @interface MyAnnotation { +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/aop/MyInterceptor.java b/src/test/java/com/hubspot/dropwizard/guicier/aop/MyInterceptor.java new file mode 100644 index 0000000..d140420 --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/aop/MyInterceptor.java @@ -0,0 +1,16 @@ +package com.hubspot.dropwizard.guicier.aop; + +import java.util.concurrent.atomic.AtomicInteger; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +class MyInterceptor implements MethodInterceptor { + + public final AtomicInteger counter = new AtomicInteger(); + + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { + counter.incrementAndGet(); + return invocation.proceed(); + } +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/aop/MyResource.java b/src/test/java/com/hubspot/dropwizard/guicier/aop/MyResource.java new file mode 100644 index 0000000..ba5d590 --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/aop/MyResource.java @@ -0,0 +1,25 @@ +package com.hubspot.dropwizard.guicier.aop; + +import com.google.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Path(MyResource.PATH) +public class MyResource { + + public static final String PATH = "/aop-rsrc"; + + public static final String RESPONSE = "Hello, World!"; + + @Inject + public MyResource() {} + + @GET + @Produces(MediaType.TEXT_PLAIN) + @MyAnnotation + public String sayHello() { + return RESPONSE; + } +} From 2e8597b00a80486e98c1cc272014e7dc8280398b Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Mon, 31 Mar 2025 12:34:45 -0400 Subject: [PATCH 11/21] formatting --- .../dropwizard/guicier/injection/BindingUtils.java | 11 ++++------- .../injection/BridgedGuiceInjectionManager.java | 6 ++---- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java index c66f3c1..3447f38 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/BindingUtils.java @@ -1,5 +1,9 @@ package com.hubspot.dropwizard.guicier.injection; +import com.google.inject.BindingAnnotation; +import com.google.inject.Key; +import com.google.inject.Provider; +import com.google.inject.internal.Nullability; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; @@ -10,19 +14,12 @@ import java.util.Collections; import java.util.Optional; import java.util.Set; - import javax.annotation.Nullable; import javax.inject.Qualifier; - import org.glassfish.hk2.utilities.reflection.ParameterizedTypeImpl; import org.glassfish.hk2.utilities.reflection.ReflectionHelper; import org.glassfish.jersey.internal.inject.Injectee; -import com.google.inject.BindingAnnotation; -import com.google.inject.Key; -import com.google.inject.Provider; -import com.google.inject.internal.Nullability; - public class BindingUtils { public static Optional translateGuiceProviderType(Injectee injectee) { diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManager.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManager.java index 4399395..cca6426 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManager.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManager.java @@ -2,15 +2,13 @@ import static com.hubspot.dropwizard.guicier.injection.BindingUtils.newKey; +import com.google.inject.Injector; +import com.google.inject.Key; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.Set; - import org.glassfish.jersey.internal.inject.InjectionManager; -import com.google.inject.Injector; -import com.google.inject.Key; - /** * InjectionManager which gets instances from Guice bindings first, falling back to delegate */ From f23ae3daa31815204630effa5d10fec437c3a5b4 Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Mon, 31 Mar 2025 12:45:31 -0400 Subject: [PATCH 12/21] fix flapping test by returning hk2 injectionmanager if no guice injector set --- .../BridgedGuiceInjectionManagerFactory.java | 12 +++++++----- .../guicier/injection/InjectorProvider.java | 5 +++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java index babc7d8..0258c4d 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java @@ -1,6 +1,7 @@ package com.hubspot.dropwizard.guicier.injection; import com.google.inject.Injector; +import java.util.Optional; import javax.annotation.Priority; import javax.ws.rs.ConstrainedTo; import javax.ws.rs.RuntimeType; @@ -27,14 +28,15 @@ public InjectionManager create(Object parent) { ImmediateHk2InjectionManager injectionManager = (ImmediateHk2InjectionManager) new Hk2InjectionManagerFactory().create(parent); - Injector guiceInjector = new InjectorProvider().get(); + Optional guiceInjectorMaybe = InjectorProvider.getMaybe(); - if (guiceInjector == null) { - throw new IllegalStateException( - "Failed to lookup guice injector from servlet context" - ); + if (guiceInjectorMaybe.isEmpty()) { + LOG.warn("No guice injector is set"); + return injectionManager; } + Injector guiceInjector = guiceInjectorMaybe.get(); + // initialize HK2 guice-bridge GuiceBridge .getGuiceBridge() diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectorProvider.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectorProvider.java index 9d6fded..6b77274 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectorProvider.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectorProvider.java @@ -3,6 +3,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.inject.Injector; +import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import javax.inject.Provider; @@ -14,6 +15,10 @@ public static void set(Injector injector) { REF.set(injector); } + public static Optional getMaybe() { + return Optional.ofNullable(REF.get()); + } + @Override public Injector get() { return checkNotNull(REF.get(), "Guice Injector not set"); From 9321789a07872a63cf0216297b564d72d0b87e19 Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Mon, 31 Mar 2025 12:55:37 -0400 Subject: [PATCH 13/21] use correct parent --- .../BridgedGuiceInjectionManagerFactory.java | 16 ++++++++++++++-- .../injection/DelegatingInjectionManager.java | 4 ++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java index 0258c4d..78da9b6 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java @@ -1,10 +1,11 @@ package com.hubspot.dropwizard.guicier.injection; -import com.google.inject.Injector; import java.util.Optional; + import javax.annotation.Priority; import javax.ws.rs.ConstrainedTo; import javax.ws.rs.RuntimeType; + import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory; import org.glassfish.jersey.inject.hk2.ImmediateHk2InjectionManager; import org.glassfish.jersey.internal.inject.Bindings; @@ -15,6 +16,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.inject.Injector; + @Priority(15) @ConstrainedTo(RuntimeType.SERVER) public class BridgedGuiceInjectionManagerFactory implements InjectionManagerFactory { @@ -26,7 +29,8 @@ public class BridgedGuiceInjectionManagerFactory implements InjectionManagerFact @Override public InjectionManager create(Object parent) { ImmediateHk2InjectionManager injectionManager = - (ImmediateHk2InjectionManager) new Hk2InjectionManagerFactory().create(parent); + (ImmediateHk2InjectionManager) new Hk2InjectionManagerFactory() + .create(getHk2Parent(parent)); Optional guiceInjectorMaybe = InjectorProvider.getMaybe(); @@ -56,4 +60,12 @@ public InjectionManager create(Object parent) { LOG.debug("Guice Component Provider initialized"); return new BridgedGuiceInjectionManager(injectionManager, guiceInjector); } + + private static Object getHk2Parent(Object parent) { + if (parent instanceof DelegatingInjectionManager) { + DelegatingInjectionManager injectionManager = (DelegatingInjectionManager) parent; + return injectionManager.getDelegate(); + } + return parent; + } } diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/DelegatingInjectionManager.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/DelegatingInjectionManager.java index 477567b..28ef85f 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/DelegatingInjectionManager.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/DelegatingInjectionManager.java @@ -17,6 +17,10 @@ public DelegatingInjectionManager(InjectionManager delegate) { this.delegate = delegate; } + public InjectionManager getDelegate() { + return delegate; + } + @Override public void completeRegistration() { delegate.completeRegistration(); From e7efce27e84068e745a5582a1a2a680ff9ccb4b9 Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Mon, 31 Mar 2025 13:35:15 -0400 Subject: [PATCH 14/21] formatting --- .../injection/BridgedGuiceInjectionManagerFactory.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java index 78da9b6..317bbec 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManagerFactory.java @@ -1,11 +1,10 @@ package com.hubspot.dropwizard.guicier.injection; +import com.google.inject.Injector; import java.util.Optional; - import javax.annotation.Priority; import javax.ws.rs.ConstrainedTo; import javax.ws.rs.RuntimeType; - import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory; import org.glassfish.jersey.inject.hk2.ImmediateHk2InjectionManager; import org.glassfish.jersey.internal.inject.Bindings; @@ -16,8 +15,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.inject.Injector; - @Priority(15) @ConstrainedTo(RuntimeType.SERVER) public class BridgedGuiceInjectionManagerFactory implements InjectionManagerFactory { From 58ae92c63f7f1c3ce05e5007c6e4cfcacd79d3c9 Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Mon, 31 Mar 2025 14:36:40 -0400 Subject: [PATCH 15/21] hk-inject all guice instances to get @Context injection working --- .../BridgedGuiceInjectionManager.java | 6 ++- .../guicier/InjectedIntegrationTest.java | 19 +++++++++ .../objects/ComponentInvocationCounter.java | 23 +++++++++++ .../objects/ContextInjectedFilter.java | 39 +++++++++++++++++++ .../guicier/objects/TestModule.java | 3 ++ 5 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/objects/ComponentInvocationCounter.java create mode 100644 src/test/java/com/hubspot/dropwizard/guicier/objects/ContextInjectedFilter.java diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManager.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManager.java index cca6426..7f4ff3d 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManager.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/BridgedGuiceInjectionManager.java @@ -55,6 +55,10 @@ private T getGuiceInstance(Key key) { return null; } - return (T) guiceInjector.getInstance(key); + T instance = (T) guiceInjector.getInstance(key); + if (instance != null) { + super.inject(instance); + } + return instance; } } diff --git a/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java b/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java index 4eaee73..4e47864 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java @@ -2,6 +2,8 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.hubspot.dropwizard.guicier.objects.ComponentInvocationCounter; +import com.hubspot.dropwizard.guicier.objects.ContextInjectedFilter; import com.hubspot.dropwizard.guicier.objects.HK2ContextBindings; import com.hubspot.dropwizard.guicier.objects.TestApplication; import io.dropwizard.Configuration; @@ -9,6 +11,8 @@ import io.dropwizard.testing.junit5.DropwizardAppExtension; import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; import javax.ws.rs.client.Client; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status.Family; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -47,6 +51,21 @@ public void emptyCtorGoogleInject() { .isEqualTo("world"); } + @Test + public void testContextInjectedFilter() { + Response response = client.target(getUri("/explicit/message")).request().get(); + assertThat(response.getStatusInfo().getFamily()).isEqualTo(Family.SUCCESSFUL); + assertThat(response.getHeaderString(ContextInjectedFilter.RESPONSE_HEADER)) + .isEqualTo("true"); + + TestApplication app = EXT.getApplication(); + ComponentInvocationCounter counter = app + .getGuiceBundle() + .getInjector() + .getInstance(ComponentInvocationCounter.class); + assertThat(counter.count("ContextInjectedFilter")).isGreaterThanOrEqualTo(1); + } + @Test public void hk2ContextBindingsAreResolvableInGuice() { Assertions.assertAll( diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/ComponentInvocationCounter.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/ComponentInvocationCounter.java new file mode 100644 index 0000000..752de31 --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/ComponentInvocationCounter.java @@ -0,0 +1,23 @@ +package com.hubspot.dropwizard.guicier.objects; + +import com.google.common.collect.LinkedHashMultiset; +import com.google.common.collect.Multiset; +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton +public class ComponentInvocationCounter { + + private final Multiset invocations = LinkedHashMultiset.create(); + + @Inject + public ComponentInvocationCounter() {} + + public void inc(String name) { + invocations.add(name); + } + + public int count(String name) { + return invocations.count(name); + } +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/ContextInjectedFilter.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/ContextInjectedFilter.java new file mode 100644 index 0000000..cb1b1ee --- /dev/null +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/ContextInjectedFilter.java @@ -0,0 +1,39 @@ +package com.hubspot.dropwizard.guicier.objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.io.IOException; +import javax.inject.Inject; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.core.Context; +import javax.ws.rs.ext.Provider; +import org.glassfish.jersey.server.ExtendedUriInfo; + +@Provider +public class ContextInjectedFilter implements ContainerResponseFilter { + + public static final String RESPONSE_HEADER = "x-context-injected-filter"; + + private final ComponentInvocationCounter counter; + + @Context + private ExtendedUriInfo extendedUriInfo; + + @Inject + public ContextInjectedFilter(ComponentInvocationCounter counter) { + this.counter = counter; + } + + @Override + public void filter( + ContainerRequestContext requestContext, + ContainerResponseContext responseContext + ) throws IOException { + checkNotNull(extendedUriInfo, "@Context injected ExtendedUriInfo null"); + + counter.inc(getClass().getSimpleName()); + responseContext.getHeaders().putSingle(RESPONSE_HEADER, "true"); + } +} diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java index d82bf06..0f0f093 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestModule.java @@ -36,6 +36,9 @@ protected void configure() { install(new StashesTestModule()); bind(EmptyCtorGoogleInjectResource.class); + + bind(ComponentInvocationCounter.class); + bind(ContextInjectedFilter.class); } @Provides From c5cadff3b163cccd6346f5e57fc967408e4a7e40 Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Mon, 31 Mar 2025 16:27:49 -0400 Subject: [PATCH 16/21] add managed dep --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index c377e21..0ae4aae 100644 --- a/pom.xml +++ b/pom.xml @@ -27,6 +27,11 @@ + + jakarta.ws.rs + jakarta.ws.rs-api + 2.1.6 + org.glassfish.jersey.inject jersey-hk2 From 512e51ec7387d237d28db1a70b10249a00d7ca62 Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Tue, 1 Apr 2025 14:39:54 -0400 Subject: [PATCH 17/21] master basepom --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0ae4aae..3836a74 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.hubspot basepom - 1.0-js-manage-jerseydeps-SNAPSHOT + 61.8 com.hubspot.dropwizard From c6d2b6544b3285434a231f4a3e186c97f173de27 Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Tue, 10 Jun 2025 14:27:57 -0400 Subject: [PATCH 18/21] bump basepom --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3836a74..f1d5d9b 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.hubspot basepom - 61.8 + 63.2 com.hubspot.dropwizard From 4a269e5f5c4dfaeba920d661ca2b3b573267732c Mon Sep 17 00:00:00 2001 From: Jared Stehler Date: Tue, 2 Sep 2025 11:51:35 -0400 Subject: [PATCH 19/21] bump to support dropwizard 3.0 --- pom.xml | 57 ++++++++++++++++--- .../AllowUnknownFieldsObjectMapper.java | 2 +- .../guicier/DropwizardAwareModule.java | 6 +- .../dropwizard/guicier/DropwizardModule.java | 2 +- .../dropwizard/guicier/GuiceBundle.java | 8 +-- .../injection/InjectionManagerProvider.java | 2 +- .../dropwizard/guicier/GuiceBundleTest.java | 13 +++-- .../dropwizard/guicier/HK2LinkerTest.java | 2 +- .../guicier/InjectedIntegrationTest.java | 2 +- .../dropwizard/guicier/StashesTest.java | 2 +- .../dropwizard/guicier/aop/AopTest.java | 2 +- .../guicier/aop/AopTestApplication.java | 8 +-- .../guicier/objects/TestApplication.java | 8 +-- 13 files changed, 79 insertions(+), 35 deletions(-) diff --git a/pom.xml b/pom.xml index f1d5d9b..ce8f0c4 100644 --- a/pom.xml +++ b/pom.xml @@ -5,22 +5,24 @@ com.hubspot basepom - 63.2 + 63.6 com.hubspot.dropwizard dropwizard-guicier - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT 3.9.1 - 2.1.12 - 4.2.25 + 3.0.16 + 4.2.36 + 33.4.8-jre 2.6.1 - 2.16.2 + 2.19.2 ${dep.jackson.version} - 2.41 - 9.4.53.v20231009 + 2.47 + 10.0.26 + 2.0.17 11 @@ -37,6 +39,17 @@ jersey-hk2 ${dep.jersey2.version} + + org.eclipse.jetty + jetty-server + ${dep.jetty.version} + + + org.eclipse.jetty.toolchain + jetty-servlet-api + + + @@ -150,4 +163,34 @@ test + + + + + + org.basepom.maven + duplicate-finder-maven-plugin + + + + + + org.jspecify + jspecify + + + io.dropwizard.logback + logback-throttling-appender + + + + org.jspecify.annotations.Nullable + + + + + + + + diff --git a/src/main/java/com/hubspot/dropwizard/guicier/AllowUnknownFieldsObjectMapper.java b/src/main/java/com/hubspot/dropwizard/guicier/AllowUnknownFieldsObjectMapper.java index 32ad71f..d9d98bb 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/AllowUnknownFieldsObjectMapper.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/AllowUnknownFieldsObjectMapper.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import io.dropwizard.setup.Bootstrap; +import io.dropwizard.core.setup.Bootstrap; /** * Dropwizard makes it really hard to allow unknown fields in the {@link io.dropwizard.Configuration} diff --git a/src/main/java/com/hubspot/dropwizard/guicier/DropwizardAwareModule.java b/src/main/java/com/hubspot/dropwizard/guicier/DropwizardAwareModule.java index 336a1eb..a830193 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/DropwizardAwareModule.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/DropwizardAwareModule.java @@ -4,9 +4,9 @@ import static com.google.common.base.Preconditions.checkState; import com.google.inject.Module; -import io.dropwizard.Configuration; -import io.dropwizard.setup.Bootstrap; -import io.dropwizard.setup.Environment; +import io.dropwizard.core.Configuration; +import io.dropwizard.core.setup.Bootstrap; +import io.dropwizard.core.setup.Environment; public abstract class DropwizardAwareModule implements Module { diff --git a/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java b/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java index b3031f9..57065f8 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/DropwizardModule.java @@ -8,10 +8,10 @@ import com.google.inject.matcher.Matchers; import com.google.inject.spi.ProvisionListener; import com.hubspot.dropwizard.guicier.injection.InjectorProvider; +import io.dropwizard.core.setup.Environment; import io.dropwizard.lifecycle.Managed; import io.dropwizard.lifecycle.ServerLifecycleListener; import io.dropwizard.servlets.tasks.Task; -import io.dropwizard.setup.Environment; import java.lang.reflect.Type; import javax.ws.rs.Path; import javax.ws.rs.ext.Provider; diff --git a/src/main/java/com/hubspot/dropwizard/guicier/GuiceBundle.java b/src/main/java/com/hubspot/dropwizard/guicier/GuiceBundle.java index 8cc0acc..9b54637 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/GuiceBundle.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/GuiceBundle.java @@ -12,10 +12,10 @@ import com.google.inject.servlet.GuiceServletContextListener; import com.google.inject.servlet.ServletModule; import com.hubspot.dropwizard.guicier.injection.InjectionManagerProviderFeature; -import io.dropwizard.Configuration; -import io.dropwizard.ConfiguredBundle; -import io.dropwizard.setup.Bootstrap; -import io.dropwizard.setup.Environment; +import io.dropwizard.core.Configuration; +import io.dropwizard.core.ConfiguredBundle; +import io.dropwizard.core.setup.Bootstrap; +import io.dropwizard.core.setup.Environment; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProvider.java b/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProvider.java index 19f0cc2..5704a5e 100644 --- a/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProvider.java +++ b/src/main/java/com/hubspot/dropwizard/guicier/injection/InjectionManagerProvider.java @@ -2,7 +2,7 @@ import static com.google.common.base.Preconditions.checkNotNull; -import io.dropwizard.setup.Environment; +import io.dropwizard.core.setup.Environment; import java.util.HashMap; import java.util.Map; import javax.inject.Inject; diff --git a/src/test/java/com/hubspot/dropwizard/guicier/GuiceBundleTest.java b/src/test/java/com/hubspot/dropwizard/guicier/GuiceBundleTest.java index 2e3fc0d..92130bf 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/GuiceBundleTest.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/GuiceBundleTest.java @@ -17,8 +17,8 @@ import com.hubspot.dropwizard.guicier.objects.ProvidedTask; import com.hubspot.dropwizard.guicier.objects.ProviderManaged; import com.hubspot.dropwizard.guicier.objects.TestApplication; -import io.dropwizard.Configuration; -import io.dropwizard.setup.Environment; +import io.dropwizard.core.Configuration; +import io.dropwizard.core.setup.Environment; import io.dropwizard.testing.ResourceHelpers; import io.dropwizard.testing.junit5.DropwizardAppExtension; import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; @@ -33,10 +33,11 @@ @ExtendWith(DropwizardExtensionsSupport.class) public class GuiceBundleTest { - private static DropwizardAppExtension EXT = new DropwizardAppExtension<>( - TestApplication.class, - ResourceHelpers.resourceFilePath("test-config.yml") - ); + private static final DropwizardAppExtension EXT = + new DropwizardAppExtension<>( + TestApplication.class, + ResourceHelpers.resourceFilePath("test-config.yml") + ); private Environment environment; private GuiceBundle guiceBundle; diff --git a/src/test/java/com/hubspot/dropwizard/guicier/HK2LinkerTest.java b/src/test/java/com/hubspot/dropwizard/guicier/HK2LinkerTest.java index 8c260d5..f3f48df 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/HK2LinkerTest.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/HK2LinkerTest.java @@ -8,7 +8,7 @@ import com.hubspot.dropwizard.guicier.objects.ExplicitResource; import com.hubspot.dropwizard.guicier.objects.HK2ContextBindings; import com.hubspot.dropwizard.guicier.objects.TestApplication; -import io.dropwizard.Configuration; +import io.dropwizard.core.Configuration; import io.dropwizard.testing.ResourceHelpers; import io.dropwizard.testing.junit5.DropwizardAppExtension; import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; diff --git a/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java b/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java index 4e47864..47f803d 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/InjectedIntegrationTest.java @@ -6,7 +6,7 @@ import com.hubspot.dropwizard.guicier.objects.ContextInjectedFilter; import com.hubspot.dropwizard.guicier.objects.HK2ContextBindings; import com.hubspot.dropwizard.guicier.objects.TestApplication; -import io.dropwizard.Configuration; +import io.dropwizard.core.Configuration; import io.dropwizard.testing.ResourceHelpers; import io.dropwizard.testing.junit5.DropwizardAppExtension; import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; diff --git a/src/test/java/com/hubspot/dropwizard/guicier/StashesTest.java b/src/test/java/com/hubspot/dropwizard/guicier/StashesTest.java index 88c38f3..f6d09ec 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/StashesTest.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/StashesTest.java @@ -4,7 +4,7 @@ import com.hubspot.dropwizard.guicier.objects.StashesTestModule; import com.hubspot.dropwizard.guicier.objects.TestApplication; -import io.dropwizard.Configuration; +import io.dropwizard.core.Configuration; import io.dropwizard.testing.ResourceHelpers; import io.dropwizard.testing.junit5.DropwizardAppExtension; import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; diff --git a/src/test/java/com/hubspot/dropwizard/guicier/aop/AopTest.java b/src/test/java/com/hubspot/dropwizard/guicier/aop/AopTest.java index 3ef0be3..23f7378 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/aop/AopTest.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/aop/AopTest.java @@ -2,7 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; -import io.dropwizard.Configuration; +import io.dropwizard.core.Configuration; import io.dropwizard.testing.ResourceHelpers; import io.dropwizard.testing.junit5.DropwizardAppExtension; import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; diff --git a/src/test/java/com/hubspot/dropwizard/guicier/aop/AopTestApplication.java b/src/test/java/com/hubspot/dropwizard/guicier/aop/AopTestApplication.java index 0d8578e..acd5375 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/aop/AopTestApplication.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/aop/AopTestApplication.java @@ -3,10 +3,10 @@ import com.google.inject.AbstractModule; import com.google.inject.matcher.Matchers; import com.hubspot.dropwizard.guicier.GuiceBundle; -import io.dropwizard.Application; -import io.dropwizard.Configuration; -import io.dropwizard.setup.Bootstrap; -import io.dropwizard.setup.Environment; +import io.dropwizard.core.Application; +import io.dropwizard.core.Configuration; +import io.dropwizard.core.setup.Bootstrap; +import io.dropwizard.core.setup.Environment; public class AopTestApplication extends Application { diff --git a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestApplication.java b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestApplication.java index 85d1d31..c9d1722 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/objects/TestApplication.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/objects/TestApplication.java @@ -1,10 +1,10 @@ package com.hubspot.dropwizard.guicier.objects; import com.hubspot.dropwizard.guicier.GuiceBundle; -import io.dropwizard.Application; -import io.dropwizard.Configuration; -import io.dropwizard.setup.Bootstrap; -import io.dropwizard.setup.Environment; +import io.dropwizard.core.Application; +import io.dropwizard.core.Configuration; +import io.dropwizard.core.setup.Bootstrap; +import io.dropwizard.core.setup.Environment; public class TestApplication extends Application { From 9131e708eada85e6642982e2502a37b2a247046e Mon Sep 17 00:00:00 2001 From: jstehler Date: Mon, 3 Nov 2025 14:08:10 -0500 Subject: [PATCH 20/21] fix merge issues --- pom.xml | 1 - .../dropwizard/guicier/GuiceBundleTest.java | 16 ---------------- .../guicier/InjectedResourcesTest.java | 3 --- 3 files changed, 20 deletions(-) diff --git a/pom.xml b/pom.xml index 802f6f0..ac36773 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,6 @@ 3.0.0-SNAPSHOT - 3.9.1 3.0.16 4.2.36 33.4.8-jre diff --git a/src/test/java/com/hubspot/dropwizard/guicier/GuiceBundleTest.java b/src/test/java/com/hubspot/dropwizard/guicier/GuiceBundleTest.java index ac24fef..cb44c9f 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/GuiceBundleTest.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/GuiceBundleTest.java @@ -11,18 +11,11 @@ import com.hubspot.dropwizard.guicier.objects.InjectedServerLifecycleListener; import com.hubspot.dropwizard.guicier.objects.InjectedTask; import com.hubspot.dropwizard.guicier.objects.InstanceManaged; -import com.hubspot.dropwizard.guicier.objects.InstanceManaged; -import com.hubspot.dropwizard.guicier.objects.ProvidedHealthCheck; import com.hubspot.dropwizard.guicier.objects.ProvidedHealthCheck; import com.hubspot.dropwizard.guicier.objects.ProvidedManaged; -import com.hubspot.dropwizard.guicier.objects.ProvidedManaged; import com.hubspot.dropwizard.guicier.objects.ProvidedProvider; -import com.hubspot.dropwizard.guicier.objects.ProvidedProvider; -import com.hubspot.dropwizard.guicier.objects.ProvidedServerLifecycleListener; import com.hubspot.dropwizard.guicier.objects.ProvidedServerLifecycleListener; import com.hubspot.dropwizard.guicier.objects.ProvidedTask; -import com.hubspot.dropwizard.guicier.objects.ProvidedTask; -import com.hubspot.dropwizard.guicier.objects.ProviderManaged; import com.hubspot.dropwizard.guicier.objects.ProviderManaged; import com.hubspot.dropwizard.guicier.objects.TestApplication; import io.dropwizard.core.Configuration; @@ -31,21 +24,12 @@ import io.dropwizard.testing.junit5.DropwizardAppExtension; import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; import java.util.Set; -import java.util.Set; -import java.util.function.Function; -import javax.servlet.ServletException; import javax.servlet.ServletException; import org.assertj.core.api.InstanceOfAssertFactories; -import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.jersey.internal.inject.InjectionManager; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; @ExtendWith(DropwizardExtensionsSupport.class) public class GuiceBundleTest { diff --git a/src/test/java/com/hubspot/dropwizard/guicier/InjectedResourcesTest.java b/src/test/java/com/hubspot/dropwizard/guicier/InjectedResourcesTest.java index 2619aa5..e5ed093 100644 --- a/src/test/java/com/hubspot/dropwizard/guicier/InjectedResourcesTest.java +++ b/src/test/java/com/hubspot/dropwizard/guicier/InjectedResourcesTest.java @@ -4,11 +4,8 @@ import com.hubspot.dropwizard.guicier.objects.ExplicitDAO; import com.hubspot.dropwizard.guicier.objects.ExplicitResource; -import com.squarespace.jersey2.guice.JerseyGuiceUtils; import io.dropwizard.testing.junit5.DropwizardExtensionsSupport; import io.dropwizard.testing.junit5.ResourceExtension; -import org.junit.ClassRule; -import org.junit.Test; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; From 85917d6d9bff1a1fb5c6e12030e14b94b22469e8 Mon Sep 17 00:00:00 2001 From: jstehler Date: Mon, 3 Nov 2025 14:22:48 -0500 Subject: [PATCH 21/21] bump basepom, rm validator-api dep --- pom.xml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index ac36773..762514d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.hubspot basepom - 63.7 + 65.1 com.hubspot.dropwizard @@ -69,10 +69,6 @@ com.google.inject guice - - javax.validation - validation-api - com.google.inject.extensions guice-servlet