I want my ExceptionMapper to catch all exceptions and log them... I'm using Jersey 2.0 right now.
I have an exception mapper like so:
#Provider
public class RestExceptionMapper implements ExceptionMapper<Exception> {
#Override
public Response toResponse(Exception e) {
log(e);
if (e instanceof WebApplicationException) {
return ((WebApplicationException) e).getResponse();
} else {
return buildResponse(e);
}
This exception mapper only gets called for non-WebApplication application exceptions.
How do I make one global exception mapper catch all the exceptions so I can log them. Is there another way I should approach this?
Thanks
Judging from the source code of Jersey where this is handled there is no way to do this with an ExceptionMapper. WebApplicationExceptions get a special treatment are never mapped.
A way to log all exceptions is to set the logger org.glassfish.jersey.server.ServerRuntime to FINER.
Related
I have a notification service(I have control of this class).
If there is any unchecked exception, then I do not want to throw it. But instead want to log it in a specific manner.
I can directly have try catch block in each method's implementation but I am in search of some magic here 😄
Is there a common way that this can be handled through Spring?
Update:
AOP is also a way to do it. For example: https://dzone.com/articles/handling-exceptions-using-springs-aop
Any other direct implementation for this?
This was my requirement but I was not able to find anything with respect to this.
I faced similar issues when dealing with calling multiple apis from rest service, where i was suppose to provide a fallback implementation when error occured. My Aspect was more than what i am giving example here.
Service
#Service
public class SuspiciousService {
final Random random = new Random();
public String beSuspicious() {
final boolean value = random.nextBoolean();
if (value) {
throw new IllegalStateException("Exception occured for: " + value);
}
return "I am not suspicious";
}
}
Sample service which randomly throws an error.
Controller
#RestController
#RequestMapping("/is-suspicious")
#AllArgsConstructor
public class SampleController {
private final SuspiciousService suspiciousService;
#GetMapping
public Map<String, String> get() {
return Map.of("isSuspicious", suspiciousService.beSuspicious());
}
}
Controller which invokes this service.
Finally, Around Aspect catches this exception and provides the sample response.
#Aspect
#Component
#Order(2)
public class AspectAroundSuspiciousService {
#Around("execution(* in.silentsudo.sprintbootresttemplate.SuspiciousService.beSuspicious(..))")
public Object parallelExecuteBeforeAndAfterCompose(ProceedingJoinPoint point) throws Throwable {
try {
return point.proceed();
} catch (RuntimeException re) {
return "Yes, I am suspicious";
}
}
}
The other approach is if you are using ByteBuddy, you can add annotation to the method throwing exception
#Advice.OnMethodExit(onThrowable = RuntimeException.class)
and have an ExceptionHandler to cath this
#ExceptionHandler
private String suspiciousRuntimeException(RuntimeException exception) {
return "Yes, I am suspicious from ex handler, error: " + exception.getMessage();
}
I choose aspect over bytebuddy for simple reason as i was handling ladder of api exception, where as this implementation will catch in general RuntimeException happenning from service#method
I'm using #Transactional in my code and I'm created a custom exception to show error messages in specific format in UI.
public class MyCustomException extends RuntimeException
When this exception is encountered I still want to rollback my transactions, same as in case when any other exception occurs.
So to make it work, I writing below code:
// service method called from rest controller
public List<String> getMyData() {
List<String> errors = new ArrayList();
try {
businessMethod();
} catch (MyCustomException e) {
log.error(e.getMessage);
errors.add(e.getMessage)
}
return errors.
}
#Transactional(rollbackFor = {MyCustomException.class, RuntimeException.class, Exception.class})
public String businessMethod() {
// Business logic to get data that can throw MyCustomException
}
My questions are:
If I'm mentioning MyCustomException.class in rollbackFor, do I need to also mention RuntimeException.class, Exception.class. Or whatever is mentioned in rollbackFor gets appended along with default exceptions for which transaction is rolled-back.
Although I'm escaping the MyCustomException from businessMethod(), but I'm catching it on its calling method getMyData(). I'm assuming that the transaction will be rolled-back in case of exception, correct?
The transaction will be rolled back on any RuntimeException, so it is not necessary to declare your own MyException.class in rollbackFor section, since your MyException extends RuntimeException. If you declare Exception.class the rollback will be performed on any Exception. But in your case you do not need rollbackFor at all.
Yes, it is correct. Your transcation starts and ends in businessMethod().
How catch NoEndpointFoundException in Spring WS?
By default MessageDispatcher.dispath() throws NoEndpointFoundException in case of absence appropriate Endpoint but then WebServiceMessageReceiverObjectSupport.handleConnection() just hides the exception. In my point I should catch it by myself.
Is it good idea to add custom EndpointMapping via MessageDispatcher.getEndpointMappings().add() and throws exception in that?
I find out following solution:
#Component
#Order(Ordered.LOWEST_PRECEDENCE)
public class NoEndpointFoundEndpointMapping implements EndpointMapping {
#Override
public EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception {
throw new MyCustomException(...);
}
}
I've created my own exception class:
public class ValidationException extends RuntimeException { ... }
I've declared it in EJB interface method:
public interface MyApi {
void save(MyDTO dto) throws ValidationException;
}
Now I've used it in the implementation:
#Stateless
#Local(MyApi.class)
public class MyService implements MyApi {
public void save(MyDTO dto) throws ValidationException {
...
throw ValidationException(errorMessages);
}
}
However, when I call that method:
#Path("/my")
#Stateless
public class MyChannel {
#Inject private MyApi myApi;
public void save(MyDTO dto) {
try{
myApi.save(dto);
} catch (ValidationException ex) {
// do sth with the exception
}
}
}
Instead of expected ValidationException, the EJBException is thrown with the following message:
0000167f BusinessExcep E CNTR0020E: EJB threw an unexpected (non-declared) exception during invocation of method "save" on bean
It surprised me, because the exception is declared in the interface and in the implementation. How else can I declare the exception, in order to be able to use it to communicate errors to the caller?
The whole mayhem happens on the WebSphere 8.5. I'm using EJB 3.0 and WebSphere libraries. The channel is JSON REST channel in the WAR module, which is wrapped in EAR module.
I believe the root of your problem lies in choosing to have your custom ValidationException extend RuntimeException. Within Java, RuntimeException or any subclass of RuntimeException does not have to be declared using a throws clause on a method signature. The intent of RuntimeException is that it is generally used in unrecoverable bug scenarios that are the result of something done incorrectly by the method caller, such as attempting to traverse beyond the end of an array (ArrayIndexOutOfBoundsException) or passing an invalid parameter (IllegalArgumentException).
Given that you would like to make your ValidationException part of the method signature and thereby require the calling client to handle the exception, I suggest the following change:
//Modify your exception so that it
//subclasses Exception (not RuntimeException):
public class ValidationException extends Exception { ... }
You will not have to modify the MyService interface, because the save method already declares that it throws the exception. But this small change will shift the way Java handles ValidationException so that when the exception is thrown, it will behave in the way you expect (and without the extraneous noise about an "undeclared" exception).
Use the #ApplicationException annotation. For example
#ApplicationException
public class ValidationException extends RuntimeException {
private static final long serialVersionUID = 7797343376699439504L;
}
You can use it with RuntimeException so you don't have to use throws declarations.
I am developing a Client-Server app with JAX-RS / Apache CXF, JSON
I would like Apache CXF to handle my exception transparently on both ends : Which means transforming the exception into a bean, serializing it with my Jackson Serializer (JSON) and then doing the over way around on client side.
I have seen several confusing posts/answers on this subject and came up with using the #WebFault annotation :
#WebFault(name=CODE, faultBean="foo.bar.FaultBean")
public class DuplicateRuleNameFault extends Exception {
static final public String CODE = "DUPLICATE_RULE_NAME";
private FaultBean faultBean;
public DuplicateRuleNameFault(String msg) {
super(msg);
this.faultBean = new FaultBean(msg);
}
public DuplicateRuleNameFault() {
}
public FaultBean getFaultBean() {
return faultBean;
}
public void setFaultBean(FaultBean faultBean) {
this.faultBean = faultBean;
}
}
With no success ... Currently, CXF seems to happily ignore the annotation on the Exception and handle it as an unknown exception : 500 status error and no response body generated on the server side.
Is there something specific I have to configure in the "" server element of my Spring context ? I already have Spring scanning my Exception/FaultBean classes (is it even needed BTW ?).
I would appreciate if you could point me at some working example.
Thanks.
#WebFault's are not part of the JAX-RS specification. You will want to read up on section 3.3.4 of the specification, which describes the different ways you can accomplish what you are trying to do.
Option 1
Design your resource classes to throw WebApplicationException's. Set the response property of these exceptions to be a valid JAX-RS response containing the fault beans you want to send to the client.
Option 2
Define exception mapping providers. You can create a hierarchy of these to handle all the common exceptions your application will throw. Or you can create a top level exception with an embedded bean and an exception handler for it. And then derive several specific exceptions from the top level one.
public abstract class MyApplicationException<T> extends Exception {
private T faultBean;
// Constructors, setters/getters
}
#Provider
public class MyApplicationExceptionHandler implements ExceptionMapper<MyApplicationException<?>> {
// Implementation
}
One way of doing this is by using the javax.ws.rs.core.Response object like so :
#GET
#Path("/")
public Response getBlah()
{
try {
return Response.status(Response.Status.OK)
.entity(<Object you want to return>).build();
}
catch (final DuplicateRuleNameFault e) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(e.getFaultBean().getMsg()).build();
}
}