getRequestURI is null with Netty and Spring Boot 3 - spring

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' : ''}"

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

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}

Related

Spring Boot 2.4.2 and Thymeleaf 3.0.12 - access static methods

Since I switched to Spring Boot 2.4.2 my Thymeleaf templates are broken. When I want to access a static member in Spring Controller I get the following error:
Exception processing template "template_name": Instantiation of new
objects and access to static classes is forbidden in this context.
The code looks like:
th:text="${T(com.test).testMethod("1234")}"
Do you have any recommendation to fix this?
This change is the part of Thymeleaf 3.0.12. They improve restricted expression evaluation mode security by restriction of the access to static code (#identifier# in OGNL, T(identifier) in SpringEL). What they have done by themselves? ... "Avoided instantiation of new objects and calls to static classes" as stated in release notes. You may move the JAVA calls into your controller and put the result into the view model. After just access this variable from Thymeleaf template.
Another quick fix is the use of th:with
th:text="${testText}"
th:with="testText=${T(com.test).testMethod("1234")}"
Source/Kudos: https://github.com/thymeleaf/thymeleaf/issues/816#issuecomment-791921248 and https://github.com/thymeleaf/thymeleaf/issues/816#issuecomment-826401631
There is a workaround to use method from beans registered at the Spring Application Context with the #beanName syntax. Like this:
<div th:text="${#testService.testMethod('123')}">...</div>
http://www.thymeleaf.org/doc/articles/springmvcaccessdata.html

What is exactly server.error.path property?

In Spring Boot, what is the purpose of server.error.path property in application.properties file?
The documentation just says:
Path of the error controller
But I want a clear description of this property with an example.
server.error.path - used as part of url for error pages.
site.getBaseUrl() + "/error"
For example some error happen on server side and you decide redirect user to error page like this:
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/images/custom-error-page-aws-404-example.png
Code example of error controller you can find here:
https://www.logicbig.com/tutorials/spring-framework/spring-boot/implementing-error-controller.html
You can use this property in #RequestMapping("/error"). But instead of "/error" you can use "${server.error.path}"
UPDATE:
Also, Spring Boot BasicErrorController use server.error.path property
Property server.error.path in spring boot application used to define an error path while dealing with custom error handler. In Spring we create custom error handler using functional interface ErrorController, ths interface has a String type method getErrorPath which helps us to return the error page path(our error page as view).
But from Spring 2.3.0 this getErrorPath() method has been deprecated and replaced with server.error.path to manage the error path.
e.g. server.error.path=/error
For more detail about interface ErrorController, please refer Spring doc for ErrorController

How do I use a Spring Service method in a Spring Security expression?

I have a spring Service and want to use a method in the service combined with the current user in a spring security expression. I saw another question on stackoverflow that led me to believe something like this was possible. I'm using spring 3.1.2.
#Service("orgService")
public class DefaultOrganizationService implements OrganizationService {
#Override
#Transactional
public boolean isOrgAdmin(String username)
{
return true;
}
}
Then in a jsp, I have something like this:
<sec:authorize access="orgService.isOrgAdmin(principal.name)">
USER IS ORG ADMIN
</sec:authorize>
However, when I run my web app with this setup, I get
org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Field or property 'orgService' cannot be found on object of type 'org.springframework.security.web.access.expression.WebSecurityExpressionRoot'
I've tried expressions with both "#orgService..." and "orgService..."
Is what I'm trying to do possible, or do I need to implement a PermissionEvaluator?
#orgService should work, for Spring Security starting from Version 3.1.0.RC2
[SEC-1723] - Support use of bean names in expressions via #beanName notation
I'm using spring 3.1.2.
I think that you are using an old version of Spring Security, not Spring.

Spring MVC 3.0 - restrict what gets routed through the dispatcher servlet

I want to use Spring MVC 3.0 to build interfaces for AJAX transactions. I want the results to be returned as JSON, but I don't necessarily want the web pages to be built with JSP. I only want requests to the controllers to be intercepted/routed through the DispatcherServlet and the rest of the project to continue to function like a regular Java webapp without Spring integration.
My thought was to define the servlet-mapping url pattern in web.xml as being something like "/controller/*", then have the class level #RequestMapping in my controller to be something like #RequestMapping("/controller/colors"), and finally at the method level, have #RequestMapping(value = "/controller/colors/{name}", method = RequestMethod.GET).
Only problem is, I'm not sure if I need to keep adding "/controller" in all of the RequestMappings and no matter what combo I try, I keep getting 404 requested resource not available errors.
The ultimate goal here is for me to be able to type in a web browser "http://localhost:8080/myproject/controller/colors/red" and get back the RGB value as a JSON string.
You are not correct about needing to add the entire path everywhere, the paths are cumulative-
If you have a servlet mapping of /controller/* for the Spring's DispatcherServlet, then any call to /controller/* will be handled now by the DispatcherServlet, you just have to take care of rest of the path info in your #RequestMapping, so your controller can be
#Controller
#RequestMapping("/colors")
public class MyController{
#RequestMapping("/{name}
public String myMappedMethod(#PathVariable("name") String name, ..){
}
}
So now, this method will be handled by the call to /controller/colors/blue etc.
I don't necessarily want the web pages to be built with JSP
Spring MVC offers many view template integration options, from passthrough to raw html to rich templating engines like Velocity and Freemarker. Perhaps one of those options will fit what you're looking for.

Spring MVC 3.0.6 Getting hold of the controller and action name

Is there a way to get the controller and action name currently ( or about to ) executing ?
I am interested in getting this primarily in an Interceptor so I can perform logic depending on action.
Grails for example offers this as params.controller and params.action
Anything similar? Could not find anything on the web.
Spring MVC 3.0.6 ( found this Spring MVC : What is the best way to pass the controller + action name to the view? but it was for version 3.1 )
Thanks!
You can use an aspect to get the method name from joinPoint.getSignature().getName(), and that can be added to the Model as an Attribute. The Controller name is probably also in there somewhere.

Resources