A JavaScript Evaluator

Let's implement a controller that has more than one possible cause for problems, and do so without cluttering the business logic:

@RestController
public class JavaScriptController {
@Value
private static class Message {
private String message;
}

// […]
Object eval = javaScript.eval(expression);
return new Message("Evaluation of " + expression +
" yields " + eval);
}
}

Go to https://bit.ly/2x9HZWM to access the complete code for this section.

The controller accepts a JavaScript expression as a parameter and returns the result as a JSON wrapped message. It contains a bit of argument checking before feeding the parameter straight into the built-in JavaScript interpreter. Note that you do not want to do this outside a protected environment because of security implications, but it is fine as an example.

Now, what could possibly go wrong?

One thing is the IllegalArgumentException that we throw ourselves, and the other is the checked ScriptException and another unchecked ParserException that Nashorn may throw. The error handling that we have in place right now only replaces one exception with a more informative one. The exceptions will escape our handler mapping. What will Spring do about it? The answer is that, by default, it will generate a rather helpful error object and a response status code of 500 Internal Server Error.

That is not quite satisfying, since the error really was on the client's side, and we should properly signal that to the client. To handle the two exceptions, we add two error handlers to the class:

@RestController
public class JavaScriptController {
// handle the explicitly thrown runtime exception
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String handleArgument(IllegalArgumentException e) {
return e.getMessage();
}

// handle the parser's exceptions
@ExceptionHandler({ParserException.class, ScriptException.
class})
@ResponseStatus(HttpStatus.NOT_ACCEPTABLE)
public String handleParse(Exception e) {
return e.getMessage();
}
}

The handleArgument() method handles the IllegalArgumentException, while handleParse() handles the two Nashorn exceptions. The exception argument is entirely optional and can have any compatible type. Again, the signatures are very flexible, and we could choose to return a ResponseEntity<> for a specialized error object instead.