Spring-data-rest-webmvc: Why cannot the ObjectError be rendered directly when handling the exception - MethodArgumentNotValidException? - spring

In light of the DefaultErrorAttributes, where ObjectError can be used to express the error details, I intended to utilize ObjectError to express the error details when handling the exception - MethodArgumentNotValidException` in the implementation of a REST API with pure Spring 5.
I handled MethodArgumentNotValidException by extends ResponseEntityExceptionHandler:
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import org.springframework.web.util.WebUtils;
#RestControllerAdvice
public class RestExceptionsHandler extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { request.setAttribute(WebUtils.ERROR_STATUS_CODE_ATTRIBUTE, status.value(), RequestAttributes.SCOPE_REQUEST);
request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, RequestAttributes.SCOPE_REQUEST);
BindingResult re = ((MethodArgumentNotValidException) ex).getBindingResult();
return new ResponseEntity<>(re.getAllErrors().get(0), headers, status);
}
}
In the code above, the BindingResult instance eventually called getAllErrors() to return a List of ObjectErrors. I just tried to get the first element from the List of ObjectErrors, and then presumably would render the ObjectError in JSON format for testing purpose. However, when running it with Jetty, even though the MethodArgumentNotValidException is handled in the mentioned exception handler - handleMethodArgumentNotValid (this is proved with debugger), the JSON for ObjectError could not be rendered in JSON format, instead the default html error page of the Jetty web container is displayed
The error html code generated from Jetty is the following:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 400 Bad Request</title>
</head>
<body>
<h2>HTTP ERROR 400</h2>
<p>Problem accessing /masterdata/cities. Reason:
<pre> Bad Request</pre>
</p>
<h3>Caused by:</h3>
<pre>org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public com.rx.entity.City com.rx.rest.controller.CityController.createCity(com.rx.entity.City): [Field error in object &apos;city&apos; on field &apos;city&apos;: rejected value [null]; codes [NotNull.city.city,NotNull.city,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [city.city,city]; arguments []; default message [city]]; default message [city cannot be empty]]
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:138)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:126)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:166)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:859)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1623)
at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:214)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:540)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1588)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1345)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:480)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1557)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1247)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:220)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:126)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.Server.handle(Server.java:502)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:364)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
at java.lang.Thread.run(Thread.java:748)
</pre>
<hr>
Powered by Jetty:// 9.4.14.v20181114
<hr/>
</body>
</html>
Quetion: Why cannot the ObjectError be rendered directly when handling the exception - MethodArgumentNotValidException?

Related

Spring Security + Thymeleaf - TemplateInputException after a second login

I have a navbar with LOGIN, PROFILE, and LOGOUT.
My goal is to remove the LOGIN and show only PROFILE and LOGOUT
after the user is logged in.
I have the controller checking for authenticated users:
#Controller
public class LoginController {
#GetMapping("/login")
private String loginRender(){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || authentication instanceof AnonymousAuthenticationToken){
return "login";
}else {
return "redirect:/";
}
}
}
The Thymeleaf template looks like this:
<ul class="logout-ul top-links-container">
<li class="top-links-item text-center" sec:authorize="!isAuthenticated()"> <i class="icon-user4" style="color: #e35f5f"></i>Login</li>
<li class="top-links-item text-center" sec:authorize="isAuthenticated()"><i class="icon-user4" style="color: #e35f5f"></i>Profile</li>
<li class="text-center logout" sec:authorize="isAuthenticated()"><form th:action="#{/logout}" th:method="post"><button title="LOGOUT" class="btn" type="submit"><i class="icon-off"></i></button></form></li>
</ul>
Configuration:
http
.authorizeRequests()
.antMatchers("/login", "/", "register",
"/custom-transfers/**", "/about-us", "/information/**", "/support/**").permitAll()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.antMatchers("/admin").hasRole(UserRoleEnum.ADMIN.name())
.antMatchers("/**").authenticated()
.and()
.formLogin()
.loginPage("/login")
.usernameParameter(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_USERNAME_KEY)
.passwordParameter(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_PASSWORD_KEY)
.defaultSuccessUrl("/user/profile")
//TODO validation page
.failureForwardUrl("/login")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID");
ISSUE
It all works when the user first logs in. When logouts and log in again, Thymleaf shows a TemplateInputException.
Exception:
ERROR 26304 --- [nio-8080-exec-9] s.e.ErrorMvcAutoConfiguration$StaticView : Cannot render error page for request [/login] and exception [An error happened during template parsing (template: "class path resource [templates/login.html]")] as the response has already been committed. As a result, the response may have the wrong status code.
org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/login.html]")
at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:241) ~[thymeleaf-3.0.12.RELEASE.jar:3.0.12.RELEASE]
at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parseStandalone(AbstractMarkupTemplateParser.java:100) ~[thymeleaf-3.0.12.RELEASE.jar:3.0.12.RELEASE]
at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:666) ~[thymeleaf-3.0.12.RELEASE.jar:3.0.12.RELEASE]
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098) ~[thymeleaf-3.0.12.RELEASE.jar:3.0.12.RELEASE]
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072) ~[thymeleaf-3.0.12.RELEASE.jar:3.0.12.RELEASE]
at org.thymeleaf.spring5.view.ThymeleafView.renderFragment(ThymeleafView.java:366) ~[thymeleaf-spring5-3.0.12.RELEASE.jar:3.0.12.RELEASE]
at org.thymeleaf.spring5.view.ThymeleafView.render(ThymeleafView.java:190) ~[thymeleaf-spring5-3.0.12.RELEASE.jar:3.0.12.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1400) ~[spring-webmvc-5.3.10.jar:5.3.10]
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1145) ~[spring-webmvc-5.3.10.jar:5.3.10]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1084) ~[spring-webmvc-5.3.10.jar:5.3.10]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.10.jar:5.3.10]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.10.jar:5.3.10]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.10.jar:5.3.10]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:655) ~[tomcat-embed-core-9.0.53.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.10.jar:5.3.10]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.53.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.53.jar:9.0.53]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.53.jar:9.0.53]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.53.jar:9.0.53]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.53.jar:9.0.53]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.53.jar:9.0.53]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327) ~[spring-security-web-5.5.2.jar:5.5.2]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) ~[spring-security-web-5.5.2.jar:5.5.2]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) ~[spring-security-web-5.5.2.jar:5.5.2]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.5.2.jar:5.5.2]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:121) ~[spring-security-web-5.5.2.jar:5.5.2]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115) ~[spring-security-web-5.5.2.jar:5.5.2]
I tried placing sec:authorize="!isAuthenticated()" outside in a <div>, tried to pass a boolean to the template with a RedirectAttribute and Model, but I can't still fix the issue.
It works when I add:
<li class="top-links-item" sec:authorize="!isAuthenticated()">TEST</li>
so I assume is because I use sec:authorize for a login page, which is managed by Spring Security. Could there be any relation?
UPDATE I found that after logout the Cookie destroys and it doesn't creates a new one for a second login. Also the issue is only of logout form in the html when I add sec:authorize=isAuthenticated(). Therefore the problem is connected to the logout instead of the login page. Why could this happen?
This occurs only when I use isAuthenticated() in Thyemleaf.
What am I doing wrong?
I would really appreciate your help.
Thank you.
I think that what happens here is the following:
Your logout form is managed by Thymeleaf which means that under the hood Thymeleaf will try to create a hidden field with the CSRF token inside. This normally works and it requires existing or new session.
The problem is that Thymeleaf is designed to minimize latencies by producing template output as your template is being processed. Thus when a page is longer in size (as it is in your case) by the time when the engine reaches your logout <form> tag some of the output MAY HAVE BEEN streamed to the client and the server starts to consider your response as committed. Once the response is marked as committed Thymeleaf will fail to access/create a session. I guess this is an architectural constraint.
So I'm not sure what exactly to advise you here. Maybe try to output the logout button earlier in your templates or optionally try to eagerly initialize the CSRF token. This setting in HttpSecurity will possibly do it:
.and()
.csrf()
.csrfTokenRepository(new HttpSessionCsrfTokenRepository())

"Could not return the resource to the pool" error with Spring and Redis

I was trying to implement Redis with Spring with XML based configuration. My configuration file like as below:
<!-- declare Redis Cache Manager -->
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"
c:template-ref="redisTemplate" />
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="172.17.0.2" p:use-pool="true" />
<!-- redis template definition -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnectionFactory" />
And my cache definitions like:
#Cacheable(value = "my-cache-key", key = "{#argSomeObj, #argSomeString, #argSomeInt}")
public MyAwesomeDTO getSomeResult(SomeObject argSomeObj, String argSomeString, int argSomeInt, Request argRequest)
{
// this part calculates and returns some values regarding to given parameters
return awesomeDTO;
}
When I hit this function in first time I got error which is stated below. When I try second time, it works properly and stores in Redis.
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
at redis.clients.util.Pool.returnBrokenResourceObject(Pool.java:103)
at redis.clients.jedis.JedisPool.returnBrokenResource(JedisPool.java:239)
at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:255)
at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:16)
at org.springframework.data.redis.connection.jedis.JedisConnection.close(JedisConnection.java:257)
at org.springframework.data.redis.core.RedisConnectionUtils.releaseConnection(RedisConnectionUtils.java:206)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:205)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:153)
at org.springframework.data.redis.cache.RedisCache.put(RedisCache.java:140)
at org.springframework.data.redis.cache.RedisCache.put(RedisCache.java:125)
at org.springframework.cache.interceptor.AbstractCacheInvoker.doPut(AbstractCacheInvoker.java:82)
at org.springframework.cache.interceptor.CacheAspectSupport$CachePutRequest.apply(CacheAspectSupport.java:651)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:358)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:299)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
Is there anybody knows how can I fix this error?
Here is the full stack trace:
01-30 12:34:35 [Thread#12:34:35.259:https://www.vtokmak.office.com:8443/some-url] ERROR com.tokmak.frontend.MyApplication - A 500 error (redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool) occured on URL [https://www.vtokmak.office.com:8443/some-url], userAgent [Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36]
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
at redis.clients.util.Pool.returnBrokenResourceObject(Pool.java:103)
at redis.clients.jedis.JedisPool.returnBrokenResource(JedisPool.java:239)
at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:255)
at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:16)
at org.springframework.data.redis.connection.jedis.JedisConnection.close(JedisConnection.java:257)
at org.springframework.data.redis.core.RedisConnectionUtils.releaseConnection(RedisConnectionUtils.java:206)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:205)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:153)
at org.springframework.data.redis.cache.RedisCache.put(RedisCache.java:140)
at org.springframework.data.redis.cache.RedisCache.put(RedisCache.java:125)
at org.springframework.cache.interceptor.AbstractCacheInvoker.doPut(AbstractCacheInvoker.java:82)
at org.springframework.cache.interceptor.CacheAspectSupport$CachePutRequest.apply(CacheAspectSupport.java:651)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:358)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:299)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
at com.tokmak.frontend2.service.misc.world.WorldService$$EnhancerBySpringCGLIB$$8a70244e.getWorld(<generated>)
at com.tokmak.frontend2.controller.world.AbstractWorldController.handle(AbstractWorldController.java:69)
at com.tokmak.frontend.Router.getView(Router.java:1069)
at com.tokmak.frontend.Router.routeRequest(Router.java:320)
at com.tokmak.webframework.RouterServlet.doRequestProcessingUnchecked(RouterServlet.java:145)
at com.tokmak.webframework.RouterServlet.doRequestProcessing(RouterServlet.java:93)
at com.tokmak.webframework.RouterServlet.doGet(RouterServlet.java:68)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalStateException: Invalidated object not currently part of this pool
at org.apache.commons.pool2.impl.GenericObjectPool.invalidateObject(GenericObjectPool.java:640)
at redis.clients.util.Pool.returnBrokenResourceObject(Pool.java:101)
... 44 more
// 01-30 12:34:35 [Thread#12:34:35.259:https://www.vtokmak.office.com:8443/some-url] WARN com.tokmak.webframework.RouterServlet - Exception [/some-url], message: "Could not return the resource to the pool"]
01-30 12:34:35 [Thread#12:34:35.259:https://www.vtokmak.office.com:8443/some-url] WARN com.tokmak.frontend.Router - I have to make use of static fail over [http://192.168.3.14/]...
01-30 12:34:35 [Thread#12:34:35.259:https://www.vtokmak.office.com:8443/some-url] WARN com.tokmak.frontend.Router - ... but since there is a static fail-over URL present in config, I try to load the data from [http://192.168.3.14/www.vtokmak.office.com:8443/some-url]
01-30 12:34:35 [Thread#12:34:35.259:https://www.vtokmak.office.com:8443/some-url] WARN com.tokmak.frontend.Router - fuck, even though I have a static fail-over URL, I failed!
Jan 30, 2018 12:34:36 PM org.apache.jasper.compiler.TldLocationsCache tldScanJar
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
although I can't see your code, I've seen this happen when you try to close a jedis instance twice, without noticing. for eg:
Jedis implements Closable and when inside a try-with-Resources it will be automatically closed.
try(Jedis jedis = getJedis()){
}catch{...}
thus if you also call jedis.close() it will throw that error.
either
try{
Jedis jedis = getJedis();
}catch(){
}finally{
jedis.close()
}
or see if you're calling close() more than once
As #mp911de mentioned here, this problem was related to Spring Data Redis version. When I upgraded it resolved.
Here is the java based configuration. Try and share results.
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import redis.clients.jedis.JedisPoolConfig;
#Configuration
#EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {
#Override
#Bean
public CacheManager cacheManager() {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate());
cacheManager.setUsePrefix(true);
//cacheManager.setCacheNames(getCacheNames());
return cacheManager;
}
#Bean
public RedisTemplate<Object, Object> redisTemplate() {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
redisTemplate.setExposeConnection(true);
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
om.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
om.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
om.setSerializationInclusion(Include.NON_NULL);
jackson2JsonRedisSerializer.setObjectMapper(om);
redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setEnableDefaultSerializer(true);
return redisTemplate;
}
#Bean
public JedisConnectionFactory jedisConnectionFactory() {
JedisPoolConfig config = new JedisPoolConfig();
config.setTestOnBorrow(false);
config.setTestOnCreate(false);
config.setTestOnReturn(false);
config.setTestWhileIdle(false);
config.setMaxTotal(1000);
config.setMaxIdle(1000);
config.setMinIdle(0);
config.setMaxWaitMillis(10000);
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
connectionFactory.setHostName("172.17.0.2");
//connectionFactory.setPort(6379);
connectionFactory.setUsePool(true);
connectionFactory.setPoolConfig(config);
return connectionFactory;
}
#Override
#Bean
public KeyGenerator keyGenerator() {
return new SimpleKeyGenerator();
}
}

ControllerAdvice configuration not working

I am having issues trying to get the controller advice working, Below is my code snippet. I have tired most of the answers on stackoverflow but havent had any success. I would appreciate if someone could guide me with this.
```
#ControllerAdvice
public class PollCoreExceptionHandler {
#ExceptionHandler(Exception.class)
public #ResponseBody ResponseException handleIllegalArgumentServiceException(
final Exception illegalArgumentServiceException) {
System.out.println("Error handling called ");
final ResponseException responseException = new ResponseException();
responseException.setErrorMessage("Error handler called " + illegalArgumentServiceException.getMessage());
return responseException;
}
}
```
My controller
```
#RequestMapping(value = "/login", method = RequestMethod.POST)
public UserDTO loginUser(#RequestBody final UserDTO userDto) throws Exception {
throw new Exception("error testing ");
}
```
Output
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 500 Server Error</title>
</head>
<body>
<h2>HTTP ERROR 500</h2>
<p>Problem accessing /ws/user/login. Reason:
<pre> Server Error</pre>
</p>
<h3>Caused by:</h3>
<pre>javax.servlet.ServletException: org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.Exception: error testing
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.Server.handle(Server.java:564)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:317)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:110)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
at org.eclipse.jetty.util.thread.Invocable.invokePreferred(Invocable.java:128)
at org.eclipse.jetty.util.thread.Invocable$InvocableExecutor.invoke(Invocable.java:222)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouK
</pre>
<h3>Caused by:</h3>
<pre>java.lang.Exception: error testing
at com.multi.enterprise.poll.core.controllers.UserController.loginUser(UserController.java:65)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet
I also see this when my app boots up.
2017-04-30 15:07:05,488 [main] INFO annotation.ExceptionHandlerExceptionResolver:273 () - Detected #ExceptionHandler methods in controllerAdvisor
2017-04-30 15:07:05,488 [main] INFO annotation.ExceptionHandlerExceptionResolver:273 () - Detected #ExceptionHandler methods in pollCoreExceptionHandler
2017-04-30 15:07:05,585 [main] INFO servlet.DispatcherServlet:508 () - FrameworkServlet 'dispatcher': initialization completed in 1213 ms

Disabling Spring MVC view resolution for a REST only application

I would like to disable Spring MVC view resolution for my application.
My application only uses Thymeleaf for mail templates and Spring MVC for the REST API. It does not serve Thymleaf pages.
I have configured the following property in my application.properties:
spring.thymeleaf.enabled=false
But I still get errors such as:
20:28:51.851 [http-nio-8080-exec-10] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet dispatcherServlet threw exception
javax.servlet.ServletException: Circular view path [error]: would dispatch back to the current handler URL [/error] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
at org.springframework.web.servlet.view.InternalResourceView.prepareForRendering(InternalResourceView.java:205)
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:145)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1257)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1037)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:726)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:471)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:394)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:311)
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:395)
at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:254)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:177)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:784)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:802)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1410)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
How can I use Thymeleaf whilst disabling view resolution for Spring MVC?
edit: Actually the only view I am serving is the SPA's index.html as follows:
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/index.html");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")//
.addResourceLocations("classpath:/")//
.setCachePeriod(ONE_YEAR);
registry.addResourceHandler("/")//
.addResourceLocations("classpath:/index.html")//
.setCachePeriod(0);
}
I think problem here is, when spring encounters an error, it is forwarding "user" to /error page. Try adding following in your properties.
spring.resources.add-mappings=false
You probably have a controller which returns some string which cannot be resolved by Spring View resolver. If you want to return JSON object use #RestController annotation for your class
MainController.java
#RestController
public class MainController {
#GetMapping("/")
public TestResponseDto greeting(/*here can be any params*/) {
System.out.println("here");
return new TestResponseDto();
}
}
TestResponse.java
public class TestResponseDto {
public String response = "test";
}

Spring Boot with SiteMesh 3

I'm writing a new web app using Spring Boot for the first time and am trying to use SiteMesh 3 without success.
I'm using a web initializer to bootstrap;
public class WebInitializer extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
I've configured the filter in the Application config class as below;
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application {
#Bean
public FilterRegistrationBean siteMeshFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new MySiteMeshFilter());
return filterRegistrationBean;
}
}
MySiteMeshFilter is as follows;
public class MySiteMeshFilter extends ConfigurableSiteMeshFilter {
#Override
protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {
builder.addDecoratorPath("/*", "/decorators/decorator.html");
}
}
Under src/main/webapp/WEB-INF/ I have a folder decorators containing decorator.html;
<html>
<head>
<title><sitemesh:write property='title'/></title>
<sitemesh:write property='head'/>
</head>
<body>
<p>This has been decorated!!!</p>
<sitemesh:write property='body'/>
</body>
</html>
and under src/main/webapp/static I have a basic html file;
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<p>Just a test html page</p>
</body>
</html>
But ... on running web app (I'm deploying the war on tomcat - not embedded) and going to localhost:8080/static/test.html I get ...
2014-09-18 16:17:53.696 ERROR 7233 --- [io-8080-exec-10] o.s.boot.context.web.ErrorPageFilter : Forwarding to error page from request [/static/test.htmlnull] due to exception [Cannot forward after response has been committed]
java.lang.IllegalStateException: Cannot forward after response has been committed
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:348)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
at org.springframework.boot.context.web.ErrorPageFilter.handleErrorStatus(ErrorPageFilter.java:134)
at org.springframework.boot.context.web.ErrorPageFilter.doFilter(ErrorPageFilter.java:111)
at org.springframework.boot.context.web.ErrorPageFilter.access$000(ErrorPageFilter.java:58)
at org.springframework.boot.context.web.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:87)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.boot.context.web.ErrorPageFilter.doFilter(ErrorPageFilter.java:100)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
If I comment out the SiteMesh filter in the configuration file (Application class) then I see the undecorated test.html find.
So am I missing something very obvious here?

Resources