Skip to content

Instantly share code, notes, and snippets.

@psamsotha
Created December 16, 2015 10:59
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/4db6a710b615d6c40504 to your computer and use it in GitHub Desktop.
Save psamsotha/4db6a710b615d6c40504 to your computer and use it in GitHub Desktop.
Jerse bug: Request scoped object should fail on injection into @singleton unless it is proxiable.
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
/**
* Jersey bug.
*
* Request scoped object should fail on injection into {@code @Singleton}, but
* since the {@code @Singleton} is not created until the first request, the
* first request scope object gets injected on the first request and remains the
* same throughout the lifetime of the singleton.
*
* The only way to make it fail as expected is to register an instance of the
* singleton. This way during start up injection process, it will see the
* request scoped object can't be injected and signal a failure.
*
* The solution is to make the request scoped object proxiable, but this is
* probably not obvious to most.
*/
public class ScopeInjectTest extends JerseyTest {
public static interface HeadersService {
String getHeader(String header);
}
public static class HeadersServiceImpl implements HeadersService {
private final MultivaluedMap<String, String> headers;
public HeadersServiceImpl(MultivaluedMap<String, String> headers) {
this.headers = headers;
}
@Override
public String getHeader(String header) {
return headers.getFirst(header);
}
}
public static class HeadersServiceFactory
extends AbstractContainerRequestValueFactory<HeadersService> {
@Override
public HeadersService provide() {
ContainerRequest request = getContainerRequest();
return new HeadersServiceImpl(request.getHeaders());
}
}
@Singleton
@Path("headers")
public static class HeadersResource {
@Inject
HeadersService service;
@GET
public String get(@QueryParam("header") String header) {
return service.getHeader(header);
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(HeadersResource.class)
.register(new AbstractBinder() {
@Override
protected void configure() {
bindFactory(HeadersServiceFactory.class)
//.proxy(true)
//.proxyForSameScope(false)
.to(HeadersService.class)
.in(RequestScoped.class);
}
});
}
private static final String HEADER = "X-Header";
private static final String HEADER_1_VALUE = "value1";
private static final String HEADER_2_VALUE = "value2";
@Test
public void headers_should_be_different() {
Response response = target("headers").queryParam("header", HEADER)
.request().header(HEADER, HEADER_1_VALUE).get();
String message = response.readEntity(String.class);
assertEquals(HEADER_1_VALUE, message);
response.close();
response = target("headers").queryParam("header", HEADER)
.request().header(HEADER, HEADER_2_VALUE).get();
message = response.readEntity(String.class);
assertEquals(HEADER_2_VALUE, message);
response.close();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment