I have a feign client like this
#FeignClient(name = "client")
public interface SomeClient {
#RequestLine("GET /?q={q}")
void execute(URI baseUrl, #Param("q") String q) throws SomeExceptionInMyCode;
}
Looking to this throws SomeExceptionInMyCode I'm asking myself when this exception will be thrown. There is no configuration for client defined, no error decoder. Exception looks like this.
public class SomeExceptionInMyCode extends Exception{
private final int statusCode;
private final String reason;
private final String body;
// getters and setters
}
Will there be an automatic attempt to decode HTTP response to this exception in case of failure? Or throws SomeExceptionInMyCode is useless and can be removed without any impact.
I searched inside my code and this exception is never created.
Will there be an automatic attempt to decode http response to this exception in case of failure?
Nope, it doesn't work like this and the SomeExceptionMyCode will not be thrown. The throws clause is useless. Even if the endpoint throws this exception from its implementation, it will be wrapped as a cause of FeignException.
The correct way to handle feign client exceptions is using Custom exception handling implementing ErrorDecoder:
public class StashErrorDecoder implements ErrorDecoder {
#Override
public Exception decode(String methodKey, Response response) {
if (response.status() >= 400 && response.status() <= 499) {
// return 4XX exception
}
if (response.status() >= 500 && response.status() <= 599) {
// return 5XX exception
}
}
}
At this point you can perform the custom exception creation and rethrowing.
An alternative solution is to use Spring-alike #RestControllerAdvice:
#RestControllerAdvice
public class ExceptionHandler {
#ExceptionHandler(FeignException.class)
public String handleFeignStatusException(FeignException e, HttpServletResponse response) {
// ...
}
}
What if the StashErrorDecoder throws a checked exception? That is allowed. In this case the throws clause in the interface surely helps. This way you can catch and handle the exception thrown by Feign. At least it should work this way.
Related
I am using OpenFeign client in Spring Boot without using Ribbon or Eureka. I created a custom error decoder which handles response errors as intended but connection refused errors seem to bypass my custom decoder.
P.S. When my remote service is up, I can make requests and receive responses.
I am new to Java and Spring and I am wondering if I need to wrap all my calls with try catch, or adding my custom error handler should be catching the error since it seems cleaner to handle all errors in one place
public class FeignErrorDecoder implements ErrorDecoder {
private final ErrorDecoder defaultErrorDecoder = new Default();
#Override
public Exception decode(String methodKey, Response response) {
if (response.status() >= 400 && response.status() <= 499) {
//handle with custom exception
}
if (response.status() >=500) {
//handle with custom exception
}
return defaultErrorDecoder.decode(methodKey, response);
}
}
#Configuration
public class FeignConfig {
//other beans here
#Bean
public ErrorDecoder feignErrorDecoder() {
return new FeignErrorDecoder();
}
}
java 8, spring, rest
I am trying to capture the Response that comes from exception mapper, and do something with it in the caller which throws the exception. Thanks.
#Provider
public class CustomerExceptionHandler implements ExceptionMapper<CustomerException>
{
#Override
public Response toResponse(CustomerException exception)
{
return Response.status(Status.BAD_REQUEST).entity(CustomerException.getMessage()).build();
}
}
public class CustomerException extends Exception implements Serializable
{
private static final long serialVersionUID = 1L;
public CustomerException() {
super();
}
public CustomerException(String msg) {
super(msg);
}
public CustomerException(String msg, Exception e) {
super(msg, e);
}
}
public class ExceptionDemo{
public void getExceptionResponse(){
//do something
throw new CustomerException("Something is wrong");// CustomerExceptionHandler is going to return me a Response, how can I capture the response here?
//capture response and do something with it
}
}
I'm not sure ExceptionMappers work in the way you think they do.
When some code in the endpoint throws an exception, and this exception percolates all the way out of the endpoint and back into the container itself (Spring in this case), then the registered ExceptionMappers are consulted to see if they match the thrown exception, and the relevant one's public Response toResponse(T e) {} method is called to transform it into a Response.
The ExceptionMapper doen't get called as part of your endpoint code, and you won't be able to take action based on its resultant Response because it hasn't yet been called. You just need to throw the exception out of the endpoint.
I have an interface:
public interface ThirdPartySystemCaller {
void sendRequest(String request) throws ThirdPartySystemException;
}
And implementation:
#Slf4j
#Service
public class ThirdPartySystemCallerImpl implements ThirdPartySystemCaller {
#Override
public void sendRequest(String request) throws ThirdPartySystemException {
if (request == null) throw new ThirdPartySystemException();
log.info("send: {}", request);
}
}
And I have a CryptoService witch can sign request:
public interface CryptoService {
String signRequest(String request) throws CryptoException;
}
And It implementation:
#Slf4j
#Service
public class CryptoServiceImpl implements CryptoService {
#Override
public String signRequest(String request) throws CryptoException {
if (request.length() > 100) throw new CryptoException(); //just for example
return "signed " + request;
}
}
Now, I can use these services:
String signedRequest = cryptoService.signRequest("Hello");
thirdPartySystemCaller.sendRequest(signedRequest);
But I need to call both services each time. I want to create Proxy:
#Slf4j
#Service
public class ThirdPartySystemCallerSignedProxy implements ThirdPartySystemCaller {
private final ThirdPartySystemCaller thirdPartySystemCaller;
private final CryptoService cryptoService;
public ThirdPartySystemCallerSignedProxy(ThirdPartySystemCaller thirdPartySystemCaller, CryptoService cryptoService) {
this.thirdPartySystemCaller = thirdPartySystemCaller;
this.cryptoService = cryptoService;
}
#Override
public void sendRequest(String request) throws ThirdPartySystemException {
String signedRequest = cryptoService.signRequest(request);
thirdPartySystemCaller.sendRequest(signedRequest);
}
}
But my ThirdPartySystemCallerSignedProxy implement ThirdPartySystemCaller interface and sendRequest method throw only ThirdPartySystemException. But if cryptoService throw CryptoException I need throw it too.
How can I do it?
I was thinking to make unchecked exceptions, But I need to be checked.
Create base exception
You can create abstract exception BusinessException which can be a base exception for ThirdPartySystemException and CryptoException. Now, you can define that sendRequest method throws BusinessException and real exception depends from given problem.
Facade
ThirdPartySystemCallerSignedProxy is a bad name because it reminds Proxy pattern which is not what you have implemented. This class reminds Facade pattern because you want to create unified interface with simpler API for two different interfaces. In that case you can wrap CryptoException if it will be thrown into ThirdPartySystemException or also create base exception and declare it in method. It is even better because you do not know which kind of exception will be thrown but for sure it will be BusinessException.
Chain of Responsibility
Many libraries use Chain of Responsibility to handle request -> response communication. All chain cells need to implement the same interface with base exception in declaration if needed. You can build the chain in bean definition. It is a little bit easier to maintain because all cells are independent and does not have to know about each other as in Facade. You can build chain in #Bean method declaration like below:
#Bean
public ServiceChainCell thirdPartyCaller() {
CryptoService crypto = cryptoService();
ThirdPartySystemCaller caller = thirdPartySystemCaller();
// Create chain
crypto.setNext(caller);
return crypto;
}
setNext method comes from ServiceChainCell interface which also should have sendRequest(String request) method.
Read more about these patterns and you will find the best solution for you.
This question already has answers here:
Spring Async Uncaught Exception handler
(4 answers)
Closed 3 years ago.
I have a custom exception that I throw in a class that is not caught in another class.
I don't know what's wrong here :
Class MailService.java
#Async
public void sendMail(String to, String subject) throws EmailNotSentException {
throw new EmailNotSentException();
}
Class MailResource.java
#RequestMapping(value = "/mails-envoyes",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<MailEnvoye> createMailEnvoye(#RequestBody MailEnvoye mailEnvoye, HttpServletRequest request) throws URISyntaxException {
try{
mailService.sendMail(to, "subject");
}catch (EmailNotSentException e){
log.debug(e.getLocalizedMessage());
}
}
Exception
public class EmailNotSentException extends MessagingException {
public EmailNotSentException() {
super();
}
public EmailNotSentException(String message) {
super(message);
}
public EmailNotSentException(String message, Exception e) {
super(message, e);
}
}
The issue is probably the #Async annotation (I'm assuming this code runs with Spring) ... as it says on the tin, it run it asynchronously, which means that it will run in a different thread, so the calling method will never receive the Exception.
If you want to handle the exception in the way you have in your code, just remove the #Async annotation.
There are a few articles around which explain how to catch an exception from an async method (google is your friend), and make it available so something else can deal with it, but it's always asynchronously.
I am using Below Custom Exception class in my project
public class BadRequestException extends WebApplicationException {
private static final long serialVersionUID = 1L;
private String message;
public BadRequestException(String message) {
super();
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
I have created a Mapper class also..
public class BadRequestExceptionMapper implements ExceptionMapper<BadRequestException> {
public Response toResponse(BadRequestException brexec) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(brexec.getResponse().getEntity()).type(MediaType.APPLICATION_JSON).build();
}
}
I am calling my service through a Servlet and the Exception is thrown by one of its method but i am not able to catch it in Servlet class.I have used below code to catch the exception..
try{
//Some Business logic then
service.path("restful").path("jwbservice/" + methodName + "/" + id).header("lid", lid).delete(String.class);
}
catch (BadRequestException ex) {
out.println(ex);
}
catch(Exception exe){
out.println(exe);
}
And the service method i have used this code in my Service class which will throw the exception.
#DELETE
#Path("/deleteLink/{id}")
#Produces(MediaType.APPLICATION_JSON)
public String deleteLink(#PathParam("id") int id, #HeaderParam("lid") String lid) throws BadRequestException {
if (id<= 0) {
throw new BadRequestException("Required Parameter: id");
}
//Some Business Logic
}
My Service throw the BadRequestException but in Servlet it is going to Exception catch not in BadRequestException Catch block.
Can any one know what i am doing wrong.
You will never get that exception in your servlet. This is because the servlet is effectively a REST client, and you are invoking a remote resource method to get some data. The resource call will either be successful (and some data will be mapped back), or it will fail and you will get no data (or a client side error).
On a side note, there is a problem in your server side exception mapper. You do not verify that the exception actually has a response entity before calling:
brexec.getResponse().getEntity()
In cases where the exception doesn't have a response the above code will cause a null pointer exception.
Some quick notes:
Exception classes already have a message property. You do not need to define an additional one
Your exception mapper needs to check for a non-existent response property, before trying to do something with it
The resource path in your servlet does not appear to match the server side path. I assume that is a copy/paste error.