Open leourbina opened 8 years ago
Below are the versions of the libraries I'm using:
jersey2-guice: 0.10
jersey: 2.17
guice: 4.0
I've look into this for a little while and I have some clues as to what is happening:
First, this only happens if the injectee has primitive type. The code below works as expected (assuming the setup from my previous comment):
package com.foo.service.resources;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/")
@Produces(MediaType.APPLICATION_JSON)
public class FooResource {
private final int bar;
@Inject
public FooResource(@Named("named.bar") Integer bar) {
this.bar = bar;
}
@GET
public int getBar() {
return bar;
}
}
Looking at the case when the injectee is a primitive, say an int
, and it requires a type conversion from a String
in a Guice binding, here's how things are supposed to work (AFAIK):
GuiceThreeThirtyResolver#resolve
is invoked, which calls (a few layers down) ServiceLocatorImpl#internalGetInjecteeDescriptor
. ServiceLocatorImpl#internalGetDescriptor
which returns null
as there are no bindings for a int
.null
, ServiceLocatorImpl#secondChanceResolve
is called which will attempt at JIT resolve the binding. This internally calls GuiceJustInTimeResolver#justInTimeResolution
GuiceBindingDescriptor
and adds it by calling ServiceLocatorUtilities#addOnDescriptor
. I can verify that this in fact takes effect in the debbuger by calling:locator.getServiceHandle(getDescriptors(BuilderHelper.createNameAndContractFilter("int", "named.bar")).get(0)).getService()
Which indeed does return the expected value (3).
java.lang.Integer
), and it looks it up in the mapping of all descriptors using this as the key, thus returning null
and missing the actual descriptor which is stored under the key int
. GuiceThreeThirtyResolver#resolve
method, and throws an exception given that the returned descriptor cannot be null
.Injectee
instance being passed is missing crucial information, although it is unclear whether this is a issue in jersey2-guice. In in particular the named qualifier is missing, as well as the unqualified
field (copied from my debugger):SystemInjecteeImpl(requiredType=int,parent=FooResource,qualifiers={},position=0,optional=false,self=false,unqualified=null,777637353)
This causes the internal cache of the ServiceLocator to be used, instead of looking up the descriptor in the internal mapping.
ServiceLocatorImpl#internalGetDescriptor
the rawClass
gets "boxed" into the java Class java.lang.Integer
which causes the lookups in the internal descriptor map to return null
as the correct descriptor is stored under "int"
not "java.lang.Integer"
. Any ideas how to fix this? The workaround for now is to not inject named primitives, and instead boxed types. /cc @rkapsi
According to the
Binder
documentation:However, this seems to not work in jersey2-guice. Below is code to reproduce this:
Given that the bound instance is a string, it should be possible to automatically have it converted to an int:
Unfortunately this results in the following exception being thrown: