Search code examples
scaladependency-injectionjerseydropwizardhk2

Dropwizard/Jersey/HK2 Dependency Injection in Scala


Trying to create a custom @Context I can inject into my resources via Jersey.

This is covered in Java in this question. I've read the docs covering this which are also in Java. And lastly some code covering the same topic (doing this all through Dropwizard) in Github.

The first part is creating the Factory.

Scala:

import org.glassfish.hk2.api.Factory
import javax.inject.Inject
import javax.ws.rs.container.ContainerRequestContext
import MyObj

class MyObjFactory @Inject()(ctr: ContainerRequestContext) extends Factory[MyObj] {
  private final val context: ContainerRequestContext = ctr

  override def provide(): MyObj = context.getProperty("myObj").asInstanceOf[MyObj]

  override def dispose(myObj: MyObj): Unit = { }
}

The next part is registering the factory, where I make an assumption that classOf[T] is the appropriate Scala equivalent to Java's T.class

import org.glassfish.hk2.utilities.binding.AbstractBinder

environment.jersey.register(new AbstractBinder {
  override def configure(): Unit = {
    bindFactory(classOf[MyObjFactory])
        .to(classOf[MyObj])
        .proxy(true)
        .proxyForSameScope(false)
        .in(classOf[RequestScoped])
  }
})

Last should be the actual injection:

@Path("/")
class MyResource {
    @GET
    def get(@Context uriInfo: UriInfo, @Context myObjFactory: MyObjFactory) = {
        // do stuff
    }
}

This all compiles but fails at runtime with the following exception

ERROR [2017-04-05 00:26:14,605] io.dropwizard.jersey.errors.LoggingExceptionMapper: Error handling a request: 8e5877857c823fef
! java.lang.IllegalArgumentException: Invalid injectee with required type of null passed to getInjecteeDescriptor
! ... 87 common frames omitted
! Causing: org.glassfish.hk2.api.MultiException: A MultiException has 1 exceptions.  They are:
! 1. java.lang.IllegalArgumentException: Invalid injectee with required type of null passed to getInjecteeDescriptor
! 
! at org.jvnet.hk2.internal.ServiceLocatorImpl.internalGetInjecteeDescriptor(ServiceLocatorImpl.java:545)
! at org.jvnet.hk2.internal.ServiceLocatorImpl.getInjecteeDescriptor(ServiceLocatorImpl.java:584)
! at org.glassfish.jersey.internal.inject.ContextInjectionResolver$1.compute(ContextInjectionResolver.java:102)
! at org.glassfish.jersey.internal.inject.ContextInjectionResolver$1.compute(ContextInjectionResolver.java:98)
! at org.glassfish.hk2.utilities.cache.Cache$OriginThreadAwareFuture$1.call(Cache.java:97)

Can't tell if I am making a mistake with my conversion to Scala or I've done something wrong actually registering the Binder.


Solution

  • get(@Context uriInfo: UriInfo, @Context myObjFactory: MyObjFactory) <===
    

    You're trying to inject the Factory. The Factory is used to create the service. It is not meant to be injected in this case. What you want to inject is the actual service, and the factory will be used to create it behind the scene

    get(@Context uriInfo: UriInfo, @Context myOb: MyObj) <===