Adrian Reyes Adrian Reyes - 1 year ago 97
Java Question

Spring Boot, java.lang.IllegalStateException when calling ControllerLinkBuilder.linkTo from a websocket

I'm getting the following error when calling

from a websocket.

java.lang.IllegalStateException: Could not find current request via RequestContextHolder
at org.springframework.util.Assert.state(
at org.springframework.hateoas.mvc.ControllerLinkBuilder.getCurrentRequest(
at org.springframework.hateoas.mvc.ControllerLinkBuilder.getBuilder(
at org.springframework.hateoas.mvc.ControllerLinkBuilderFactory.linkTo(
at org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo(
at urlshortener2014.common.web.UrlShortenerController.createAndSaveIfValid(
at urlshortener2014.richcarmine.web.UrlShortenerControllerWithLogs.access$200(
at urlshortener2014.richcarmine.web.UrlShortenerControllerWithLogs$
at urlshortener2014.richcarmine.massiveShortenerNaiveWS.ShortURLWSGenerator.onCall(
at urlshortener2014.richcarmine.massiveShortenerNaiveWS.ShortURLWSGenerator.onCall(
at java.util.concurrent.Executors$
at java.util.concurrent.ThreadPoolExecutor.runWorker(
at java.util.concurrent.ThreadPoolExecutor$

The whole project is about shortening urls, as my first approach with spring websockets I'm trying to get it work just by answering back the shortened url from any url.


public class MyHandler extends TextWebSocketHandler {

AtomicLong messageOrder = new AtomicLong(0);
ExecutorService threadPool = Executors.newCachedThreadPool();
CompletionService<CSVContent> pool = new ExecutorCompletionService<>(threadPool);

/* controller reference */
UrlShortenerControllerWithLogs controller;

protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {"WS: " + message.getPayload());
long order = messageOrder.getAndIncrement();
pool.submit(new ShortURLWSGenerator(order,message.getPayload(),"","","",session.getRemoteAddress(),controller));
CSVContent content = pool.take().get();
session.sendMessage(new TextMessage("Echo Test: " + content.getShortURL().getUri()));

Here is

public class ShortURLWSGenerator extends RequestContextAwareCallable<CSVContent>{
public CSVContent onCall() {

ShortURL shortURL = null;
try {
shortURL = controller. new CreateCallable(url,sponsor,brand,owner,address.toString()).call();
} catch (Exception e) {

CSVContent content = new CSVContent();

return content;

Used RequestContextAwareCallable which solved the same problem when implementing the same functionlity as a REST service, in any case I'm still getting the same error even with a simple Callable.

Here is CreateCallable that just wraps the main function

public class CreateCallable implements Callable<ShortURL>{
public ShortURL call() throws Exception {
/* explodes while creating the new short url */
return createAndSaveIfValid(url,sponsor,brand,owner,ip);

Finally here is
which calls

protected ShortURL createAndSaveIfValid(String url, String sponsor,
String brand, String owner, String ip) {
UrlValidator urlValidator = new UrlValidator(new String[] { "http",
"https" });
if (urlValidator.isValid(url)) {
String id = Hashing.murmur3_32()
.hashString(url, StandardCharsets.UTF_8).toString();
ShortURL su = new ShortURL(id, url,
id, null)).toUri(), sponsor, new Date(
System.currentTimeMillis()), owner,
HttpStatus.TEMPORARY_REDIRECT.value(), true, ip, null);
} else {
return null;

The complete project can be found here on github

Answer Source

linkTo depends on the current HTTP request but the HTTP current request does not exist because the call was originated by a WebSocket event. Therefore you need a different approach.

  1. Create a method named e.g. createAndSaveIfValidExtended based on createAndSaveIfValid. The code is the same but linkTo(methodOn(UrlShortenerController.class).redirectTo(id, null)).toUri() is replaced by the method createLink(id)

  2. Create a method String createLink(String id). This method will build the URL by using a property defined in (see here how) whose value will be injected in a field that represents where the app will be deployed concatenated with /l and the value of ìd.

  3. In CreateCallable, call createAndSaveIfValidExtended instead of createAndSaveIfValid