简体   繁体   中英

Is it possible to throw a custom Exception without stack trace?

In my application I user AngularJS as front end and Java as backend. Whenever I need to show a custom error in front end panel, I throw from Java using Custom Exception and in Angular I will get this as a response and build message using javascript. This Custom Exception is a common one and so, in the server log, the whole stack trace is being captured. I am in a situation where throw should be there, and the stack trace should not print. I THOUGHT OF CATCH. But, after throwing, it continues the transaction when it needs to actually stop after throw. There is much complex code that I am pasting only the necessary once needed.

 List<GenericException> failedValidations = new ArrayList<>();
 if (CollectionUtils.isNotEmpty(failedValidations)) {
        String failedValidationErrorCode = Util.convertListToString(failedValidations.stream().map(GenericException::getCode).collect(Collectors.toList()));
        throw new ReservationException("Exception thrown with error codes :"+ failedValidationErrorCode, failedValidations);
    }

Now, when this error is thrown,

com.abc.def.exceptions.ReservationException: Exception thrown with error codes :5965
at com.abc.def.service.impl.ReservationImpl.validateStepOne(ReservationImpl.java:1038)
at com.abc.def.service.impl.ReservationImpl.validateStepOne(ReservationImpl.java:3226)
at sun.reflect.GeneratedMethodAccessor7611.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at com.sun.proxy.$Proxy1629.validateStepOne(Unknown Source)
at com.abc.def.controller.ReservationController.validateStepOne(ReservationController.java:605)
at sun.reflect.GeneratedMethodAccessor7610.invoke(Unknown Source)
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:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:817)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:731)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:968)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:870)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:751)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:844)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:844)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:280)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:254)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:136)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:346)
at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:25)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
at weblogic.websocket.tyrus.TyrusServletFilter.doFilter(TyrusServletFilter.java:215)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
at weblogicx.servlet.gzip.filter.GZIPFilter.doFilter(GZIPFilter.java:70)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
at com.abc.def.config.InboxFilter.doFilter(InboxFilter.java:42)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:316)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
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:330)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at com.abc.def.config.CorsFilter.doFilter(CorsFilter.java:38)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
at com.abc.def.config.PFCLoginFilter.doFilter(PFCLoginFilter.java:132)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3456)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3422)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:323)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
at weblogic.servlet.provider.WlsSubjectHandle.run(WlsSubjectHandle.java:57)
at weblogic.servlet.internal.WebAppServletContext.doSecuredExecute(WebAppServletContext.java:2280)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2196)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2174)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1632)
at weblogic.servlet.provider.ContainerSupportProviderImpl$WlsRequestExecutor.run(ContainerSupportProviderImpl.java:256)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:311)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:263)> 

Consider this one printing for 1000 times for a day in server log. All I need is the first line alone to print in the server log. that is,

 com.abc.def.exceptions.ReservationException: Exception thrown with error codes :5965

If only the error codes were there, it is more than enough for debugging. I know this was a long question, please help me through this.

You're already using spring mvc (see your stack trace that contains spring mvc classes)

If so, probably the best option would be catching the exception at the level of Contoller Advice or any other exception handling mechanism supported by spring MVC .

Basically the stack trace is printed by spring mvc engine itself only if no-one (controller, advice or maybe service) has caught it.

From the angular standpoint there is no such a thing as an exception though. Instead you get a non 200 status with some default JSON this is a response in HTTP format, not an exception but just a response of some specific type. So I believe the best would be to establish some protocol of for messages that come to the client side and clearly the server stack trace is not something to be sent to client.

This is a kind of convention that may include:

  1. HTTP status (non 200 to differentiate between errors and regular answers)
  2. JSONmessage in a predefined format with:
  • Exception ID
  • Time on server
  • Message
  • Parameters to be mapped on client
  • I18n related information if its relevant for your application.

Long story short:

  • You create a controller advice and map the custom exception there
  • The mapping method will create a "protocol" json and return it to angular.
  • This mapping method will be called by spring automatically if no-one has caught the exception before.
  • Since the mapping method will handle the exception, it won't be printed on console of the server which is kind of what you're trying to achieve.
  • The client will get the json and will create some "infrastructure" code in angular that handles all the messages (maybe shows the message at the top of the screen, popup whatever).

You could replace the stacktrace with an empty array.

public ReservationException(String message, List<GenericException> failedValidations) {
    super(message);
    this.setStackTrace(new StackTraceElement[0]);

    // Alternative: Keep the method where the exception was thrown.
 // this.setStackTrace(Arrays.copyOf(this.getStackTrace(), 1)); 
}

will only print

com.abc.def.exceptions.ReservationException: Exception thrown with error codes :5965

when Throwable::printStackTrace() is called.

But it is definitely better to configure your logger or spring to not print the stacktrace, as Mark Bramnik suggested since you loose valuable information for troubleshooting by removing the stacktrace.

Try creating a custom exception handler, you can decide what should be logged after a specified exception is thrown.

https://www.baeldung.com/exception-handling-for-rest-with-spring

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM