Injecting HttpRequest in RESTEasy Reactive / Quarkus fails - java

I'm currently trying to inject and read out the HttpRequest in Quarkus 1.13 but without any success. I'm using RESTEasy-Reactive for my endpoint.
This is how I'm currently including it
#Path("/users/{id}")
class UserController(
#Inject val service: UserService,
#Context val httpRequest: io.vertx.core.http.HttpServerRequest,
)
...
The build process succeeds but when I try to access a property like httpRequest.absoluteURI() I am getting an NPE
java.lang.NullPointerException: Cannot invoke "org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext.serverRequest()" because the return value of "org.jboss.resteasy.reactive.server.core.CurrentRequestManager.get()" is null
at io.quarkus.resteasy.reactive.server.runtime.QuarkusContextProducers.httpServerRequest(QuarkusContextProducers.java:26)
at io.quarkus.resteasy.reactive.server.runtime.QuarkusContextProducers_Subclass.httpServerRequest$$superaccessor3(QuarkusContextProducers_Subclass.zig:451)
at io.quarkus.resteasy.reactive.server.runtime.QuarkusContextProducers_Subclass$$function$$3.apply(QuarkusContextProducers_Subclass$$function$$3.zig:29)
...
I also tried other classes like io.vertx.mutiny.core.http.HttpServerRequest or java.net.http.HttpRequest but still without success. Injecting it with #Inject didn't even build. I'm missing the HttpServletRequest class :/
Anybody got an idea?

You have a few options:
Using HttpFilter: https://javaee.github.io/javaee-spec/javadocs/javax/servlet/http/HttpFilter.html
#WebFilter(urlPatterns = "/*")
public class FilterEverything extends HttpFilter {
#Override
protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
//Do something with HttpServletRequest
}
}
Using ContainerRequestFilter: https://docs.oracle.com/javaee/7/api/javax/ws/rs/container/ContainerRequestFilter.html
As Quarkus Documentation Showcases:
#Provider
public class LoggingFilter implements ContainerRequestFilter {
private static final Logger LOG = Logger.getLogger(LoggingFilter.class);
#Context
UriInfo info;
#Context
HttpServerRequest request;
#Override
public void filter(ContainerRequestContext context) {
//Do whatever you want
}
}
As part of the method signature:
#GET
#Path("/someEndPoint")
#Produces("application/json")
public JsonObject getData(#PathParam("owner") String owner, #Context HttpServletRequest request) {
//Do something here
}

Related

Filter Chain with Mockito Unit Test with Servlet Request

I am using Mockito for Testing Filter,I am trying to test do filter chain method which requires HTTPServlet request as parameter, I tried mocking both Servlet Request and HTTPServlet Request but I am receiving
errors,
when using HTTPServlet request as null pointer exception, & with
Servlet Request as it cannot be cast. Any leads is appreciated.
My Filter looks like,
public class CheckerFilter implements Filter {
private final UserDetails userDetails;
priate final UserAuthentication userAuthentication
public CheckerFilter(UserDetails userDetails,UserAuthentication userAuthentication ){
this.userDetails = userDetails;
this.userAuthentication = userAuthentication;
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException{
final HttpServletRequest request = (HttpServletRequest)req;
final String method = request.getMethod();
final String contentType = request.getContentType();
boolean result = evaluate();
....
if(result)filter.doChain(request, res, chain);
else res.sendRedirect('\XXX');
}
}
Test looks like,
public class CheckerFilterTest {
#InjectMocks private CheckerFilter checkerFilter;
final UserDetails userDetails =mock(UserDetails.class);
final UserAuthentication userAuthentication = mock (UserAuthentication.class);
#Mock ServletRequest mockServeletRequest;
#Mock ServletResponse mockResponse;
#Mock HTTPServeltRequest mockHttprequest;
public void setUp (){
checkerFilter = new CheckerFilter(userDetails, userAuthentication);
}
#Test
public void Evaluate_returnsTrue(){
when(evaluate()).thenReturn(true);
checkerFilter.doFilter(mockHTTPrequest, mockResponse, mockchain);
//Error denoting mockHTTPRequest as null pointer exception.
//checkerFilter.doFilter(mockServletrequest, mockResponse, mockchain);Error mentioning Servlet Request cannot be cast to HTTPServlet Request.
}
}
The mocks need to be initialised. You can use MockitoAnnotations.initMocks(this) in the setup() method to initialise the #Mock annotated mocks. Also you have to use the http servlet request mock and not a servlet request mock as it cannot be downcasted

How can i custom filter for 302 Status Code in spring mvc java and response.redirect to custom page?

Hi all I want to create RedirectionFilter at java spring. The main purpose is when status code 302 is detected then send redirect and replacing the response content by custom text content. The first problem is don't know how to catch the response code 302. This is my current thinking .
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) (request);
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
String redirectURL="www.google.com";
if(statuscode == 302 ){
httpServletResponse.sendRedirect(redirectURL);
}
Something like that. I have out of ideas. Thanks for helping.
You can use HandlerInterceptorAdapter to get the response after each call and can validate the response code and do necessary things
#Component
public class TestInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, java.lang.Object object) throws Exception {
System.out.println("test");
return true;
}
#Override
public void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, java.lang.Object handler, #org.springframework.lang.Nullable java.lang.Exception ex) throws java.lang.Exception {
if(response.getStatus()==302){
// your code
}
}
}
After creating a interceptor need to register it in InterceptorRegistry
#Component
public class InterceptorsConfig implements WebMvcConfigurer {
#Autowired
private TestInterceptor testInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(testInterceptor);
}
}
Once triggering a request, the control will come to interceptor first.
Restcontroller sample
#RestController
#RequestMapping("/test")
public class Restcontroller {
#GetMapping
public ModelAndView redirectWithUsingRedirectPrefix(ModelMap model) {
model.addAttribute("attribute", "redirectWithRedirectPrefix");
return new ModelAndView("redirect:/redirectedUrl", model);
}
}

Spring 3 HandlerInterceptor passing information to Controller

I've setup a Spring HandlerInterceptor to add an attribute to the HttpServletRequest to be able to read it from the Controller, sadly this does not seem to work which seems strange to me. Am I doing things wrong? Any idea how to transmit the data from the Interceptor to the Controller?
Here is the simplified code of the two impacted classes
public class RequestInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
request.setAttribute("my-role", "superman");
}
[...]
}
#RestController
#RequestMapping("Test")
public class TestController {
public final Logger logger = LoggerFactory.getLogger(getClass());
#RequestMapping(value = "something")
public void something(HttpServletRequest request) {
logger.info(request.getAttribute("my-role"));
}
[...]
}
The request.getAttribute("my-role") returns null... but does return the excepted value if I read it in the postHandle of the HandlerInterceptor, I feel like I'm missing something...
EDIT : I found out that going thru the session with "request.getSession().setAttribute" works as a charm, still i do not understand why the request itself does not work in this use case.
Can you try with session instead of request like below.
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
...
HttpSession session = request.getSession();
session.setAttribute("attributeName", objectYouWantToPassToHandler);
....
}
In your handler handleRequest method:
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
....
HttpSession session = request.getSession();
objectYouWantToPassToHandler objectYouWantToPassToHandler = session.getAttribute("attributeName");
....
}

Get HttpServletRequest and HttpServletResponse from Camel Message Body

I'm trying to send a request to an HTTP endpoint using Camel Jetty or Camel HTTP component. I was wondering if it's possible to convert the request and response to HttpServletRequest and HttpServletResponse objects.
I have the following route:
from("direct://processing/callEndpoint")
.to("jetty:http://www.google.com")
.to("bean:processHttpResponse")
I'm using Guice for dependency injection and "bean:processHttpResponse" is the following:
public class HttpResponseBean {
public void processResponse(Exchange exchange) {
HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class);
HttpServletResponse response = exchange.getOut().getBody(HttpServletResponse.class);
}
}
Both request and response objects are null. When debugging/inspecting the Exchange, the In Message is a byte array (byte[]) and the Out Message is null. Not sure how to proceed..
Refer to the Camel Jetty goto the Consumer Example.
Try to call your bean like this.
from("jetty:http://localhost:{{port}}/myapp/myservice").bean(HttpResponseBean,"processResponse");
public class HttpResponseBean {
public void processResponse(Exchange exchange) {
// we have access to the HttpServletRequest here and we can grab it if we need it
HttpServletRequest req = exchange.getIn().getBody(HttpServletRequest.class);
}
}
You should implement a processor like this one:
public class MyBean implements Processor {
public void process(Exchange exchange) throws Exception {
HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class);
HttpServletResponse response = exchange.getOut().getBody(HttpServletResponse.class);
}
}
If you have a #Configuration Spring context like this
#Configuration
class ApplicationConfiguration {
#Bean
public MyBean myBean() {
return new MyBean();
}
}
you should be able to refer to it in the process statement like this .process("bean:myBean").
If you are building your route using a RouteBuilder, please use a SpringCamelContext in order to let Camel access the beans.

