Skip to content

Instantly share code, notes, and snippets.

@psamsotha
Created May 25, 2016 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save psamsotha/838a194f883438faee2037e2baabe6c6 to your computer and use it in GitHub Desktop.
Save psamsotha/838a194f883438faee2037e2baabe6c6 to your computer and use it in GitHub Desktop.
Nested injection with Jersey/HK2 (Stackoverflow http://stackoverflow.com/q/37431802/2587435)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Type;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import org.glassfish.hk2.api.Injectee;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceHandle;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* Run like any other JUnit test. Only one required dependency
*
* <dependency>
* <groupId>org.glassfish.jersey.test-framework.providers</groupId>
* <artifactId>jersey-test-framework-provider-inmemory</artifactId>
* <version>2.22.1</version>
* </dependency>
*
* @author Paul Samsotha
*/
public class NestedInjectionTest extends JerseyTest {
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public static @interface CustomInject {}
public static class ChildObject {
String getName() {
return getClass().getSimpleName();
}
}
public static class ParentObject {
@CustomInject
private ChildObject object;
String getResult() {
assertNotNull(object);
return this.getClass().getSimpleName() + ":" + object.getName();
}
}
public static class CustomInjectResolver implements InjectionResolver<CustomInject> {
@Inject
@Named(InjectionResolver.SYSTEM_RESOLVER_NAME)
InjectionResolver<Inject> systemInjectionResolver;
@Override
public Object resolve(Injectee injectee, ServiceHandle<?> root) {
Type requiredType = injectee.getRequiredType();
return (ChildObject.class.equals(requiredType)
|| ParentObject.class.equals(requiredType))
? systemInjectionResolver.resolve(injectee, root)
: null;
}
@Override
public boolean isConstructorParameterIndicator() { return false; }
@Override
public boolean isMethodParameterIndicator() { return false; }
}
private static class Binder extends AbstractBinder {
@Override
protected void configure() {
bindAsContract(ParentObject.class);
bindAsContract(ChildObject.class);
bind(CustomInjectResolver.class)
.to(new TypeLiteral<InjectionResolver<CustomInject>>(){})
.in(Singleton.class);
}
}
@Path("test")
public static class TestResource {
@CustomInject
ParentObject object;
@GET
public String get() {
return object.getResult();
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(TestResource.class)
.register(new Binder())
.register(new LoggingFilter(Logger.getAnonymousLogger(), true));
}
@Test
public void should_inject_fine() {
final Response response = target("test").request().get();
assertEquals(200, response.getStatus());
assertEquals("ParentObject:ChildObject", response.readEntity(String.class));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment