1

we have a working asynchronous REST API with Spring Boot and Hateoas:

@RestController
@EnableAutoConfiguration
@RequestMapping("/metfrag/api/v1")
/** @RequestMapping("${metfragrest-controller.path}") Fail in linkTo() **/ 
public class MetFragRestController {
...
    @RequestMapping(method = RequestMethod.POST, value = "", ...)
    @ResponseBody
    public ResponseEntity<Resource<ProcessAssembler>> process(...) {
        ...
        linkTo(MetFragRestController.class).slash("status").slash(processid);
        ...
    }
}

The linkTo() is needed to return the URL where to poll for the job status.

This breaks if I provide the base URL from an application.properties value: @RequestMapping("${metfragrest-controller.path}"). The linkTo() calls o.s.hateoas.mvc.ControllerLinkBuilder.linkTo(), which uses o.s.web.util.UriComponents.expand() and fails in o.s.web.util.UriComponents$VarArgsTemplateVariables.getValue().

What I need is the call

resource.add(linkTo(MetFragRestController.class).slash("status").slash(processid).withRel("status"));

to return something like http://localhost:8090/metfrag/api/v1/status/java_io_tmpdir5547995162586347505

Any ideas what to try next ?

Thanks in advance,

yours, Steffen

If needed, full code is available from MetFragRestController.java

Full java trace:

2023-06-21 12:32:51.457 ERROR 1 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: Not enough variable values available to expand 'metfragrest-controller.path'] with root cause

java.lang.IllegalArgumentException: Not enough variable values available to expand 'metfragrest-controller.path'
    at org.springframework.web.util.UriComponents$VarArgsTemplateVariables.getValue(UriComponents.java:329) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.util.UriComponents.expandUriComponent(UriComponents.java:232) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.util.HierarchicalUriComponents$FullPathComponent.expand(HierarchicalUriComponents.java:688) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.util.HierarchicalUriComponents.expandInternal(HierarchicalUriComponents.java:331) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.util.HierarchicalUriComponents.expandInternal(HierarchicalUriComponents.java:48) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.util.UriComponents.expand(UriComponents.java:165) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.util.UriComponentsBuilder.buildAndExpand(UriComponentsBuilder.java:360) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.util.DefaultUriTemplateHandler.expandAndEncode(DefaultUriTemplateHandler.java:147) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.hateoas.mvc.ControllerLinkBuilder$CustomUriTemplateHandler.expandAndEncode(ControllerLinkBuilder.java:340) ~[spring-hateoas-0.23.0.RELEASE.jar!/:na]
    at org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo(ControllerLinkBuilder.java:122) ~[spring-hateoas-0.23.0.RELEASE.jar!/:na]
    at org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo(ControllerLinkBuilder.java:102) ~[spring-hateoas-0.23.0.RELEASE.jar!/:na]
    at de.ipbhalle.metfragrest.MetFragRestController.process(MetFragRestController.java:119) ~[classes!/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) ~[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1457) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-8.5.20.jar!/:8.5.20]
    at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na]
sneumann
  • 11
  • 2
  • I double-checked that the variable is available in the controller `de.ipbhalle.metfragrest.MetFragRestController - The value of the property variable is: /metfrag/api/v2` but it is "lost" further in the stacktrace beyond `o.s.hateoas.server.mvc.WebMvcLinkBuilder.linkTo()` Still lost how to continue :-( – sneumann Jun 23 '23 at 19:35
  • Solved: Workaround is to NOT provide the baseURL in the @RequestMapping, , and use server.servlet.context-path instead. Yours, Steffen – sneumann Jun 23 '23 at 21:05

0 Answers0