I'm trying to test a resource with Resteasy using an embedded Netty instance as described in the Resteasy Docs.
Injecting path parameters and query parameters works like a charm but then I tried to test a resource that injects HttpServletRequest and HttpServletResponse from the context like this:
#GET
#Path("/")
public void example(#Context HttpServletResponse response,
#Context HttpServletRequest request) { ... }
Resteasy cannot find HttpServletRequestin the context and throws the following exception:
5105 [r #1] DEB o.j.resteasy.core.SynchronousDispatcher - PathInfo: /auth
5201 [r #1] ERR c.s.f.v.s.r.e.ApplicationExceptionMapper - Unhandled application exception: Unable to find contextual data of type: javax.servlet.http.HttpServletRequest
org.jboss.resteasy.spi.LoggableFailure: Unable to find contextual data of type: javax.servlet.http.HttpServletRequest
I tried putting mock versions of request and response in the context as suggested in RESTEasy Mock vs. Exception Mapper vs. Context but it does not work either as the contextual data is a ThreadLocal and Netty spawns a new thread for each request.
Any ideas on how to solve this?
What worked in my case was injecting a org.jboss.seam.mock.HttpServletRequest, since I am using seam in my application. You should try some mock framework like spring.test or mockito.
Here is how my code looks like:
import org.jboss.resteasy.core.Dispatcher;
import org.jboss.resteasy.mock.MockDispatcherFactory;
import org.jboss.resteasy.mock.MockHttpRequest;
import org.jboss.resteasy.mock.MockHttpResponse;
import org.jboss.resteasy.plugins.server.resourcefactory.POJOResourceFactory;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.seam.mock.MockHttpServletRequest;
import org.jboss.seam.mock.DBUnitSeamTest;
public class Test extends DBUnitSeamTest{
#Test
public void test() throws Exception {
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
POJOResourceFactory noDefaults = new POJOResourceFactory(ClasstoBeTested.class); dispatcher.getRegistry().addResourceFactory(noDefaults);
MockHttpRequest request = MockHttpRequest.get("/serviceToBeTested/1961");
MockHttpResponse response = new MockHttpResponse();
HttpServletRequest servletRequest = new MockHttpServletRequest(getSession());
ResteasyProviderFactory.getContextDataMap().put(HttpServletRequest.class, servletRequest);
dispatcher.invoke(request, response);
Assert.assertEquals(HttpServletResponse.SC_OK, response.getStatus());
Assert.assertTrue(response.getContentAsString().contains("1961"));
}
}
I just got hit by this again on another project and decided to investigate once more.
The issue is that in a mock request with Netty, there is no HttpServletRequest available. If you look into the sources of NettyJaxrsServerand related classes, Reasteasy uses its own abstraction for http requests that do not implement HttpServletRequest.
If I change my implementation to use these abstractions, I can access request and response in my resource.
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
#GET
#Path("/")
public void example(#Context HttpResponse response,
#Context HttpRequest request) { ... }
This is not perfect, because it makes my resources depend on Resteasy interfaces but I decided to go with it for now to support mock testing of multipart data.
Related
Heee there,
right now I am totally stuck. I spend hours asking google but I haven't found any solution or approach yet. Maybe you guys can help me.
Some background information:
I am developing a microservice into an existing microservice infrastructure. I want to use spring boot and connect the service to our existing authentication service. There are plenty of other jax rs microservices which are already connected to it. I started with an authentication and an authorization filter. The authentication filter works perfectly.
The problem:
I want to use my own "Secured" annotation like in the other services.
So there are some annotated resource methods in controllers like this example one:
#Secured({Role.ADMIN,...})
#RequestMapping(value = "/interfaces", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ExportInvoiceInterfaceResponseRepListWrapper> getAll() {
...
}
so when the following filter gets triggered I want to read the roles of the annotated controller method. In jax rs I just used the Class ResourceInfo to do so. As you may know I can't use this class in a default spring boot setup. Is there any way to get the class "the spring boot way"?
public class AuthorizationFilter extends GenericFilterBean {
#Context
private ResourceInfo resourceInfo;
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// Get the resource class which matches with the requested URL
// Extract the roles declared by it
Class<?> resourceClass = resourceInfo.getResourceClass();
List<Role> classRoles = extractRoles(resourceClass);
...
}
Any help would be awesome. Thank you in advanced.
Cheers
Frank
I have a Jersey 1.8 application running. Jersey is running as a Servlet.
I need to write a servlet filter that given a plain request/response, is able to figure out which REST resource/method will respond to the request and extract values from annotations.
For example, imagine I have the following resource:
#Path("/foo")
#MyAnnotation("hello")
public class FooResource {
#GET
#Path("/bar")
#MyOtherAnnotation("world")
public Response bar(){
...
}
}
When a request GET /foo/bar comes in, I need my servlet filter to be able to extract the values "hello" and "world" from MyAnnotation and MyOtherAnnotation before Jersey's own servlet processes the request.
This filter logic should be able to work for all requests and all resources registered.
Is there a way to access Jersey's internal routing mechanism to obtain a class/method reference where Jersey will dispatch the request?
I'm open to other suggestions as well, but ideally nothing like trying to hack my own routing mechanism by reading the #Path annotations myself.
#Provider
#Priority(Priorities.AUTHORIZATION)
public class MyFilter implements ContainerRequestFilter
#Context // request scoped proxy
private ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
if (resourceInfo.getResourceClass().isAnnotationPresent(MyAnnotationion.class) ||
resourceInfo.getResourceMethod().isAnnotationPresent(MyOtherAnnotation.class)) {
to register the filter use
bind(AuthFilter.class).to(ContainerRequestFilter.class).in(Singleton.class);
I have a RESTful server implementation as well as a library for clients to make the calls, all using JAX-RS. The server components are divided up into interface FooResource and implementation FooResourceService.
In order for the client and server libraries to share RESTful path and other definitions, I wanted to split out the FooResource interface into its own project:
#Path(value = "foo")
public interface FooResource {
#GET
public Bar getBar(#PathParam(value = "{id}") int id) {
I want to set some headers in the response. One easy way to do this is to use #Context HttpServletResponse in the method signature:
public Bar getBar(#PathParam(value = "{id}") int id, #Context HttpServletResponse servletResponse) {
But the problem is that this exposes implementation details in the interface. More specifically, it suddenly requires my REST definition project (which is shared between the client and server library) to pull in the javax.servlet-api dependency---something the client has no need up (or desire for).
How can my RESTful resource service implementation set HTTP response headers without pulling in that dependency in the resource interface?
I saw one post recommending I inject the HttpServletResponse as a class member. But how would this work if my resource service implementation is a singleton? Does it use some sort of proxy with thread locals or something that figures out the correct servlet response even though the singleton class is used simultaneously by multiple threads? Are there any other solutions?
The correct answer seems to be to inject an HttpServletResponse in the member variable of the implementation, as I noted that another post had indicated.
#Context //injected response proxy supporting multiple threads
private HttpServletResponse servletResponse;
Even though peeskillet indicated that the semi-official list for Jersey doesn't list HttpServletResponse as one of the proxy-able types, when I traced through the code at least RESTEasy seems to be creating a proxy (org.jboss.resteasy.core.ContextParameterInjector$GenericDelegatingProxy#xxxxxxxx). So as far as I can tell, thread-safe injection of a singleton member variable seems to be occurring.
See also https://stackoverflow.com/a/10076327/421049 .
So injecting HttpServletResponse seems like a no go. Only certain proxy-able types are inject-able into singletons. I believe the complete list is as follows:
HttpHeaders, Request, UriInfo, SecurityContext
This is somewhat pointed out in the JAX-RS spec, but is explained more clearly in the Jersey reference guide
The exception exists for specific request objects which can injected even into constructor or class fields. For these objects the runtime will inject proxies which are able to simultaneously server more request. These request objects are HttpHeaders, Request, UriInfo, SecurityContext. These proxies can be injected using the #Context annotation.
SecurityContext may be Jersey specific, as it's not stated in the spec, but I'm not sure.
Now those types mentioned above don't really do much for you because they are all request contexts and nothing to set the response.
One Idea though is to use a javax.ws.rs.container.ContainerResponseFilter, along with the HttpHeaders to set a temporary request header. You can access that header through the ContainerRequestContext passed to the filter method. Then just set the response header through the ContainerResponseContext, also passed to the filter method. If the the header is not specific to the context of that resource method, then it's even easier. Just set the header in the filter.
But let's say the header is dependent on the execution of the resource method. Then you could do something like
#Singleton
#Path("/singleton")
public class SingletonResource {
#Context
javax.ws.rs.core.HttpHeaders headers;
#GET
public String getHello() {
String result = resultFromSomeCondition(new Object());
headers.getRequestHeaders().putSingle("X-HELLO", result);
return "Hello World";
}
private String resultFromSomeCondition(Object condition) {
return "World";
}
}
Then the ContainerResponseFilter might look something like this
#Provider
public class SingletonContainerResponseFilter
implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext crc,
ContainerResponseContext crc1) throws IOException {
String header = crc.getHeaderString("X-HELLO");
crc1.getHeaders().putSingle("X-HELLO", "World");
}
}
And just so only the singleton classes run through this filter, we can simply use a #NameBinding annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.ws.rs.NameBinding;
#NameBinding
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface SingletonHeader {}
...
#SingletonHeader
public class SingletonResource {
...
#SingletonHeader
public class SingletonContainerResponseFilter
implements ContainerResponseFilter {
This is the only way I can think to handle this situation.
Resources:
Filters and Interceptors
Name Binding
#Path("/foo")
public interface FooResource {
#GET
#Path("{id}")
public Response getBar(#PathParam("id") int id) {
Bar bar = new Bar();
//Do some logic on bar
return Response.ok().entity(bar).header("header-name", "header-value").build()
}
}
Returns a JSON representation of the instance of bar with a status code 200 and header header-name with value header-value. It should look something along the lines of:
{
"bar-field": "bar-field-value",
"bar-field-2": "bar-field-2"
}
I know that this topic was discussed many times, but I found that the most of information on this is not up to date.
I am looking for tutorial/example on how to integrate GWT with Spring framework.
I have found many examplex (some of them even working), but only with older libraries. I am looking for a solution with newest libraries (or at least compatible with the newest).
Also many examples use spring4gwt library (for creating "glue" servlet) - is there another way?
I want to create simple example application using GWT + Spring + Hibernate + Maven. I started by creating Web Application Project (from Eclipse). I converted project to Maven project. And to be honest I am stuck here. I can create simple service (+ async), but have no idea how to configure proper servlet and go further. Examples I found relay on spring4gwt, but I would like not to use it (no new version since 2009 I think).
It would be great if someone could explain integration step-by-step.
Sorry if this one is a duplicate, but after long search I haven't found clear solution that suits my needs.
You have many ways to integrate with Spring, but i think the best option is use RestyGWT Framework
Since you are using HTTP protocol and JSON format for serializing objects, you won't have problem to comunicate with the Spring Controllers using RestyGWT.
You could also use your own controllers to respond to GWT RPC Requests. Instead of using GWT Dispatcher, you use the Spring MVC Request Dispacher and map the URLS on controllers to your services in GWT client.
if you use the RESTY GWT API, you could just write your interface, map the methods using JAX-RS annotations like #POST, #GET, #DELETE, #PathParam, etc.
Here's what I'm doing on my project using RestyGWT:
The project is compose of 2 projects:
project-client
project-server
The client contains all files related to GWT and RestyGWT.
The server contains all files from the back end implementation using Spring.
Maven overlay is used to merge the 2 projects on the package compile phase, so you end with a final war with the GWT *js files and the server files.
To use RestyGWT you have to create an interface who extends RestService:
public interface MyRestService extends RestService{
#GET
#Path("/foo")
public void getFoo(MethodCallback<List<Foo>);
#POST
#Path("/foo")
public void saveFoo(Foo foo ,MethodCallback<MessageResponse>);
}
To use the service you write something like this:
MyRestService service = GWT.create(MyRestService.class);
and you will have something like this to use the service:
service.getFoo(new MethodCallBack<List<Foo>>(){
public void onSucess(List<Foo> foos){
/* You will get foos, you dont have to worry about serialization, RESTYGWT does it for you */
}
public void onError() ...
});
And you will have a controller to respond to this request like this:
#Controller
class myController{
#Autowired FooService svc;
#RequestMapping(value = "/foo", method = RequestMethod.GET, produces= "application/json")
public #ResponseBody List<Foo> getAllFoos(){
return svc.all();
}
#RequestMapping(value = "/foo", method = RequestMethod.POST, produces= "application/json", consumes="application/json")
public #ResponseBody MessageResponse save(#ResponseBody Foo foo){
svc.save(foo);
return new MessageResponse("Foo saved with sucess", 200);
}
}
I've created many projects with this setup, you don't need spring4gwt!
My solution is to use a "bridge" class that allow you to call async services like spring controllers:
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.servlet.ModelAndView;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
public abstract class BaseRemoteService extends RemoteServiceServlet implements
ServletContextAware {
private static final long serialVersionUID = 2470804603581328584L;
protected Logger logger = Logger.getLogger(getClass());
private ServletContext servletContext;
#RequestMapping(method = { RequestMethod.GET, RequestMethod.POST })
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
doPost(request, response);
return null; // response handled by GWT RPC over XmlHttpRequest
}
#Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
#Override
public ServletContext getServletContext() {
return this.servletContext;
}
}
Now, your *RpcServiceImpl should be something like:
#Controller
#RequestMapping("/*/action.service")
public class ActionRpcServiceImpl extends BaseRemoteService implements ActionRpcService {
//this class is managed by spring, so you can use #Autowired and other stuffs
//implementation of your rpc service methods,
}
I wrote an HttpServletRequestWrapper named HTTPRequest that reads the full HTTP POST body for further use. This one is based in the code at http://natch3z.blogspot.com/2009/01/read-request-body-in-filter.html
My Jersey server application needs to get this wrapper to read the body. Unfortunately, I don't know how to do that.
I've tried putting
#Context HTTPRequest request;
but it does not work (Missing dependency for field).
I've tried too doing:
#Context HttpServletRequest request;
then casting to HTTPRequest, it didn't work neither ($ProxyXXX cannot be cast to HTTPRequest).
I've searched for information in the Internet but I cannot find anything regarding this. Any idea? :)
Thanks!
I don't quite understand: HTTPRequest is your objects extending the HttpServletRequestWrapper, right?
So if you want Jersey to inject it via the #Context annotation, you need to implement the ContextResolver. Actually in your case it should be easy:
#Provider
HTTPRequestContextResolver implements ContextResolver<HTTPRequest> {
#Context HttpServletRequest request;
HTTPRequest getContext(Class<?> type) {
return new HTTPRequest(request);
}
}
Updated: If you already wrapped the original request in a filter, you may have a problem to get it, since Jersey wraps the original request using the dynamic proxy.