I've created a server filter that extends jersey's ContainerRequestFilter, within this custom filter I'd like to inject an (EntityManager) object. To accomplish this I created a factory that implements jersey's hk2.api.Factory and configuration. This setup successfully injects the object into resources, however, it fails to inject the object into the filter.
Does anyone know how to configure jersey to inject objects into filters?
Original Error:
A MultiException has 3 exceptions. They are:
java.lang.IllegalStateException: Not inside a request scope.
java.lang.IllegalArgumentException: While attempting to resolve the dependencies of co.example.filters.Filter errors were found
java.lang.IllegalStateException: Unable to perform operation: resolve on co.example.filters.Filter
Error Messages:
WARNING: The following warnings have been detected: WARNING: Unknown
HK2 failure detected: MultiException stack 1 of 2
javax.persistence.PersistenceException: [PersistenceUnit: egunit]
Unable to build Hibernate SessionFactory at
org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.
at
org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.access$600(EntityManagerFactoryBuilderImpl.java:120)
at
org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:860)
at
org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850)
at
org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:425)
at
org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:849)
at
org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:75)
at
org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:54)
at
javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
at
javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:39)
at
co.example.factories.ExampleEntityManagerFactory.(ExampleEntityManagerFactory.java:21)
...
...
...
MultiException stack 2 of 2
java.lang.IllegalStateException: Unable to perform operation: create
on co.example.factories.ExampleEntityManagerFactory at
org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:395)
at
org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471)
at
org.jvnet.hk2.internal.PerLookupContext.findOrCreate(PerLookupContext.java:69)
at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2064)
at
org.jvnet.hk2.internal.ServiceHandleImpl.getService(ServiceHandleImpl.java:105)
at
org.jvnet.hk2.internal.ServiceHandleImpl.getService(ServiceHandleImpl.java:87)
at
org.jvnet.hk2.internal.FactoryCreator.create(FactoryCreator.java:117)
at
org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471)
at
org.glassfish.jersey.process.internal.Reque.findOrCreate(RequestScope.java:162)
at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2064)
at
org.jvnet.hk2.internal.ServiceLocatorImpl.internalGetService(ServiceLocatorImpl.java:711)
at
org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:661)
at
org.jvnet.hk2.internal.IterableProviderImpl.get(IterableProviderImpl.java:108)
at co.example.filters.Filter.filter(Filter.java:35)
Custom Filter:
#Provider
public class Filter implements ContainerRequestFilter {
#Inject private javax.inject.Provider<EntityManager> entityManagerProvider;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
EntityManager entityManager = entityManagerProvider.get();
EntityDao ed = new EntityDao(entityManager);
...
}
Factory:
public class ExampleEntityManagerFactory implements Factory<EntityManager> {
private final CloseableService closeableService;
private final EntityManagerFactory entityManagerFactory;
#Inject
public ExampleEntityManagerFactory(CloseableService closeableService) {
this.closeableService = closeableService;
this.entityManagerFactory = Persistence.createEntityManagerFactory("egunit");
}
#Override
public EntityManager provide() {
final EntityManager instance = entityManagerFactory.createEntityManager();
//closeableService.add(new Closeable() {
// #Override
// public void close() throws IOException {
// if (instance.isOpen()) instance.close();
// }
//});
return instance;
}
#Override
public void dispose(EntityManager instance) {
if (instance.isOpen()) instance.close();
}
}
Binding:
public class Configuration extends ResourceConfig {
public Configuration() {
...
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(ExampleEntityManagerFactory.class).to(EntityManager.class).in(RequestScoped.class);
}
});
}
}
Hard to tell for sure without seeing some code (and verifying), but I'm just going to make an educated guess and say that it's a scoping issue. The EntityManager should be inherently inside a request scope, so I'm guessing that's how you have it set up. So it works fine in your resource class, which I'm guessing is also request scoped (default behavior).
Your ContainerRequestFilter on the other hand, is in a singleton scope. So trying to inject a request scoped EntityManager into the singleton scoped filter is not possible, and you are probably getting the message "Not in a request scope" on startup.
One easy fix is to simply inject javax.inject.Provider<EntityManager>. One of the things it states about the Provider in the javadoc:
Compared to injecting T directly, injecting Provider<T>:
abstracting scope so you can look up an instance in a smaller scope from an instance in a containing scope.
So just do
#Provider
public static class Filter implements ContainerRequestFilter {
#Inject
private javax.inject.Provider<EntityManager> emProvider;
#Override
public void filter(ContainerRequestContext request) throws IOException {
EntityManager em = emProvider.get();
}
}
Given all else is functional, this should work (as tested). If this is not the problem/solution, please post some code and the complete stack trace.
For anyone interested, here is the complete test, using Jersey Test Framework.
Only Maven dependency required
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.17</version>
<scope>test</scope>
</dependency>
Test (If you want to see it fail, remove the javax.inject.Provider in the filter, and simple inject EntityManager)
import java.io.IOException;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import junit.framework.Assert;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
public class FilterScopeTest extends JerseyTest {
public static class EntityManager {
public String getEntity() {
return "Some Entity";
}
public void close() {
}
}
public static class EntityManagerFactory implements Factory<EntityManager> {
EntityManager em = new EntityManager();
public EntityManagerFactory() {
System.out.println("+++++ EntityManagerFactory Created +++++");
}
#Override
public EntityManager provide() {
return em;
}
#Override
public void dispose(EntityManager t) {
em.close();
}
}
public static class Binder extends AbstractBinder {
#Override
protected void configure() {
bindFactory(EntityManagerFactory.class).to(EntityManager.class).in(RequestScoped.class);
}
}
#Provider
public static class Filter implements ContainerRequestFilter {
#Inject
private javax.inject.Provider<EntityManager> em;
public Filter() {
System.out.println("+++++ Filter Created +++++");
}
#Override
public void filter(ContainerRequestContext request) throws IOException {
System.out.println("+++++ In filter EM is null: " + (em.get() == null) + " +++++");
System.out.println("+++++ EM entity value: " + (em.get().getEntity()) + " +++++");
}
}
#Path("em")
public static class EmResource {
#Inject
EntityManager em;
#GET
public String getStuff() {
return em.getEntity();
}
}
#Override
public Application configure() {
return new ResourceConfig(EmResource.class, Filter.class).register(new Binder());
}
#Test
public void doIt() {
Response response = target("em").request().get();
Assert.assertEquals(200, response.getStatus());
System.out.println(response.readEntity(String.class));
response.close();
}
#Test
public void doIt2() {
Response response = target("em").request().get();
Assert.assertEquals(200, response.getStatus());
System.out.println(response.readEntity(String.class));
response.close();
}
}
Related
I'm writing a RESTful web service where I'm trying to inject a request scoped service class into a filter.
I have gone through Paul Samsotha's blog on how to inject request scoped services using proxies.
Here's my implementation:
The supplier for this:
public class FileServiceSupplier implements Supplier<FileService> {
#Inject
ContainerRequestContext context;
public FileService get() {
String something = context.get("something");
new FileService(something);
}
}
and I'm binding the supplier here
import org.glassfish.jersey.internal.inject.AbstractBinder;
...
public class CustomDependencyBinder extends AbstractBinder {
#Override
protected void configure() {
bindFactory(FileServiceSupplier.class)
.proxy(true)
.proxyForSameScope(false)
.to(FileService.class)
.in(RequestScoped.class);
}
}
public class MyWebService extends ResourceConfig {
public MyWebService() {
register(new CustomDependencyBinder());
}
}
But now when I'm injecting this into a filter:
public class FileScanningFilter implements ContainerRequestFilter {
#Inject
private FileService fileService;
#Inject
private ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
boolean status = fileService.assertStatus();
}
}
#Provider
public class FileScanningFeature implements DynamicFeature {
#Override
public void configure(ResourceInfo resourceInfo, FeatureContext featureContext) {
featureContext.register(FileScanningFilter.class);
}
}
But now when I send a request I get the following error:
"There is more than one active context for org.glassfish.jersey.process.internal.RequestScoped" "java.lang.IllegalStateException: There is more than one active context for org.glassfish.jersey.process.internal.RequestScoped
at org.jvnet.hk2.internal.ServiceLocatorImpl._resolveContext(ServiceLocatorImpl.java:2193)
at org.jvnet.hk2.internal.ServiceLocatorImpl.access$000(ServiceLocatorImpl.java:105)
at org.jvnet.hk2.internal.ServiceLocatorImpl$3.compute(ServiceLocatorImpl.java:165)
at org.jvnet.hk2.internal.ServiceLocatorImpl$3.compute(ServiceLocatorImpl.java:161)
at org.glassfish.hk2.utilities.cache.Cache$OriginThreadAwareFuture$1.call(Cache.java:74)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at org.glassfish.hk2.utilities.cache.Cache$OriginThreadAwareFuture.run(Cache.java:131)
at org.glassfish.hk2.utilities.cache.Cache.compute(Cache.java:176)
at org.jvnet.hk2.internal.ServiceLocatorImpl.resolveContext(ServiceLocatorImpl.java:2207)
at org.jvnet.hk2.internal.MethodInterceptorImpl.internalInvoke(MethodInterceptorImpl.java:64)
at org.jvnet.hk2.internal.MethodInterceptorImpl.invoke(MethodInterceptorImpl.java:101)
at org.jvnet.hk2.internal.MethodInterceptorInvocationHandler.invoke(MethodInterceptorInvocationHandler.java:39)
at com.sun.proxy.$Proxy88.getResourceMethod(Unknown Source)
at com.test.FileScanningFilter.filter(AuthFilter.java:56)
Even though I inserted it once in the filter, it is saying there are multiple contexts.
I'm using Jersey 2.28
P.S: For the AbstractBinder , I followed this answer
I'm testing a Micronaut class that has a bean injected into it. In my test I provide a #MockBean class to override it. However, it seems Micronaut still injects the real dependency.
#MicronautTest
public class ClassUnderTestTest {
#Inject ClassUnderTest classUnderTest;
#Test
public void test() {
}
#MockBean
Dependency dependency() {
return mock(Dependency.class);
}
}
I uploaded a minimum repro to Github: https://github.com/crummy/micronaut-test-dependencies . The real dependency throws an exception, and the test does too. I would not have expected this to happen because of my #MockBean.
If I change the annotation to be #MockBean(Dependency.class) then I get this error: Message: No bean of type [di.failure.example.Dependency] exists. This seems even more confusing to me - now it doesn't resolve my real or my mock dependency?
Injecting mock bean with #MockBean annotation works if your dependency in ClassUnderTest is represented by interface. Let's say Dependency is a simple interface like:
package di.failure.example;
public interface Dependency {
void run();
}
Your application may provide an implementation for this interface called DependencyImpl:
package di.failure.example;
import javax.inject.Singleton;
#Singleton
public class DependencyImpl implements Dependency {
#Override
public void run() {
throw new RuntimeException("I don't want this to load!");
}
}
Now, for test purpose you can define a mock that replaces DependencyImpl:
package di.failure.example;
import io.micronaut.test.annotation.MicronautTest;
import io.micronaut.test.annotation.MockBean;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
import static org.mockito.Mockito.mock;
#MicronautTest
public class ClassUnderTestTest {
#Inject
ClassUnderTest classUnderTest;
#Test
public void test() {
classUnderTest.run();
}
#MockBean(DependencyImpl.class)
public Dependency dependency() {
return mock(Dependency.class);
}
}
This test executes and the mock returned by dependency() method is used in place of DependencyImpl.
Using #Replaces annotation
As Sergio mentioned in the comments section you can replace class based bean dependency using #Replaces annotation. Consider following example:
package di.failure.example;
import io.micronaut.context.annotation.Replaces;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
import javax.inject.Singleton;
#MicronautTest
public class ClassUnderTestTest {
#Inject
ClassUnderTest classUnderTest;
#Test
public void test() {
classUnderTest.run();
}
#Replaces(Dependency.class)
#Singleton
public static class MockDependency extends Dependency {
public MockDependency() {
System.out.println("MockDependency.<init>");
}
#Override
void run() {
System.out.println("Does not throw any exception...");
}
}
}
In this example we have defined a class MockDependency and we instruct Micronaut's DI mechanism to replace Dependency bean with MockDependency. However, there is one important thing we need to remember about - because our MockDependency extends Dependency class, parent construct gets invoked. The example you have shown in the question won't work in this case, because Dependency.<init> throws RuntimeException and the test fails. In this modified example I have used class like this one:
package di.failure.example;
import javax.inject.Singleton;
#Singleton
public class Dependency {
public Dependency() {
System.out.println("Dependency.<init>");
}
void run() {
throw new RuntimeException("I don't want this to load!");
}
}
When I run the test it passes and I see following console output:
Dependency.<init>
MockDependency.<init>
Does not throw any exception...
The main difference comparing to #MockBean is that in case of #Replaces you are using a concrete class object. As a workaround (if we really need a Mockito mock object) is to create a mock internally and delegate calls to this object, something like this:
#Replaces(Dependency.class)
#Singleton
public class MockDependency extends Dependency {
private final Dependency delegate;
public MockDependency() {
this.delegate = mock(Dependency.class);
}
#Override
void run() {
delegate.run();
}
}
I had the case - controller MyController with service MyService.
#MockBean(MyServiceImpl.class) did't mock injected service.
when(myService.doSomething()).thenReturn... immediately called real method.
I fixed mocking issue with giving MyService-bean a name and passing this name to #MockBean(name = )
controller:
#Controller
public class MyController {
private MyService myService;
...
}
factory:
#Factory
public class MyFactory {
#Named("myService") // Named just because #MockBean didn't work without it
#Context
public MyService myService() {
return new MyServiceImpl();
}
}
test:
#MicronautTest
class MyControllerTest {
#Inject
MyService myService;
#Inject
#Client("/")
#HttpClient client;
#MockBean(named = "myService")
MyService mockMyService() {
return mock(MyService.class);
}
#Test
void test() {
when(myService.doSomething()).thenReturn(genDto());
...
}
}
Details:
micronaut-test-junit5 3.1.1
junit-jupiter-api 5.6.2
I want to test a code that is "service" level or "dao" level.
but I couldn't resolve a exception
"No EntityManager bound to this thread. Try wrapping this call in
JPAApi.withTransaction, or ensure that the HTTP context is setup on
this thread."
This is a my code for testing by junit.
and the code what make a exception is userService.createUser(); in function "createUser"
#Inject
Application application;
#Before
public void setup() {
Module testModule = new AbstractModule() {
#Override
public void configure() {
}
};
GuiceApplicationBuilder builder = new GuiceApplicationLoader()
.builder(new ApplicationLoader.Context(Environment.simple()))
.overrides(testModule);
Guice.createInjector(builder.applicationModule()).injectMembers(this);
Helpers.start(application);
}
#After
public void teardown() {
Helpers.stop(application);
}
#Test
#Transactional
public void createUser() {
running(application, () -> {
UserService userService = application.injector().instanceOf(UserService.class);
userService.createUser();
});
}
Please, Help me to resolve the exception
thx ~
As a thought, you might add another injected field:
#Inject play.db.jpa.JPAApi japApi
Then in your test you can call jpaApi.withTransaction(anotherRunnableBlock);
probably too late for JungGyu Kim, but for other who google this issue.
I found solution for version 2.6.x, but should work also for 2.5.x.
package models;
import org.junit.Before;
import org.junit.Test;
import play.Application;
import play.db.jpa.JPAApi;
import play.test.Helpers;
import play.test.WithApplication;
import java.util.stream.Stream;
import static org.junit.Assert.assertTrue;
public class MyRepositoryTest extends WithApplication {
#Override
public Application provideApplication() {
return Helpers.fakeApplication(Helpers.inMemoryDatabase());
}
JPAApi jpaApi;
MyRepository myRepository;
#Before
public void init() {
// must get instances like this, as application is created for each test
jpaApi = app.injector().instanceOf(JPAApi.class);
userRepository = app.injector().instanceOf(UserRepository.class);
// no need to setup / clear DB, WithApplication create new DB for each test
}
#Test
public void testGetAllEntries() {
// insert some data first
performNativeQuery("INSERT INTO ...");
// call tested method
final Stream<Entity> result = myRepository.getAllEntries();
// perform some assertions
assertTrue(result.count() == 1);
}
private void performNativeQuery(final String query) {
jpaApi.withTransaction(em -> em.createNativeQuery(query).executeUpdate());
}
}
I am able to access HttpServletRequest by using #Context annotation in my rest service. But unable to access the same in repository class.I do not want to pass the request form MyService to MyRespository while calling methods.
#Path("/someUrl")
public MyService{
#Context
private HttpServletRequest request;
#Get
public void someMethod()
{
myRepository.someMethod();
}
}
But same annotation not working for my Repository class
#Repository
public MyRepository
{
#Context
private HttpServletRequest request;
public void someMethod()
{
//need request here
}
}
it injection null request. Not sure why this is not working.
The problem is the way Jersey (and its DI framework HK2) is integrated, is that Spring components can be injected into Jersey (HK2) components, but not vice versa. HttpServletRequest is bound as a Jersey component.
What you can do is create an HK2 service, that wraps the Spring repo, and the HttpServletRequest. IMO, it is better design anyway. A repository shouldn't be concerned with the HttpServletRequest, it is only concerned with data.
So you can have
public class MyService {
#Inject // or #Autowired (both work)
private MyRepository repository;
#Context
private HttpServletRequest request;
}
Then bind the service with HK2
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
public class AppBinder extends AbstractBinder {
#Override
public void configure() {
bindAsContract(MyService.class).in(RequestScoped.class);
// note, if `MyService` is an interface, and you have
// an implementation, you should use the syntax
//
// bind(MyServiceImpl.class).to(MyService.class).in(...);
//
// Then you inject `MyService`. Whatever the `to(..)` is,
// that is what you can inject
}
}
And register the binder with Jersey
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(new AppBinder());
}
}
Then you can inject MyService into your resource class.
If you don't want to go this route, then you need to make MyRepository an HK2 service, or use a an HK2 Factory to wrap the repository, and explicitly inject it. Something like
import javax.inject.Inject;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.ServiceLocator;
import org.springframework.context.ApplicationContext;
public class MyRepositoryFactory implements Factory<MyRepository> {
private final MyRepository repo;
#Inject
public MyRepositoryFactory(ApplicationContext ctx, ServiceLocator locator) {
MyRepository r = ctx.getBean(MyRepository.class);
locator.inject(r);
this.repo = r;
}
#Override
public MyRepository provide() {
return repo;
}
#Override
public void dispose(MyRepository t) {/* noop */}
}
Then register the factory
#Override
public void configure() {
bindFactory(MyRepositoryFactory.class).to(MyRepository.class).in(Singleton.class);
}
If you do the above, then you just use the MyRepository, instead of adding the service layer. Basically you need to get the repo from Spring, and explicitly inject it with the HK2 ServiceLocator (which is the HK2 analogue of the Spring ApplicationContext).
I am trying to write unit test for a Rest api call which is having a POST method for adding a video file to web based application using Jersey2. Here is the signature of the method of my class(TemplateController.java) for which I want to write unit test:
#POST
#Path("/video/add")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response addVideoData(
#Context HttpServletRequest request,
AttachmentDTO attachmentDTO) {
...
}
Here is my test method of the test class (TemplateControllerUnitTestCase.java):
#Test
public void videoAdd_requestObjectIsNull_ResponseStatusIsOK() throws Exception {
// arrange
Builder builder = target("/target/video/add").request();
// action
final Response response = builder.post(Entity.entity(attachemntDTO, MediaType.APPLICATION_JSON));
// assertion
...
}
I'm able to pass the AttachmentDAO object to the TemplateController class from test class but unable to pass the request object which is becoming null in the method(addVideoData()) of the TemplateController.java class.
I'm using RequestHelper class which is a helper class for HttpServletRequest, so I want to pass an object of this class to the method(addVideoData()) using Jersey2 test framework.
You can use the HK2 capabilities of Jersey 2, that helps with Dependency Injection. Doing it this way, you can create a Factory for HttpServletRequest and return the mock from your RequestHelper. For example
public class HttpServletRequestFactory implements Factory<HttpServlet> {
#Override
public HttpServletRequest provide() {
return RequestHelper.getMockServletRequest();
}
#Override
public void dispose(HttpSession t) {
}
}
Then in your JerseyTest subclass, just register an AbstractBinder with the ResourceConfig. For example
#Override
public Application configure() {
ResourceConfig config = new ResourceConfig(...);
config.register(new AbstractBinder(){
#Override
public void configure() {
bindFactory(HttpServletRequestFactory.class).to(HttpServletRequest.class);
}
});
}
Another option
...is to not mock the HttpServletRequest at all, and use the actual HttpServletRequest. To do that, we need to configure the DeploymentContext as we override the getDeploymentContext(), and return a ServletDeploymentContext. You can see an example here and here. The first has also has an example of using a Factory, while the second show an example of how to configure based on web.xml settings. If you chose the case for mocking the HttpServletRequest, then you wouldn't need to override the getTestContainerFactory and configureDeployment as seen in the examples. Simply using the Application configure() override is enough, as long as nothing else is dependent on servlet features.
The examples in the link use
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>${jersey.version}</version>
</dependency>
Extra
Both the example I linked to are trying to take advantage of the Sevlet features. So I'll give a complete example of using a request mock.
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Assert;
import org.junit.Test;
public class MockHttpSevletRequestTest extends JerseyTest {
#Path("http")
public static class HttpResource {
#GET
public Response getResponse(#Context HttpServletRequest request) {
return Response.ok(request.getMethod()).build();
}
}
#Override
public Application configure() {
ResourceConfig config = new ResourceConfig(HttpResource.class);
config.register(new AbstractBinder() {
#Override
public void configure() {
bindFactory(HttpServletRequestFactory.class)
.to(HttpServletRequest.class);
}
});
return config;
}
public static class HttpServletRequestFactory implements Factory<HttpServletRequest> {
#Override
public HttpServletRequest provide() {
return new MockHttpServletRequest();
}
#Override
public void dispose(HttpServletRequest t) {
}
}
#Test
public void test() {
String response = target("http").request().get(String.class);
System.out.println(response);
Assert.assertEquals("POST", response);
}
}
MockHttpServletRequest is simple a dummy implementation of HttpServletRequest where I only override one method getMethod() and always return POST. You can see from the result, that even though it's a get request, it still returns POST
public class MockHttpServletRequest implements HttpServletRequest {
#Override
public String getMethod() {
return "POST";
}
...
}