My example code
@Controller
public class DemoController {
@GetMapping(path = "/demo/{*path}")
public Object demo(@PathVariable String path) {
System.out.println(path);
return null;
}
}
gradle config
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.5'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'org.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
Problem
When I try to request http://localhost:8080/demo/XXX
Java heap space
java.lang.OutOfMemoryError: Java heap space
at java.base/jdk.internal.misc.Unsafe.allocateUninitializedArray0(Unsafe.java:1382)
at java.base/jdk.internal.misc.Unsafe.allocateUninitializedArray(Unsafe.java:1375)
at java.base/java.lang.StringConcatHelper.newArray(StringConcatHelper.java:494)
at java.base/java.lang.StringConcatHelper.simpleConcat(StringConcatHelper.java:421)
at java.base/java.lang.invoke.DirectMethodHandle$Holder.invokeStatic(DirectMethodHandle$Holder)
at java.base/java.lang.invoke.DelegatingMethodHandle$Holder.reinvoke_L(DelegatingMethodHandle$Holder)
at java.base/java.lang.invoke.Invokers$Holder.linkToTargetMethod(Invokers$Holder)
at org.springframework.util.StringUtils.applyRelativePath(StringUtils.java:682)
at org.springframework.web.servlet.view.InternalResourceView.prepareForRendering(InternalResourceView.java:209)
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:148)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:314)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1431)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1167)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1106)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:110)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:110)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:110)
Comment From: bclozel
Thanks for getting in touch but this controller implementation is invalid - the null
view name causes a infinite recursion, dispatching again on the same controller method. This is causing the OOM, rather than the usage of @PathVariable
. Can you explain what you're trying to achieve here by returning a null
object as a view name?
Comment From: mitu2
Thanks for getting in touch but this controller implementation is invalid - the
null
view name causes a infinite recursion, dispatching again on the same controller method. This is causing the OOM, rather than the usage of@PathVariable
. Can you explain what you're trying to achieve here by returning anull
object as a view name?
I encountered when using {path} ->{* path}. The former does not affect the service when returning null, so it was not processed during use. Getting the view name from the database happened to get null, and calling this API multiple times caused the service to continuously trigger OOM
// javax.servlet.ServletException: Circular view path [demo1]: would dispatch back to the current handler URL [/demo1] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
@GetMapping(path = "demo1")
public String demo1() {
return null;
}
// NoResourceFoundException
@GetMapping(path = "demo2/{path}")
public String demo2(@PathVariable("path") String path) {
System.out.println(path);
return null;
}
// Just add a *, {path} -> {*path}
// java.lang.OutOfMemoryError: Java heap space
@GetMapping(path = "demo3/{*path}")
public String demo3(@PathVariable("path") String path) {
System.out.println(path);
return null;
}
// Just add a *, {path} -> {*path}
// javax.servlet.ServletException: Circular view path []: would dispatch back to the current handler URL [/demo4/123/] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
@GetMapping(path = "demo4/{*path}")
public String demo4(@PathVariable("path") String path) {
System.out.println(path);
return "";
}
Comment From: bclozel
As explained above, you would get infinite recursion without @PathVariable
in the first place. I'm closing this issue as an application error. Thanks for your report.
Comment From: mitu2
As explained above, you would get infinite recursion without
@PathVariable
in the first place. I'm closing this issue as an application error. Thanks for your report.
Okay