I want to show error message while hitting post method url directly using java springboot so I used try catch exception but it is not working, I am getting error message which i mentioned in this question, help or suggestion is appreciated.
I just required when we hit the localhost:8080/LoginProcess, url I need to show error404 html page.
Controller Method
#PostMapping("/LoginProcess")
public String LoginProcess(#ModelAttribute("customer") Customer thecustomer,HttpSession session) {
try {
Customer result = customerservice.Login_service(thecustomer.getUserName(),thecustomer.getPassword());
if(result==null)
{
return "login";
}
else if(result.getRole().equals("1"))
{
session.setAttribute("l_uname",result.getUserName() );
session.setAttribute("l_pwd",result.getPassword() );
return "admindash";
}
else
{
session.setAttribute("l_uname",result.getUserName() );
session.setAttribute("l_pwd",result.getPassword() );
return "customerdash";
}
}catch(Exception e) {
return "err404";
}
}
Error Message
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sun Mar 03 16:18:46 IST 2019
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'GET' not supported
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported
at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:200)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:422)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:368)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:65)
at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:401)
at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1231)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1014)
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.doGet(FrameworkServlet.java:897)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
try use , #PostMapping(value = "/loginProcess") or try use RequestMapping with method #RequestMapping(value = "/loginProcess", method = RequestMethod.POST)
I got the resolution by creating the same duplicate method with #GetMapping and it works fine. now it redirect to my custom error page. thanks to yali who gave me idea through comments.
#GetMapping("/LoginProcess")
public String LoginProcess() {
return "err404";
}
try #ControllerAdviceandExceptionHandler
#ControllerAdvice
public class DemoControllerAdvice {
#ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ResponseEntity<String> handleIOException(HttpRequestMethodNotSupportedException ex) {
// prepare responseEntity
return ResponseEntity.notFound().build();
}
}
You can not send http post request from browser,so I'll suggest you to use post man tools to test.
I'm not sure whether Spring has provided any implementation on it. But you can handle it by writing your own intercepter.intercepter will execute before hitting to controller so you can check http methods type forward it to error jsp
Related
I'm currently working on a plugin for Killbill, using Jooby for developing the servlet. The servlet will receive a notification from payment gateway and process the update into internal Killbill system
#Singleton
public class NotificationServlet {
private final InvoiceApi invoiceApi;
private static final Logger logger = LoggerFactory.getLogger(NotificationServlet .class);
#Inject
public NotificationServlet() {
// initiate InvoiceApi
this.invoiceApi = new InvoiceApi(new KillBillHttpClient());
}
#POST
#Path("/notify")
public Result notify(#Body String body) throws KillBillClientException {
logger.info(body);
JSONObject dataJson = new JSONObject(body);
if (dataJson.getString("status_code").equalsIgnoreCase("1")) {
String referenceId = dataJson.getString("reference_id");
String[] referenceIdArray = referenceId.split("\\|");
String apiKey = referenceIdArray[0];
String apiSecret = referenceIdArray[1];
String accountId = referenceIdArray[2];
String invoiceId = referenceIdArray[3];
String amount = referenceIdArray[4];
InvoicePayment invoicePayment = new InvoicePayment();
invoicePayment.setPurchasedAmount(new BigDecimal(amount));
invoicePayment.setAccountId(UUID.fromString(accountId));
invoicePayment.setTargetInvoiceId(UUID.fromString(invoiceId));
RequestOptions requestOptions = RequestOptions.builder()
.withCreatedBy("createdBy")
.withReason("reason")
.withComment("comment")
.withQueryParams(ArrayListMultimap.create())
.withTenantApiKey(apiKey)
.withTenantApiSecret(apiSecret)
.build();
InvoicePayment result = invoiceApi.createInstantPayment(UUID.fromString(invoiceId),
invoicePayment,
true,
null,
null,
requestOptions);
}
return Results.with("", Status.OK)
.type(MediaType.json);
}
When I tested this servlet using Postman, the servlet works fine. But when I tested this with the payment gateway, I got Jersey's ContainerException
2022-04-07T16:08:07,423+0000 lvl='ERROR', log='[default]', th='catalina-exec-10', xff='', rId='', tok='', aRId='', tRId='', Servlet.service() for servlet [default] in context with path [] threw exception [org.glassfish.jersey.server.ContainerException: java.io.IOException: Stream closed] with root cause
java.io.IOException: Stream closed
at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:367)
at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:152)
at com.google.common.io.ByteStreams.copy(ByteStreams.java:109)
at org.killbill.billing.jaxrs.resources.PluginResource.createInputStream(PluginResource.java:247)
at org.killbill.billing.jaxrs.resources.PluginResource.serviceViaOSGIPlugin(PluginResource.java:185)
at org.killbill.billing.jaxrs.resources.PluginResource.doFormPOST(PluginResource.java:140)
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:498)
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.lambda$static$0(ResourceMethodInvocationHandlerFactory.java:52)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:124)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:167)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:176)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:79)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:475)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:397)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:81)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:255)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:248)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:244)
at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
at org.glassfish.jersey.internal.Errors.process(Errors.java:244)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:265)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:234)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:680)
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:394)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:346)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:366)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:319)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:205)
at com.google.inject.servlet.ServletDefinition.doServiceImpl(ServletDefinition.java:290)
at com.google.inject.servlet.ServletDefinition.doService(ServletDefinition.java:280)
at com.google.inject.servlet.ServletDefinition.service(ServletDefinition.java:184)
at com.google.inject.servlet.ManagedServletPipeline.service(ManagedServletPipeline.java:89)
at org.killbill.billing.server.security.TenantFilter.handleAuthenticationError(TenantFilter.java:120)
at org.killbill.billing.server.security.TenantFilter.doFilter(TenantFilter.java:89)
at org.killbill.billing.server.filters.ResponseCorsFilter.doFilter(ResponseCorsFilter.java:75)
at ch.qos.logback.classic.helpers.MDCInsertingServletFilter.doFilter(MDCInsertingServletFilter.java:49)
at com.google.inject.servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:121)
at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:133)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.shiro.guice.web.SimpleFilterChain.doFilter(SimpleFilterChain.java:44)
at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at org.apache.shiro.guice.web.SimpleFilterChain.doFilter(SimpleFilterChain.java:41)
at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at org.apache.shiro.guice.web.SimpleFilterChain.doFilter(SimpleFilterChain.java:41)
at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.codahale.metrics.servlet.AbstractInstrumentedFilter.doFilter(AbstractInstrumentedFilter.java:111)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:544)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.valves.rewrite.RewriteValve.invoke(RewriteValve.java:305)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:747)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:616)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:818)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1626)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
I'm suspecting it might be because different type of body being sent, since I tested with Postman using raw data in JSON format meanwhile the gateway is sending x-www-form-urlencoded. I noticed this since there's a warning before this error appeared
2022-04-07T16:08:01,477+0000 lvl='WARN', log='WebComponent', th='catalina-exec-9', xff='', rId='', tok='', aRId='', tRId='',
A servlet request to the URI http://path/to/my/notify-servlet contains form parameters in
the request body but the request body has been consumed by the servlet or a servlet filter
accessing the request parameters. Only resource methods using #FormParam will work as
expected. Resource methods consuming the request body by other means will not work as expected.
I've tried adjusting the method according to Jooby's docs on form submission, but the issue still persists. So is the issue still in Jooby or it's in Jersey?
I am using SpringBoot with Spring MVC to do a simple CRUD User Registration HTML5 form with a number of fields to post using the POST submit method. I have a REST Controller which uses #Controller and #ResponseBody, which goes through a user service that calls methods to handle the GET, POST calls to the repository using Spring's JPA repository. As soon as the user keys in a new user record and hits the submit button, the controller will save the record and transfer to the listAllUsers.html view (which contains a grid to show all saved users) using Spring's Model and View.
The user record is succesfully saved when I both use the GET AND POST methods as the action methods in the submitting form and the controller method but after that, the GET method successfully directs my view to listAllUsers.html but the POST method doesn't. When I use the POST method, I get a "Spring Boot 405 POST method not supported" and I am not directed by the controller to the view listAllUsers.html. How do I get redirected to the view, listAllUsers.html using the POST method? I reproduce my code below.
registerNewUser.html:
<div class="card" style="">
<div class="container" style="padding:30px;">
<span style="font-size:20pt;">用户注册</span><br/><br/>
<form id= "add_user" name="add_user" method="POST" action="/addUser">
<div class="card-body">
<table style="border-collapse: separate; border-spacing: 10px;" cellpadding="10" cellspacing="10" width="50%">
<tr><td>昵称</td><td><input type="text" id="txtUserName" name="txtUserName" style="" size="20" placeholder="单行输入"></td></tr>
<tr><td>电话号码</td><td><input type="text" id="txtTelNo" name="txtTelNo" style="" size="20" placeholder="单行输入"></td></tr>
<tr><td>密码</td><td><input type="password" id="txtPassword" name="txtPassword" style="" size="20" placeholder=""></td></tr>
<tr><td>邮箱</td><td><input type="text" id="txtEmail" name="txtEmail" style="" size="20" placeholder="单行输入"></td></tr>
<tr><td colspan="2" style="height:20px;"></td></tr>
<tr><td colspan="2"><input type="submit" style="width:60%;text-align:center;" value="注册"></td></tr>
</table>
</div>
</form>
</div>
</div>
UserController.java:
#Controller
public class UserController {
#Autowired
UserService service;
/*#PostMapping(
value = "/addUser",
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE},
produces = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
*/
#RequestMapping(value = "/addUser", method = RequestMethod.POST)
public ModelAndView addUser(HttpServletRequest request, #RequestParam("txtUserName") String usrName, #RequestParam("txtTelNo") String telNo, #RequestParam("txtPassword") String password, #RequestParam("txtEmail") String email,
HttpSession session) {
User savedUser = new User();
savedUser.setUserName(usrName);
savedUser.setUserTelNo(telNo);
savedUser.setUserPassword(password);
savedUser.setUserEmail(email);
savedUser.setUserRole("开发 人员");
service.addNewUser(savedUser);
ModelAndView mav = new ModelAndView("listUsers");
return mav;
}
}
I got this error message in my console:
2021-01-24 23:51:12.604[0;39m [33m WARN[0;39m [35m17700[0;39m [2m---[0;39m [2m[nio-8080-exec-7][0;39m [36m.w.s.m.s.DefaultHandlerExceptionResolver[0;39m [2m:[0;39m Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
This error message was shown on the white page :
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'POST' not supported
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
at org.springframework.web.servlet.support.WebContentGenerator.checkRequest(WebContentGenerator.java:381)
at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:536)
at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:53)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1060)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:962)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:113)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:113)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:113)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:712)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:459)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:384)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312)
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:171)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:316)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1393)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1138)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1077)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:962)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:888)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:832)
You are confusing #RequestBody and #RequestParam.
Your controller method needs a RequestBody object and not String parameters.
I've finally got it working with the POST method. I just added a "redirect:" to the return parameters of the controller to redirect to the required views and of course changed to the POST methods for the calling form and the controller. Here is my modified code below:
//login
#RequestMapping(value= "/login", method= RequestMethod.POST)
public String login(#RequestParam("txtUserName") String usrName, #RequestParam("txtPassword") String password) {
System.out.println("LOGIN UserName : " + usrName + " Password : " + password);
//Process the admin password - hardcoded
if(usrName.equals("admin") && password.equals("admin123"))
{ return "redirect:main.html"; }
else
{ return "redirect:invalid_login.html"; }
}
I am trying to return different error codes with HttpStatuses as response when invocation of my endpoint fails.
now I am testing endpoint definition:
#PostMapping("shredding_type/update")
public void updateShreddingType(
#RequestBody CdtUpdateReqDTO<ShredTypeGuiDTO> req
) throws IOException {
shreddingTypeCtrl.updateShreddingType(req.getCdt());
}
for DataIntegrityViolationException and my exception handler looks like:
#ControllerAdvice
public class ErrorHandlingAspect {
#ExceptionHandler(Exception.class)
#ResponseBody
private ResponseStatusException handleException(Exception ex) {
OperationCtx ctx = OpCtxHolder.getCurrReqCtx();
ctx.setStatusCode(400);
HttpStatus status = HttpStatus.BAD_REQUEST;
if ("static GUI".equals(ctx.getSystemName()))
status = createCodeForGUI(ex);
return new ResponseStatusException(status);
}
private HttpStatus createCodeForGUI(Exception ex) {
HttpStatus status = HttpStatus.BAD_REQUEST;
if (ex instanceof DataIntegrityViolationException)
status = HttpStatus.CONFLICT;
return status;
}
}
and I'm still getting HttpResponse of status code 500 in my angular app.
this is the stacktrace I get when violating that constrain:
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:112)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3174)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3688)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:90)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:50)
at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1414)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1500)
at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1537)
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1505)
at org.hibernate.query.Query.getResultList(Query.java:132)
at com.nws.vedica.dbs.dao.ShreddingTypeDAO.getAllTypes(ShreddingTypeDAO.java:51)
at com.nws.vedica.dbs.dao.ShreddingTypeDAO$$FastClassBySpringCGLIB$$460d869e.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
... 121 common frames omitted
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "shredding_type_shreddingtype_key"
Detail: Key (shreddingtype)=(N2) already exists.
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2433)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2178)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:306)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:155)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:132)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175)
... 139 common frames omitted
2019-10-25_12:05:35.473 WARN o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Failure in #ExceptionHandler private org.springframework.web.server.ResponseStatusException com.nws.vedica.aop.ErrorHandlingAspect.handleException(java.lang.Exception) sys$reqId: pYfaKFF; statusCode: 400; ip: 0:0:0:0:0:0:0:1; userId: static GUI; epUri: /api/KDMS/shredding_type/update; sys$systemName: static GUI
org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class java.lang.Throwable]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: org.springframework.web.server.ResponseStatusException["mostSpecificCause"])
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:293)
at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:103)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:290)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:180)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:119)
at org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver.doResolveHandlerMethodException(ExceptionHandlerExceptionResolver.java:408)
at org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver.doResolveException(AbstractHandlerMethodExceptionResolver.java:61)
at org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:139)
at org.springframework.web.servlet.handler.HandlerExceptionResolverComposite.resolveException(HandlerExceptionResolverComposite.java:79)
at org.springframework.web.servlet.DispatcherServlet.processHandlerException(DispatcherServlet.java:1297)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1109)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1055)
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:660)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:90)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:117)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:106)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
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)
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: org.springframework.web.server.ResponseStatusException["mostSpecificCause"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1191)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter._handleSelfReference(BeanPropertyWriter.java:944)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:721)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1396)
at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:913)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:287)
... 68 common frames omitted
notice the Failure in #ExceptionHandler private org.springframework.web.server.ResponseStatusException.. part. I think this is the reason why setting HttpStatus manually fails but can not figure why it is.
What can be wrong with this?
You're not actually changing the HTTP status code. You're just putting one into your ResponseStatusException. But that doesn't magically change the response code.
If you include a HttpServletResponse parameter, you can set the code with response.setStatus(400). If the code is always the same, you don't need the respose, and can annotate the handler method with #ResponseStatus(HttpStatus.BAD_REQUEST).
However in your case the correct response code is 500, since your server did something wrong (5XX codes) and not the client (4XX codes).
I'm using MySQL Ver 15.1 Distrib 10.1.38-MariaDB, for debian-linux-gnu (x86_64).
Open-JDK 1.8.0
Spring Boot 2.1.4 RELEASE
Accessing my application I got this stacktrace on my whitelable page:
This application has no explicit mapping for /error, so you are seeing
this as a fallback.
Mon May 27 16:12:06 AZOST 2019
There was an unexpected error (type=Internal Server Error, status=500).
No method or field with name 'id' on line 15
com.samskivert.mustache.MustacheException$Context: No method or field
with name 'id' on line 15
at com.samskivert.mustache.Template.checkForMissing(Template.java:326)
at com.samskivert.mustache.Template.getValue(Template.java:234)
at com.samskivert.mustache.Template.getValueOrDefault(Template.java:279)
at com.samskivert.mustache.Mustache$VariableSegment.execute(Mustache.java:802)
at com.samskivert.mustache.Mustache$BlockSegment.executeSegs(Mustache.java:845)
at com.samskivert.mustache.Mustache$SectionSegment.execute(Mustache.java:881)
at com.samskivert.mustache.Template.executeSegs(Template.java:157)
at com.samskivert.mustache.Template.execute(Template.java:134)
at org.springframework.boot.web.servlet.view.MustacheView.renderMergedTemplateModel(MustacheView.java:81)
at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:178)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:316)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1370)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1116)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1055)
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.doGet(FrameworkServlet.java:897)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
This is my code:
main.mustache
<html>
<body>
<div>
<form method="POST">
<input type ="text" name="text" placeholder="Введите сообщение" />
<input type ="text" name="tag" placeholder="Тег"/>
<button type="submit">Добавить</button>
</form>
</div>
<div>Message list</div>
{{#messages}}
<div>
<b>{{id}}</b>
<span>{{text}}</span>
<i>{{tag}}</i>
</div>
{{/messages}}
This is my Controller:
GreetingController
package com.example.sweater;
import com.example.sweater.domain.Message;
import com.example.sweater.repos.MessageRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Map;
#Controller
public class GreetingsController {
#Autowired
private MessageRepo messageRepo;
#RequestMapping("/greeting")
public String greeting(#RequestParam(name="name", required = false, defaultValue = "World") String name,
Map<String, Object> model)
{
model.put("name", name);
return "greeting";
}
#GetMapping
public String main(Map<String, Object> model){
Iterable<Message> messages = messageRepo.findAll();
model.put("messages", "messages");
return "main";
}
#PostMapping
public String add(#RequestParam String text, #RequestParam String tag, Map<String, Object> model){
Message message = new Message(text, tag);
messageRepo.save(message);
Iterable<Message> messages = messageRepo.findAll();
model.put("messages", messages);
return "main";
}
}
This is my project structure:
![ProjectStructure]: (https://lh3.googleusercontent.com/PKENYsmd29WxawAs-jMtrwBTBqDHNMoS3LWU_BTyDOjO7L5z8DrojsmB-pHfb03QE2Ce7Q3_xE4HrMk3PZax06Cd2b-NY42pB9e5DzCv-Uh6VlkbtebFb2W0HYq8u7WaG7WWU7uC7_7z5x8TXTXl65Wg-rMCes6HkQ8PTQ2_-QOMBW_I2yV8dXN2Xs2-vsHAWX5upPKw2oi3ZAtxOVvDKUm-znDD4czMIPAMKsDAfBXWWf5QbVpTysOEoE_rF7_7z9lWBf0ujZBYpllK5aXxsWB0OorsnnLb9XvmCMaGU-3xsOykLRFiq_LcYk5erFkEsBSkkobYT67ZPIPxrcnC3iGluBy5IYjDUrhwVpn-WPv76RsEID0qF0PYrAGO01M1Xb0QzhOJjx0wKsIKIDBRSEfxSRSLp-rGVW0rsDF_VIQeRXLs-Bvt45LznMXIBjCH_OLA3sg5p7RsgmiiRrjtsFhKmH-GOUds1GvrUTfpdpjlcySm_vpYK84WhyGfc64As45xB04w62mkD0LgZpw9pFcENbp8l9_MNhRlh0dLccB0Tku5H9h1-9H4FD3OzHYlw6SlsoNfYob_7BeZK3QXaTujtu1K7Hn-5zaxJ_oI4Ea_4P59BSmzAp6X_D6O0Rs9rZ8zPtSPNHiBzB6SP_vOuCfMuOAa8w=w340-h520-no)
I expected this code to display HTML code with empty fields waiting for me to fill in them, access the database and show all tuples which was typed into empty fields, but instead I ran into this stacktrace. What should i fix to make it work correctly?
From your stack trace it can be seen that you are passing messages to be iterated in the template :
There was an unexpected error (type=Internal Server Error, status=500).
No method or field with name 'id' on line 15
But the messages model being returned from the controller might be missing 'id' values . If we didn’t assign a value to a {{id}} on the Mustache’s page, the jmustache will throw the above error message.Can you please check if the data returned from the main method is returning correctly.Or mark the value as optional in the template.
If not check the following :
Ensure that you have configured mustache properly.Ensure that you have the following dependency added in pom :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mustache</artifactId>
</dependency>
Also ensure that all your dynamic html content is kept in the directory :
src/main/resources/templates/
folder so that spring will take it up.
I have an extension method that converts string to Date in Kotlin.
fun String.convertToDate() : Date {
var pattern: String = "dd-mm-yyyy"
val dateFormatter = SimpleDateFormat(pattern)
return dateFormatter.parse(this) // parse method throw ParseException
}
And this is the code where I am trying to catch possible exception.
try {
"22---2017".convertToDate()
} catch (ex: ParseException) {
// ParseException supposed to be caught in this block
logger.error("Parse exception occur")
} catch (ex: Exception) {
// ParseException caught in this block
logger.error("Exception occur")
}
The ParseException caught in the last block that is where Exception is caught. But should it be caught in the ParseException block ? What am I missing here ?
===UPDATE===
I am developing an Spring MVC project. I have run the code in simple stand alone kotlin program where it behaves accordingly. But in my spring project it behaves differently. I am giving the the full code, Controller and the Service layer.
Controller
#PostMapping
#PreAuthorize("hasAnyRole('USER','ROLE_USER','ROLE_ADMIN','ADMIN')")
fun postAttendance(#RequestBody attendanceJson: AttendanceJsonWrapper,
request: HttpServletRequest): ResponseEntity<*> {
val organization = getOrganizationFromSession(request)
try {
val attendanceBook: AttendanceBook = attendanceService.post(attendanceJson, organization.id!!)
logger.info("Post successfully attendance book {}", attendanceBook)
} catch (ex: SameDateAttendanceException) {
logger.error("Duplicate attendance entry found at date [{}]", attendanceJson.date, attendanceJson.classId)
return responseConflict(attendanceJson)
} catch (ex: java.text.ParseException) {
ex.printStackTrace()
logger.error("Parse exception occur")
return responseError(ErrorObject(
attendanceJson,
"date",
Constants.INVALID_DATE_FORMAT,
Constants.EXPECTED_DATE_FORMAT))
} catch (ex: Exception) {
ex.printStackTrace()
logger.error("Exception occur")
if (ex.cause is ParseException) {
logger.info("What the hell is happening")
}
return responseOK(attendanceJson)
}
Service
#Service
open class AttendanceService constructor(val attendanceRepository: AttendanceRepository) {
#Transactional
open fun post(attendanceJsonWrapper: AttendanceJsonWrapper, orgId: Long): AttendanceBook {
// ParseException should thrown from this line.
val _attendanceDate = attendanceJsonWrapper.date.convertToDate()
// Other logic goes here
return attendanceRepository.save(attendanceBook)
}
}
Log
for given input 28--2017 from front end following log produced.
2017-06-28 02:36:52.942 ERROR 4632 --- [nio-8080-exec-1] c.l.c.rest.AttendanceRestController : Exception occur
2017-06-28 02:52:32.485 INFO 2796 --- [io-8080-exec-10] c.l.c.rest.AttendanceRestController : What the hell is happening
Exception
java.lang.reflect.UndeclaredThrowableException
at com.lynas.service.AttendanceService$$EnhancerBySpringCGLIB$$7b42c004.post(<generated>)
at com.lynas.controller.rest.AttendanceRestController.postAttendance(AttendanceRestController.kt:34)
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:498)
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.doDispatch(DispatcherServlet.java:963)
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.doPost(FrameworkServlet.java:872)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:110)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:124)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
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)
Caused by: java.text.ParseException: Unparseable date: "28--2017"
at java.text.DateFormat.parse(DateFormat.java:366)
at com.lynas.util.UtilKt.convertToDate(Util.kt:56)
at com.lynas.service.AttendanceService.post(AttendanceService.kt:23)
at com.lynas.service.AttendanceService$$FastClassBySpringCGLIB$$2b941a4b.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
... 103 more
The UndeclaredThrowableException is caused by kotlin. why? we know kotlin does not have checked exceptions.
The documentation of UndeclaredThrowableException says:
Thrown by a method invocation on a proxy instance if its invocation handler's invoke method throws a checked exception
On the other hand, Kotlin can throw any exceptions but in java them will are: unchecked/checked exception and error.
we know almost all of the popular frameworks is created base on java.reflect package includes java.reflect.Proxy.
In short, when the kotlin function throw a java checked exception and don't declare the exception that it will maybe throwing.
then call a java Proxy you maybe receive such a UndeclaredThrowableException.
In java you can declare a checked-exception will be throwing as below:
// v--- it is a checked exception in java
int read() throws IOException{/**/}
Thanks for #glee8e to points my mistake.
you also can throws an exception in kotlin, since kotlin don't have throws keyword so you must using #Throws to declare an exception will be throwing:
#Throws(IOException::class)
fun read():Int{/**/}
let's reproduce the UndeclaredThrowableException in kotlin:
//throws a UndeclaredThrowableException takes the original IOException as its cause
// because java.lang.Runnable don't declare any checked exception at all
// |
// v
Runnable::class.proxying(::throwsAJavaCheckedException).run()
// throws the original IOException directly because java.util.concurrent.Callable
// has declared that it will be throwing a checked Exception
// |
// v
Callable::class.proxying(::throwsAJavaCheckedException).call()
fun throwsAJavaCheckedException(proxy:Any, method:Method, args:Array<Any>?): Any? {
throw IOException();
}
typealias Invocation = (Any, Method, Array<Any>?) -> Any?;
fun <T:Any> KClass<T>.proxying(handler:Invocation) = cast(Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(),
arrayOf(java),
handler
));
How to avoiding this problem?
If the function is wrote by yourself the solution is so simpler.
yes, declare the function will be throwing a checked exception. for example:
#Throws(ParseException::class)
fun convertToDate(){/**/}
OR write some gradle-plugin like as allopen, I named it allthrows here.
But you also can make some compromises. If you are not sure what will be happens in the frameworks like as spring,
you should wrap your invocation into a helper method. for example:
val task = Runnable::class.proxying(::throwsAJavaCheckedException)
// v-- the result return by catch-block immediately if no exception occurs
val result : Unit = catch(task::run).by { actual: Throwable ->
val exceptional: Unit = Unit;
// v--- you can choose return an exceptional value or rethrow the exception
when (actual) {
is RuntimeException -> exceptional
is ParseException -> logger.info(acutal)
else -> throw actual
}
}
val result : Unit? = catch(task::run).only { actual:Throwable ->
// only handle the exception don't return the exceptional value
logger.info(actual);
}
inline fun <T> catch(crossinline block: () -> T): () -> T {
return { block(); };
}
inline fun <T> (() -> T).by(exceptionally: (Throwable) -> T): T {
return only { exceptionally(it) }!!
}
inline fun <T : R, R> (() -> T).only(exceptionally: (Throwable) -> R): R? {
try {
return invoke();
} catch(e: UndeclaredThrowableException) {
return exceptionally(e.cause ?: e);
} catch(e: Exception) {
return exceptionally(e);
}
}
It seems that your service is running in a different invocation context than your controller. As the service is throwing the exception you cannot catch it in the controller; it looks like you're calling the service directly, but due to code injection you really aren't. So what happens is that the invocation context (usually a thread) ends with an exception. This gets translated into a UndeclaredThrowableException with the original exception as cause.
There are two ways of dealing with this:
catch the exception locally in the service where the exception is generated;
catch the UndeclaredThrowableException in a separate try/catch and then re-throw the cause.
The first option should be preferred but requires you to handle the exception in the service. The second one looks too much like a hack to me, but it doesn't require setting up the exception handling in the service instead of the controller.