Have a service method which can throw an exception
if (NOT_FOUND) {
throw new ResourceNotFoundException("Resource not found");
}
And ControllerAdvice with exceptionHandler
#ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity handleResourceNotFound(Exception ex) {
return new ResponseEntity("your-error-message");
}
So i need to pass another String as param and access it form exceptionHanlder:
if (NOT_FOUND) {
String param2 = "param2";
throw new ResourceNotFoundException("Recource not found", param2);
}
#ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<Problem> handleResourceNotFound(Exception ex) {
doomething(param2);
return new ResponseEntity({your-error-message});
}
Is there any way to do it?
Yes, as Abra said, you can create your own exception that inherits from ResourceNotFoundException, and add the other parameter there. Then in the exception handler you can get it from the exception:
This could be the class
public class CustomException extends ResourceNotFoundException {
private String otherParam;
public CustomException(String message, String otherParam) {
super(message);
this.otherParam = otherParam
{
public getOtherParam() {
return otherParam;
}
}
Then you throw it
throw new CustomException("Recource not found", param2);
Then in exception handler you can get the second param
#ExceptionHandler(CustomException.class)
public ResponseEntity<Problem> handleResourceNotFound(CustomException ex) {
doomething(ex.getOtherParam());
return new ResponseEntity(ex.getMessage());
}
i refer to the error handle tutorial (chapter 6.3) , where you see an proper usage of the Exception Handler as you did in your code snippet.
there is an interesing aspect of your approach:
Of course, we'll use the global exception handling mechanism that we discussed earlier to handle the AccessDeniedException as well:
so the purpose of your Exception Handler is to handle Exceptions of a vast variety of exceptions: global exception handling. You would not know where the exception was thrown. Therefor it makes no sense to add additional logic to your Exception handler on the Handler side.
rather than adding a backpack to the handler you should take the action on the point of existing. that would take a small archituetur change and handle there:
if (NOT_FOUND) {
String param2 = "param2";
doomething(param2);
throw new ResourceNotFoundException("Recource not found");
}
clean code - separation of concerns
if it was a general aspect of exception handling, you would have the general informatiaon already in your hands
if it is a specific aspect, then it should be handled where it happens!
Just update your advice:
#ExceptionHandler(ResourceNotFoundException.class)
// public ResponseEntity handleResourceNotFound(Exception ex) {
public ResponseEntity handleResourceNotFound(ResourceNotFoundException ex) {
// ex contains all parameters that you need
return new ResponseEntity("your-error-message");
}
Related
I have a generic function which does something and, in case of failure, it should throw a specific exception.
To simplify you can imagine it as such:
public static <E extends Exception> void doSomething(Class<E> exceptionClass) throws E {
try {
//Do stuff
} catch (Exception e) {
String message = "...";
//-> here I want to throw a new exception of type E with the message I built above and the caught exception as cause
}
}
In order to do that, what I can think about is to build a new E by reflection and throw an unchecked exception if any of the exceptions that can be thrown during reflection is actually thrown:
public static <E extends Exception> buildException(Class<E> exceptionClass, String msg, Throwable cause) {
try {
return exceptionClass.getDeclaredConstructor(String.class, Throwable.class).newInstance(msg, cause);
} catch (NoSuchMethodException ... e) {
//Catch everything that can be thrown
throw new RuntimeException(e);
}
}
... and then call it simply throw buildException(exceptionClass, message, e) inside the main function.
However I don't like too much this solution because I need to get the class in parameter from the caller (while they are already inferring me the type via E) and I may as well have to throw a Runtime exception if my reflection operation fails (all E extends Exception so the constructor I look for should always be there, but we never know if the caller doesn't customize the exception too much...)
Although the drawbacks, I can't get anything better into my mind.
Does anyone have some better design ideas for this?
Note: about the need. I have several classes which perform the same operation (the "do stuff") but that need to throw a specific exception (class 1 throws exception 1, class 2 throws exception 2 etc.) which wraps any possible exception thrown while performing the "do stuff" operation. Of course I may move the catch on caller side but that would make a lot of code duplication for the exact same operation.
Instead of passing the class and let the called method handle the exception creation you could let the calling method handle it instead. This is possible by accepting a function:
public static <E extends Exception> void doSomething(Function<String, E> exceptionFunction) throws E {
try {
//Do stuff
} catch (Exception e) {
String message = "...";
throw exceptionFunction.apply(message);
}
}
This function would expect a String, your message, and will then return an instance of the exception to be thrown. As you can see, you can trigger the function by using exceptionFunction.apply(message).
You can also use e to add the "cause" stacktrace:
public static <E extends Exception> void doSomething(Function<String, E> exceptionFunction) throws E {
try {
//Do stuff
} catch (Exception e) {
String message = "...";
var exception = exceptionFunction.apply(message);
exception.initCause(e);
throw exception;
}
}
The call of the doSomething method would then look like this:
doSomething((s) -> new MyException());
or if you prefer method references, like this:
doSomething(MyException::new);
(mind that MyException would need a constructor with a String parameter)
I have the following Java method:
public Class createClass(Class class) {
try {
// retrieve the professor of the class and check if he exists
Professor professorFound = professorRepository.findById(class.getProfessorId());
if (professorFound != null) {
// if the professor exists, then check if he already has a class
// with the same id
List<Class> classes = professorFound.getClasses();
List<Class> classFound = classes.stream().... // loop to find the class...
// if he has, throw an exception
if(!classFound.isEmpty()) {
throw new ClassAlreadyRegisteredException();
} else {
// if he does not have, then create the class
Class class = new Class();
professorFound.getClasses().add(class);
return professorRepository.save(professorFound);
}
} else {
// if the professor does not exist, throw an exception
throw new ProfessorNotFoundException();
} catch (Exception e) {
// if there is any other error during the communication with the database,
// throw a generic IOException
throw new ClassIOException();
}
}
Basically, what I need is to throw specific Exceptions (if the professor informed in the request does not exist, or if the professor already has a class with the same id), or throw a generic IOException if there is any other error during the communication with the database.
However, in the way that I have developed, if any specific Exception is thrown, the try block will catch the exception and will throw a generic IOException.
How can I solve this problem?
I'm very interested in understanding what are the best practices in this case.
Should I catch each specific exception separately and throw them twice?
Is that a good practice?
EDIT:
This is how my ClassAlreadyRegisteredException looks like:
public class ClassAlreadyRegisteredException extends ApiException {
private static final long serialVersionUID = 1L;
public ClassAlreadyRegisteredException(String code, String message, String developerMessage, String origin, HttpStatus status) {
super(code,message,developerMessage,origin, status);
}
}
This is how my ApiException looks like:
#Data
#AllArgsConstructor
#RequiredArgsConstructor
#EqualsAndHashCode(callSuper = false)
public class ApiException extends RuntimeException{
private static final long serialVersionUID = 1L;
private String code;
private String userMessage;
private String developerMessage;
private String origin;
private HttpStatus status;
}
Thanks in advance.
Catch and re-throw.
try {
... same as before ...
} catch (ClassAlreadyRegisteredException | ProfessorNotFoundException e) {
throw e;
} catch (Exception e) {
// if there is any other error during the communication with the database,
// throw a generic IOException
throw new ClassIOException();
}
Alternatively, remember the exception to throw it later.
Exception fail = null;
try {
….
// save exception in place of existing throws
// for example:
fail = new ClassAlreadyRegisteredException();
…
} catch (Exception ex) {
...same as original...
}
if (fail != null) {
throw fail;
}
I use both techniques; the choice depends on what is simpler in any given situation. Neither is uncontestably better.
For the catch and re-throw method, you have to keep the list of caught-and-rethrown exceptions consistent with the exceptions you actually throw from within the try-clause. In larger cases, I'd avoid that problem by using an exception hierarchy, so I could catch the common base class.
For the save-and-throw method, you have to arrange control flow so that nothing significant is done after detecting the failure, since you don't have the immediate 'throw' command to exit the try-clause. Nevertheless there are cases where it is simple enough; the original example is one such.
Checked vs Unchecked Exceptions
It's totally acceptable to throw an exception in a catch block. A common use case is to take a checked Exception and throw a unchecked RuntimeException which would allow the exception bubble up to where it needs to be handled.
You'll want to use checked exceptions for use cases such as Connectivity/IO, SQL exceptions..
Handling Checked Exceptions
To answer your question, in most libraries that connect to the database, an checked IOException is thrown if there are any connectivity issues. For these cases, you can always specify this in the method signature public Class createClass() throws IOException
this specifies that any callers of createClass() has to fulfill the contract that the IOException is handled.
or
You can rethrow this as a RuntimeException
try {
...
} catch (IOException e) {
throw new RuntimeException(e); // <- send the original exception so you can preserve the exception and stacktrace.
}
This will essentially bubble up to STDOUT or whatever handler your framework specifies.
CAUTION:
However, catching an cover all Exception and throwing a more specific ClassIOException can have unintended consequences.
If you have a NullPointerException this will be captured by your catch (Exception e) block and rethrown as a ClassIOException
Doing this will corrupt the stacktrace and cause your error logs to be much more difficult to debug.
Understanding what constitutes an checked Exceptions.
Another tip is to consider what your Exception cases are.
If they are standard flow of the application, service, or business logic -- these may not be appropriate exceptions.
The ClassAlreadyRegisteredException and ProfessorNotFoundException may not be exceptional cases in your application... unless these are already specified by your professor.
Sometimes these can be thrown as RuntimeException if the situation calls for it.
Best Practices?
There are still many opinions on how exceptions are handled. So here are some rule of thumb questions I ask myself when working with exceptions
Is the stacktrace preserved? Will I be able to trace back to the root Exception
Is this common logic and represents an exceptional case that deviates from what my application provides?
If I throw this exception, is it an absolute necessity for anything calling this method to handle this exceptional logic?
We were using the Hystrix functionality by directly extending the HystrixCommand class. But for some of the business exceptions, Hystrix's fallback method is being triggered.
I don't want to trigger the Hystrix fallback for some of the business specific exceptions. How I can achieve it without annotation based?
Use the ignoreExceptions annotation param
#HystrixCommand(ignoreExceptions = { BaseException.class, MissingServletRequestParameterException.class, TypeMismatchException.class })
See https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-javanica#error-propagation
I see you are extending the HystrixCommand instead of using the annotation, but that doesn't matter, just set that property in the command and it should have the same effect.
Unfortunately, a Hystrix Command is created by a Builder pattern, so you will have to do some hacking. The ignoreExceptions was added to DefaultProperties.java, which is used in the HystrixCommandBuilder
If you wrap your logic in a try/catch and re-throw any exceptions in a HystrixBadRequestException then it will not trigger the fallback.
#Override
protected Object run() throws Exception {
try {
return //call goes here
}
catch (Throwable e) {
//We wrap any exceptions in a HystrixBadRequestException because this way any other errors will not
//trip the short circuit
throw new HystrixBadRequestException("Exception thrown hystrix call", e);
}
}
From the docs:
http://netflix.github.io/Hystrix/javadoc/com/netflix/hystrix/exception/HystrixBadRequestException.html
An exception representing an error with provided arguments or state rather than an execution failure.
Unlike all other exceptions thrown by a HystrixCommand this will not trigger fallback, not count against failure metrics and thus not trigger the circuit breaker.
NOTE: This should only be used when an error is due to user input such as IllegalArgumentException otherwise it defeats the purpose of fault-tolerance and fallback behavior.
Two ways to do this.
Using HystrixCommand annotation and specifying the exception types.
#HystrixCommand(ignoreExceptions = { HttpStatusCodeException.class, JsonMappingException.class })
Using "HystrixBadRequestException" and customize your code in way to just ignore few exception cases or status codes. This implementation will check for specific error codes on exceptions expected with you backend API contract and does not invoke hystrix fallback. Throwing "HystrixBadRequestException" will not count as hystrix fault.
#HystrixCommand(commandKey = "MyHystrixCommand", fallbackMethod = "myHystrixFallback", threadPoolKey = "ThreadPoolKey")
public ResponseEntity<String> getServiceCallResponse(String serviceUrl, HttpEntity<?> entity) {
ResponseEntity<String> resp = null;
try {
resp = restTemplate.exchange(serviceUrl, HttpMethod.POST, entity, String.class)
.getBody();
}
catch(Exception e) {
handleExceptionForHystrix("getServiceCallResponse", e);
}
return resp;
}
private void handleExceptionForHystrix(String function, Exception e) {
if (e instanceof HttpStatusCodeException) {
HttpStatus httpStatusCode = ((HttpStatusCodeException)e).getStatusCode();
if(httpStatusCode.equals(HttpStatus.BAD_REQUEST) || httpStatusCode.equals(HttpStatus.INTERNAL_SERVER_ERROR)) {
throw new HystrixBadRequestException("Hystrix Bad Request Exception Occurred" + httpStatusCode, e);
}
throw new RuntimeException(function, e);
}
throw new RuntimeException(function, e);
}
public ResponseEntity<String> myHystrixFallback(String serviceUrl, HttpEntity<?> entity, Throwable hystrixCommandExp) {
return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
}
I am using GAE for my backend. I would like to set something like "default exception" for each Cloud Endpoint method. In other words if the method throws some Exception I don't expect (this Exception is not listed in method signature in throws), the thrown Exception can contain some information about my database ... This information can be exploited by an attacker. This issue is also known as "Improper error handling" listed in OWASP 10 [1]. Therefore I would like to catch such Exceptions and throw a default custom Exception instead of it.
In practice:
This code is a possible "hard coded" solution for my problem. But it's too much writing for many cloud endpoint methods. So I am asking if there is some pattern, or some setting in some .xml of GAE which solves my problem in a simpler way.
public User insertUser(User user) throws ExceptionA, ExceptionB, ExceptionC, DefaultException
//I am expecting that insertUser can throw ExceptionA, ExceptionB, ExceptionC
{
try {
}
catch (ExceptionA e1) {
throw new ExceptionA(e1.getMessage());
}
catch (ExceptionB e2) {
throw new ExceptionB(e2.getMessage());
}
catch (ExceptionC e3) {
throw new ExceptionC(e2.getMessage());
}
catch (Exception e4) {
/*This Exception can contain some exploitable information*/
throw new DefaultException("Something went wrong");
}
finally {
}
return user;
}
After some time and with some new knowledge I am returning to my question.
This is possible using the Spring MVC exception handling.
Following the tutorial I can create a GlobalExceptionHandler, which enables to return the concrete HTTP value in case an exception is thrown in some of the endpoint methods.
#ControllerAdvice
class GlobalControllerExceptionHandler {
#ResponseStatus(corresponding HTTP return value)
#ExceptionHandler(SomeException.class)
public void handleException() {
// Nothing to do
}
}
I want to set a custom exception message. However, I'm unsure of how to do this. Will I need to create a custom exception class or is there an easier way of doing this?
Most standard exception classes provide a constructor that takes a mesage, for example:
public UnsupportedOperationException(String message) {
super(message);
}
The above class simply calls its parent's constructor, which calls its parent's constructor, and so on, ultimately culminating in:
public Throwable(String message) {
...
}
If you create your own exception class, I think it's a good idea to following this convention.
You can only set the message at the creation of the exception. Here is an example if you want to set it after the creation.
public class BusinessException extends RuntimeException{
private Collection<String> messages;
public BusinessException(String msg){
super(msg);
}
public BusinessException(String msg, Exception cause){
super(msg, cause);
}
public BusinessException(Collection<String> messages){
super();
this.messages= messages;
}
public BusinessException (Collection<String> messages, Exception cause){
super(cause);
this.messages= messages;
}
#Override
public String getMessage(){
String msg;
if(this.messages!=null && !this.messages.isEmpty()){
msg="[";
for(String message : this.messages){
msg+=message+",";
}
msg= StringUtils.removeEnd(msg, ",")+"]";
}else msg= super.getMessage();
return msg;
}
}
Well, if the API offers an exception that suits your needs (IllegalArgumentException for example), just use it and pass your message in the constructor.
The best approach is to wrap the exception.
try {
my code that throws E;
} catch (final E e) {
throw new MyE("my message", e);
}
The Exception class (its parent, actually - Throwable) takes a message as an argument in its constructor:
throw new Exception("message") or Exception("message", innerException);
The root Exception class accepts a String custom message, as do (as far as I can tell) all of derivative classes.
So: no, you don't need to create a custom class. One of the existing exceptions probably covers your case (read their descriptions to find out which). If none of those are really satisfactory, then you can create an extension of Exception (or RuntimeException, etc.) and maintain the custom message constructor.
Try this code:
try{
throw new Exception("Test String");
}
catch(Exception ex){
System.out.println(ex.getMessage());
}
Another variant
public class MyCustomExceptionWithoutMessageInConstructor extends IllegalArgumentException {
private static final String ERROR_MESSAGE = "terrible error";
public MyCustomExceptionWithoutMessageInConstructor() {
super(ERROR_MESSAGE);
}
}