getRequestURI is null with Netty and Spring Boot 3
Asked Answered
C

3

5

In Thymeleaf < 3.1 I used below expression to get the request URI.

th:classappend="${#arrays.contains(urls, #httpServletRequest.getRequestURI()) ? 'active' : ''}"

It worked all the time till recently I upgraded to Spring Boot 3.0 that pulls Thymeleaf 3.1. I am getting this exceptions:

[THYMELEAF][parallel-2] Exception processing template "index": Exception evaluating SpringEL expression: "#arrays.contains(urls, #servletServerHttpRequest.getRequestURI()) ? 'active' : ''" (template: "fragments/header" - line 185, col 6)

Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1011E: Method call: Attempted to call method getRequestURI() on null context object

What is the alternative now since I am using Netty instead of Tomcat in Spring Boot 3.0? I could not figure this from here.

As a workaround, for now to tackle this, I am using:

@GetMapping ("/")
String homePage(Model model) {
    model.addAttribute("pagename", "home");
    return "index";
}

AND

th:classappend="${pagename == 'home' ? 'active' : ''}"
Colored answered 27/11, 2022 at 23:16 Comment(0)
F
11

In Thymeleaf 3.0, access is provided to HttpServletRequest:

#request : direct access to the javax.servlet.http.HttpServletRequest object associated with the current request. reference

This has been removed from Thymeleaf in 3.1.0. Here is the equivalent section from the documentation: Web context namespaces for request/session attributes, etc..


The "what's new in 3.1" documentation does not specifically mention HttpServletRequest, but it does mention the removal of all the "web-API based expression utility objects".

The #request, #response, #session, and #servletContext are no longer available to expressions in Thymeleaf 3.1.

Spring Boot 3.0.0 uses Thymeleaf 3.1.0 (as you noted).


What to do instead?

See the related GitHub issue: Recommended way to go after upgrade to SpringBoot3 - attributes

Specifically:

These objects are not directly available in templates in Thymeleaf 3.1 for security reasons. The recommended way to make this information available to templates is to add the specific pieces of information that are really needed by the template as context variables (model attributes in Spring).

Example:

model.addAttribute("servletPath", request.getServletPath();

That is the same basic approach as what you are already doing, in your work-around.


See also: Remove web-API based expression utility objects

Fourth answered 28/11, 2022 at 1:32 Comment(1)
You are awesome @andrewJames. I completely overlooked section 1.6 in the documentation for what's new in 3.1. Thanks a lot for your time and effort.Colored
S
4

Adding to @andrewJames answer,

If you are using request.getServletPath() in many pages, then in such case, it's more convenient to use Spring's @ModelAttribute annotation in a @ControllerAdvice class. It will register this @ModelAttribute method for all controllers in your app. Example:

@ControllerAdvice
public class GlobalController {

  @ModelAttribute("servletPath")
  String getRequestServletPath(HttpServletRequest request) {
    return request.getServletPath();
  }
}

Finally in any page you can access by using:

${servletPath}
Surveillance answered 3/1, 2023 at 13:58 Comment(1)
Yes I am aware of this and using it to publish app name and signed-in user’s name across all the pages.Colored
A
0

Using Thymeleaf 3.1.2 I solved a similar problem adding HttpServletRequest to my route

@RequestMapping("/route")
public String route(Model model, HttpServletRequest request) {
    model.addAttribute("currentUri", request.getRequestURI());
    return "view";
}

In the page you can reference the currentUri attribute for example

th:attr="aria-expanded=${currentUri == '/users' ? 'true' : 'false'}"
Asgard answered 9/2 at 12:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.