How do I get the server-side exception message with GWT? - java

I tried
public void onFailure(Throwable caught) {
Throwable cause = caught.getCause();
String causeStr = (cause==null) ? "" : ", "+cause.getMessage();
errorLabel.setText(SERVER_ERROR + ": " + caught.getMessage() + causeStr);
But cause is always null and caught.getMessage() always equals the very generic 500 The call failed on the server; see server log for details. I want to throw IllegalArgumentExceptions from the server and be able to show it on the client:
throw new IllegalArgumentException("Email address is invalid.");

Your Exception needs to be Serializable to travel through the cables.
In addition, the best practice says: You should have two exception kinds:
SystemException: that is a fatal exception, the user can't recover (this should not be serializable since you will give the user a feedback of the type "an error occured on the server, please contact the administrator"
BusinessException: which is due to a misuse of your ammplication by the user (ex: UnauthorizedException, BadMailException or more generally InvalidvalueException)
This way you will write System exceptions in the logs and send back business exceptions to the user

You can use com.google.gwt.core.client.GWT.UncaughtExceptionHandler to catch the exception on the server, and then throw your own exception that
implements Serializable, and
is defined in a source folder that is acccessible to (and compiled for) the client.

You could also override the RequestFactoryServlet and pass it a custom exception handler::
public class CustomRequestFactoryServlet extends RequestFactoryServlet {
private static class ApplicationExceptionLogger implements ExceptionHandler {
private final Logger log = LoggerFactory.getLogger(ApplicationExceptionLogger.class);
#Override
public ServerFailure createServerFailure(Throwable throwable) {
log.error("Server Error", throwable);
return new ServerFailure(throwable.getMessage(), throwable.getClass().getName(), throwable.getStackTrace().toString(), true);
}
}
public CustomRequestFactoryServlet() {
super(new ApplicationExceptionLogger());
}
}
In web.xml ::
<servlet>
<servlet-name>requestFactoryServlet</servlet-name>
<servlet-class>com.myvdm.server.CustomRequestFactoryServlet</servlet-class>
</servlet>

I also found you can send back a Google UmbrellaException, but you have to instantiate it a little funny because it only takes Sets in the constructor:
Server
public String getUserId () throws Exception {
Set<Throwable> s = new HashSet<Throwable>(Arrays.asList(new IllegalArgumentException("Hidey hidey ho!")));
if (true) throw new com.google.gwt.event.shared.UmbrellaException(s);
Client
public void onFailure(Throwable caught) {
log.severe("fetchUserName(), Could not fetch username: " + caught.getMessage());
Console
Mon Oct 14 12:05:28 EDT 2013 com.example.client.Login
SEVERE: fetchUserName(), Could not fetch username: Exception caught: Hidey hidey ho!

I liked Zied's and Fred's answers the best as they are the simplest and most transparent. However, no need to use UncaughtExceptionHandler or create SystemExceptions, so it can be even simpler. Just capture exceptions as normal, re-wrap, and throw. No need to litter the server Interface with exceptions (just yours). Any serious errors like OutOfMemoryError will be handled by GWT as normal. Also simpler instantiation than my other answer. GWT already has pass/fail handlers with onSuccess/onFailure so no need to re-check for a failure within onSuccess with a special return value. However, the only way to reach onFailure is with an Exception, so even though a boolean might be sufficient, an Exception is required to indicate an error to the client handler.
MyException
package com.example.shared;
import java.io.Serializable;
public class MyException extends Exception implements Serializable {
private static final long serialVersionUID = 1104312904865934899L;
public MyException() {}
public MyException (String s) {
super(s);
}
}
Server
public void cancelSend() throws MyException {
throw new MyException("Because I said so");

Related

#ControllerAdvice doesn't handle more specific exception

There's a piece of code that throws a exception:
java.lang.RuntimeException: cn.dev33.satoken.exception.NotLoginException: Invalid Token:ldxutBDDKBEDa9LjWNTKLFbW7g7B86qU.
And then it goes into handleRuntimeException rather than returnNotLoginException method.
#Component
#Slf4j
#Primary
public class MyLockKeyBuilder extends DefaultLockKeyBuilder {
#Override
public String buildKey(MethodInvocation invocation, String[] definitionKeys) {
String key = super.buildKey(invocation, definitionKeys);
Object loginId = StpUtil.getLoginId(); // throw a exception
key = loginId.toString();
return key;
}
}
#ControllerAdvice(basePackages = "com.test")
#Slf4j
public class GraceExceptionHandlerApp {
#ResponseStatus(HttpStatus.UNAUTHORIZED)
#ExceptionHandler(value = NotLoginException.class)
#ResponseBody
public JSONObject returnNotLoginException(NotLoginException e) {
e.printStackTrace();
String message = e.getMessage();
ResponseStatusEnum failed = ResponseStatusEnum.UNAUTHORIZED;
failed.setMsg(message);
return ZheliResult.exception(failed);
}
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(RuntimeException.class)
#ResponseBody
public JSONObject handleRuntimeException(RuntimeException e, HttpServletRequest request)
{
String requestURI = request.getRequestURI();
return ZheliResult.errorCustom(ResponseStatusEnum.FAILED);
}
...
}
I want it goes into the returnNotLoginException method, could anyone tell me how to do it?
UPDATE
I've made a mistake, really, for I didn't offer enough info.
Missed Info:
My application was a distributed system and services to invoke another via rpc communication. MyLockKeyBuilder was on the provider service, and GraceExceptionHandlerApp was on the comsumer service.
When the provider service throw a exception and before it being passed to the comsumer sevice, it would be filter by a Filter called ExceptionFilter, which wrap the exception that the comsumer side doesn't recognize to RuntimeException, to avoid serialization issue.
Finally I solved this problem by rewritting the ExceptionFilter class to allow original NotLoginException to be passed to the consumer side.
NotLoginException is the inner exception of your RuntimeException. If you want your controller advice to handle it, catch the RuntimeException buildKey and throw its inner exception.
Based on your question,
java.lang.RuntimeException: cn.dev33.satoken.exception.NotLoginException: Invalid Token:
Your exception type is java.lang.RuntimeException & cause of exception is NotLoginException.
Controller advice will invoke respective method when type of exception matches & not cause of exception.
So if you really want to invoke returnNotLoginException, then you need to throw NotLoginException in your logic instead of throwing RuntimeException.
Something like:
..
throw new NotLoginException("exception"); //in your StpUtil.getLoginId();
..

How to return http status code for exceptions in rest services

In my application I have different layers like the rest layer, service layer and DB layer, according to business scenarios I am trowing different business exceptions from the service layer.
But now, I have to set different HTTP codes like 400, 403, 409, 412.. to REST responses.
How can I set different HTTP status codes based on different scenarios?
Which is the most feasible way like: aspect, exception mapper, or ....?
Since I can set HTTP status only once in rest layer (
referred this ), I am not able to map to different HTTP codes because my exception is from service layer.
My exception class looks like this:
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 1L;
public BusinessException(ErrorEnumeration error) {
}
public BusinessException(Exception e, ErrorEnumeration error) {
}
}
and the exception will be thrown from the service like this:
throw new BusinessException(ErrorEnumeration.VALIDATION_FAILED);
Please help by suggesting a solution
You can use exceptions defined in jax-rs or you can use your own exceptions. Fist catch your business exceptions and convert them to jax-rs versions. For example, for 404 you can throw javax.ws.rs.NotFoundException.
You can also write your own exceptions by extending them from javax.ws.rs.ClientErrorException
Here is an example for 409-Conflict status exception
import javax.ws.rs.ClientErrorException;
import javax.ws.rs.core.Response;
public class ConflictException extends ClientErrorException{
public ConflictException(Response.Status status) {
super(Response.Status.CONFLICT); // 409
}
}
Update
Most simple and feasible way is catching your business exceptions and re-throw them with jax-rs exceptions.
try{
businessService.executeBusinessRule();
}catch (BusinessException e){
// It is better if your BusinessException has some child class to handle
if(e.getError() == ErrorEnumeration.VALIDATION_FAILED){
throw new BadRequestException();
}else{
throw new ConflictException();
}
}
If you are using spring you can always catch these exceptions using aop.
#Aspect
public class BusinessExceptionInterceptor{
#AfterThrowing(pointcut = "execution(* com.your.service.packge..* (..))", throwing = "e")
public void errorInterceptor(BusinessException e) {
// re-throw again...
}
Update 2
Also it is better to define a new exception instead of reusing same exception with different state. You can define a new ValidationException which extends from BusinessException like this.
public class ValidationException extends BusinessException{
public ValidationException() {
super(ErrorEnumeration.VALIDATION_FAILED);
}
}
By using this way you can still handle all the BusinessException but it is easier to identify or map them to Jax-rs exceptions.

auto log java exceptions

I have written a huge Web-Application and 'forgot' to include logging (I only print the errors with the standard e.printStackTrace() method).
My question is, if there is any method to auto-log (getLogger.LOG(SEVERE,"...")) any thrown exception?
maybe with a custom exception-factory like in exceptionFactory JSF?
I want to log every thrown exception with my logger, e.g. before the program enters the catch-block, the exception has to be logged already:
try{
...
} catch(Exception1 e){
//Exception must have been already logged here (without adding getLogger().LOG(...) every time)
System.out.println(e.printStackTrace());
} catch(Exception2 e){
//Exception must have been already logged here (without adding getLogger().LOG(...) every time)
System.out.println(e.printStackTrace());
}
Take a look at aspect oriented programming which can insert logging code at runtime for your favorite logging framework. The JDK includes the java.lang.instrument package which can insert bytecodes during classloading to perform your logging.
Otherwise, you can install a servlet Filter as the top most filter in the call chain which will catch most of your exceptions.
public class LogFilter implements javax.servlet.Filter {
private static final String CLASS_NAME = LogFilter.class.getName();
private static final Logger logger = Logger.getLogger(CLASS_NAME);
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
logger.entering(CLASS_NAME, "doFilter", new Object[]{request, response});
try {
chain.doFilter(request, response);
} catch (IOException | ServletException | RuntimeException | Error ioe) {
logger.log(Level.SEVERE, "", ioe);
throw ioe; //Keep forwarding.
} catch (Throwable t) {
logger.log(Level.SEVERE, "", t);
throw new ServletException(t);
}
logger.exiting(CLASS_NAME, "doFilter");
}
#Override
public void destroy() {
}
}
You can set uncaught exception handler for main thread and every other you create using Thread.setUncaughtExceptionHandler() method and do all the required logging there.
I am now also in front of new larger project and interested in elimination of not necessary code to be produced. First I wanted to log every entry and exit from method including input and output data. In my case of event driven architecture I am pushing these data to elastic and analyse continuously method processing timeouts, that is lot of code lines. So I handled this with AspectJ. Very nice example of this is here:
http://www.baeldung.com/spring-performance-logging
Same applies for auto Error logging, here is dummy example which I will extend to work with slf4j, but these are details:
public aspect ExceptionLoggingAspect {
private Log log = LogFactory.getLog(this.getClass());
private Map loggedThrowables = new WeakHashMap();
public pointcut scope(): within(nl.boplicity..*);
after() throwing(Throwable t): scope() {
logThrowable(t, thisJoinPointStaticPart,
thisEnclosingJoinPointStaticPart);
}
before (Throwable t): handler(Exception+) && args(t) && scope() {
logThrowable(t, thisJoinPointStaticPart,
thisEnclosingJoinPointStaticPart);
}
protected synchronized void logThrowable(Throwable t, StaticPart location,
StaticPart enclosing) {
if (!loggedThrowables.containsKey(t)) {
loggedThrowables.put(t, null);
Signature signature = location.getSignature();
String source = signature.getDeclaringTypeName() + ":" +
(enclosing.getSourceLocation().getLine());
log.error("(a) " + source + " - " + t.toString(), t);
}
}
}
I would be happy to hear what else is good example of boiler plate code reduction. I of course use Loombok which does superior task...
NOTE: do not reinvent wheel, so look here as other people collected usefull AOP to be reused in your project out of the box :-)) open source is great community: https://github.com/jcabi/jcabi-aspects

EJBProcessor exception handling

I have a JBOSS ESB that uses a standard out of the box EJBProcessor action. How do I get hold of an exception, if the exception be thrown in the method call that was run in the EJB?
Any advice would be helpful.
You can subclass EJBProcessor and override the process method like this:
#Override
public Message process(Message pMessage) {
try {
pMessage = super.process(pMessage);
} catch (Throwable wEx) {
handleProcessError(pMessage, wEx);
}
return pMessage;
}
You will more than likely catch an instance of ActionProcessingException, and you can look at the cause to see the exception in your EJB.
Your action configuration in your jboss-esb.xml will remain exactly the same, except you will substitute the name of your subclass for org.jboss.soa.esb.actions.EJBProcessor.

Throwing and logging Exceptions, a better way

Ultimately, i'd like to
if (badThingsHappen) {
log the issue
throw exception with description
}
The obvious redundancy here is that often exception description and the message to be logged is (often) the same.
This looks needlessly verbose
if (badThingsHappen) {
logger.error("oh no! not again!");
throw new AppException("oh no! not again!");
}
Declaring temporary String feels wrong
if (badThingsHappen) {
String m = "oh no! not again!";
logger.error(m);
throw new AppException(m);
}
Is it ok to have Exception's constructor handle the logging? Is there a better (cleaner) way?
You could use a utility method:
public class AppException extends Exception {
public static AppException logAndThrow(Logger logger, String message) throws AppException {
AppException e = new AppException(message);
// log the stack trace as well
logger.error(message, e);
throw e;
}
}
and the use it:
if (badThingsHappen) {
AppException.logAndThrow(logger, "oh no! not again!");
}
I usually prefer to log exceptions when I catch them, rather then when I throw them.
This cleans up the logs quite a bit more, and also lets the "client" code handle the exception and information output much more precisely, since the information you want to associate with the exception when logging can be dependent of context.
If you do want to log as soon as it happens, I would build the exception and log it before throwing, something like:
if(badthingshappen){
Exception e = new Exception("holy $%##");
logger.log(e);
throw e;
}
A bit verbose yes... but this is java.
Typically when working with Exceptions and logging requirements I include logging support in the Exceptions.
Exceptions typically inherit from a Base Exception class in our project and it has hooks for logging log4j or other logging utilities.
class Problem extends java.lang.Exception {
private boolean debug=false;
public Problem(String message) {
if(debug) {
logging.exception(message);
/* Maybe a stack trace? */
}
}
}
I just wrote an error-logging method myself, today (this is used to log errors if they occur in a listener method, so it's also logging the method in which the error occurred and the object in which the listener is implemented to help tracking):
protected void listenerError(String listenerMethodName, Object listener,
RuntimeException e) {
logger.error("Exception while calling " + listenerMethodName
+ " on object " + listener, e);
throw e;
}
I wrote it in the class in question (or the base class, to be exact), because you probably want to use the logger in that class (and all subclasses). Another option would be to create a utility method in a utility class (I would not write an Exception class for it), and provide the logger as parameter:
class ExceptionUtil {
public static error(Exception e, Logger logger) {
logger.error(e);
throw e;
}
}
You can, of course, provide the method and object as params for this method (or an overloaded version of it), as necessary.

Categories

Resources