Retrieve Request Body in Exception Mapper

I'm trying to retrieve the body of a request in a JAX-RS ExceptionMapper. Here is my code so far:
#Provider #Componenet
public class BaseExceptionMapper implements ExceptionMapper<Exception> {
#Context private HttpServletRequest request;
#Override
public Response toResponse(Exception ex) {
// Trying to retrieve request body for logging throws an error
String requestBody = IOUtils.toString(request.getInputStream());
}
}
So my dilemma is I can't get the request body for logging because the servlet API wont allow you to call request.getInputStream() / request.getReader() more than once for a request (and JAX-RS Is obviously calling it to parse the request). Does anyone know if there is a way to do what I'm trying to do?
This question is a bit older, but still the answer may help others. My Example also depends on Commons-Io.
You can create a ContainerRequestFilter and use TeeInputStream to proxy/copy the original InputStream:
#Provider
#Priority(Priorities.ENTITY_CODER)
public class CustomRequestWrapperFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext)
throws IOException {
ByteArrayOutputStream proxyOutputStream = new ByteArrayOutputStream();
requestContext.setEntityStream(new TeeInputStream(requestContext.getEntityStream(), proxyOutputStream));
requestContext.setProperty("ENTITY_STREAM_COPY", proxyOutputStream);
}
}
And use #Inject with javax.inject.Provider in your ExceptionMapper to get the ContainerRequest injected.
The ExceptionMapper would look like this:
#Provider
public class BaseExceptionMapper implements ExceptionMapper<Exception> {
#Inject
private javax.inject.Provider<ContainerRequest> containerRequestProvider;
#Override
public Response toResponse(Exception exception) {
ByteArrayOutputStream bos = (ByteArrayOutputStream) containerRequestProvider
.get().getProperty("ENTITY_STREAM_COPY");
String requestBody = bos.toString();
...
}
}
When I have also used the #Component annotation my ExceptionMapper was not used. I think that #Provider is sufficient.
One possible solution is to use a servlet filter and wrap the request, which allows you to intercept read calls to the request input stream. Example pseudo-code (depends on commons-io):
import org.apache.commons.io.output.StringBuilderWriter;
import org.apache.commons.io.input.TeeInputStream;
class MyHttpRequest extends HttpServletRequestWrapper {
private StringBuilderWriter myString = new StringBuilderWriter();
private InputStream myIn;
public MyHttpRequest(HttpServletRequest request) {
super(request);
myIn = new TeeInputStream(request.getInputStream(), myString);
}
#Override public ServletInputStream getInputStream()
throws java.io.IOException {
// this will need an extra wrapper to compile
return myIn;
}
public String getRequestBody() {
return myString.toString();
}
}
Filter:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
MyHttpRequest wrapper = new MyHttpRequest((HttpServletRequest) request);
chain.doFilter(wrapper, response, chain);
}
Mapper:
#Context private HttpServletRequest request;
#Override public Response toResponse(Exception ex) {
String body = "";
if (this.request instanceof MyHttpRequest) {
body = ((MyHttpRequest)request).getRequestBody()
}
}
You'll need a wrapper class for ServletInputStream, and you can find an example implementation here: Modify HttpServletRequest body
I know this is an old question but I found a workaround that I think it's nice to share.
With the following code you should be able to get the ContainerRequestContext inside the ExceptionMapper, then you can read the body, query params, headers, etc.
#Provider
public class CustomExceptionMapper implements ExceptionMapper<CustomException> {
#Context
private ResourceContext resourceContext;
#Override
public Response toResponse(CustomException e) {
ContainerRequestContext requestContext =
resourceContext.getResource(ContainerRequestContext.class);
}
}
Hope it can help

Categories