32

I created a RestController which look like this :

@RestController
public class GreetingController {

    @RequestMapping(value = "/greetings", method = RequestMethod.GET)
    public Mono<Greeting> greeting(HttpServletRequest request) {

        return Mono.just(new Greeting("Hello..." + request.toString()));
    }
}

Unfortunately when I try to hit the "greetings" endpoint I get an exception :

java.lang.IllegalStateException: No resolver for argument [0] of type [org.apache.catalina.servlet4preview.http.HttpServletRequest]

I am using

compile('org.springframework.boot.experimental:spring-boot-starter-web-reactive')

How to fix this ?

Link to full stack-trace. Link to build.gradle

----------EDIT----------

Using the interface. Now getting :

java.lang.IllegalStateException: No resolver for argument [0] of type [javax.servlet.http.HttpServletRequest] on method (rest is same)

Brian Clozel
  • 56,583
  • 15
  • 167
  • 176
Dexter
  • 1,710
  • 2
  • 17
  • 34
  • 1
    You are using the wrong `HttpServletRequest`. Use the interface instead of a concrete implementation. – M. Deinum Nov 01 '16 at 13:50
  • Fixed it, but still Spring giving trouble. – Dexter Nov 01 '16 at 13:56
  • Try adding @Context before HttpServletRequest request? http://cxf.apache.org/docs/jax-rs-basics.html#JAX-RSBasics-Contextannotations – Lawrence Tierney Nov 01 '16 at 15:29
  • Nope none of the "HandlerMethodArgumentResolver", as mentioned below in my answer handles this annotation. I think ServletServerHttpRequest is the way to go... – Dexter Nov 02 '16 at 06:17

2 Answers2

50

You should never use the Servlet API in a Spring Reactive Web application. This is not supported and this is making your app container-dependent, whereas Spring Web Reactive can work with non-Servlet runtimes such as Netty.

Instead you should use the HTTP API provided by Spring; here's your code sample with a few changes:

import org.springframework.http.server.reactive.ServletServerHttpRequest;

@RestController
public class GreetingController {

    @GetMapping("/greetings")
    public Mono<Greeting> greeting(ServerHttpRequest request) {

        return Mono.just(new Greeting("Hello..." + request.getURI().toString()));
    }
}

You can inject either ServerWebExchange or directly ServerHttpRequest / ServerHttpResponse.

Kris
  • 3,898
  • 1
  • 23
  • 32
Brian Clozel
  • 56,583
  • 15
  • 167
  • 176
  • I can understand "making your app container-dependent", but what do you mean by "not supported " ? – Dexter Nov 06 '16 at 14:48
  • 3
    The class you were using to get the servlet response was internal and should not be used in application code. This can be also very problematic, since you should only use the Servlet 3.1 async IO API to write to the body, or you'll risk blocking completely your application. – Brian Clozel Nov 10 '16 at 11:29
4

I went deep into the call hierarchy and found that there is this class InvocableHandlerMethod, in package org.springframework.web.reactive.result.method , which has :

private List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();

There is a resolveArguments() method in this class, which is called to "resolve the arguments". Unfortunately there is no resolver for javax.servlet.http.HttpServletRequest in this list.

There is however a ServerWebExchangeArgumentResolver which is able to resolve ServletServerHttpRequest, from this I can extract the HttpServletRequest. Yeaaa....

So the endpoint looks like :

@RequestMapping(value = "/greetings", method = RequestMethod.GET)
public Mono<Greeting> greeting(ServletServerHttpRequest servletServerHttpRequest) {

    HttpServletRequest httpServletRequest = servletServerHttpRequest.getServletRequest();
    .
    .
    .
}

It is important that the ServletServerHttpRequest be from the package org.springframework.http.server.reactive

Dexter
  • 1,710
  • 2
  • 17
  • 34