RestEasy ExceptionMapper not catching the exceptions - exception

I'm throwing an exception MyCustomException from my application. (EJB Layer)
I've an exception mapper in web service layer which looks like following -
package net.webservices;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import net.common.MyCustomException;
#Provider
public class EJBExceptionMapper implements
ExceptionMapper<net.common.MyCustomException> {
public Response toResponse(MyCustomException exception) {
return Response.status(Response.Status.BAD_REQUEST).build();
}
}
I've registered my mapper in web.xml of the web service layer as following -
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>net.webservices.EJBExceptionMapper</param-value>
</context-param>
The EJBExceptionMapper is not catching the MyCustomException. But instead its being caught by the catch block of the web service implementation.
What could be the problem?
Note: I don't want to register my ExceptionMapper manually using getProviderFactory().addExceptionMapper()

I don't know why your solution doesn't work (but I've never used RESTeasy, only Jersey). In any case, it would probably be simpler to extend WebApplicationException. That way, you don't have to register a provider:
public class MyCustomException extends WebApplicationException {
public MyCustomException() {
super(Response.status(Response.Status.BAD_REQUEST).build());
}
}

You need to throw exception (of type MyCustomException ) in the catch block and add a "Throws MyCustomException" to the method signature

Related

How do I log com.fasterxml.jackson errors with Quarkus?

I use Jackson to check and databind input JSON for a REST API, and I would like to log the error when the input doesn’t match a #Valid constraint.
However, the exceptions are throwned as a Response by the API but do not appear in Quarkus’ logs.
How do I log Jackson’s exceptions ?
One has to create a handler for the Jackson exceptions, e.g. using ExceptionMapper.
The following example catches all exceptions of type JsonProcessingException (finer tuning is obviously possible), logs them as SEVERE (using lombok’s #Log annotation) and returns a 400 Bad Request Response including the message. Note that the function has to be toResponse(Exception).
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.java.Log;
#Log
#Provider
public class MyJsonProcessingExceptionHandler implements ExceptionMapper<JsonProcessingException> {
#Override
public Response toResponse(JsonProcessingException exception) {
log.severe(exception.getMessage());
return Response.status(Response.Status.BAD_REQUEST).entity(exception.getMessage()).build();
}
}
Do not forget the #Provider annotation so that the Exception handler acts as a filter on the REST API.
In principle other files of the project (including the controller) do not need to be modified, only this class in its own file.

Apache Camel Rest Custom Json Deserializer

I use Camel 2.16.0 for a Camel Rest project. I have introduced an abstract type that I need a custom deserializer to handle. This works as expected in my deserialization unit tests where I register my custom deserializer to the Objectmapper for the tests. To my understanding it is possible to register custom modules to the Jackson Objectmapper used by Camel as well (camel json).
My configuration:
...
<camelContext id="formsContext" xmlns="http://camel.apache.org/schema/spring">
...
<dataFormats>
<json id="json" library="Jackson" useList="true" unmarshalTypeName="myPackage.model.CustomDeserialized" moduleClassNames="myPackage.MyModule" />
</dataFormats>
</camelContext>
My module:
package myPackage;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class MyModule extends SimpleModule {
public MyModule() {
super();
addDeserializer(CustomDeserialized.class, new MyDeserializer());
}
}
The Camel rest configuration:
restConfiguration()
.component("servlet")
.bindingMode(RestBindingMode.json)
.dataFormatProperty("prettyPrint", "true")
.contextPath("/")
.port(8080)
.jsonDataFormat("json");
When running the service and invoking a function that utilize the objectmapper I get the exception:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of myPackage.model.CustomDeserialized, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
Any suggestions on what is wrong with my setup?
I found this solution to the problem and used this implementation for my custom jackson dataformat:
public class JacksonDataFormatExtension extends JacksonDataFormat {
public JacksonDataFormatExtension() {
super(CustomDeserialized.class);
}
protected void doStart() throws Exception {
addModule(new MyModule());
super.doStart();
}
}

Jersey unable to catch any Jackson Exception

For my REST api I'm using jersey and ExceptionMapper to catch global exceptions.
It works well all the exception my app throws but I'm unable to catch exception thrown by jackson.
For example one of my endpoint accept an object that contains an enum. If the Json in the request has a value that is not in the enum jersey throw this exception back
Can not construct instance of my.package.MyEnum from String value 'HELLO': value not one of declared Enum instance names: [TEST, TEST2]
at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream#5922e236; line: 3, column: 1] (through reference chain: java.util.HashSet[0]->....)
Even though I have created this mapper
#Provider
#Component
public class JacksonExceptionMapper implements ExceptionMapper<JsonMappingException> {
#Override
public Response toResponse(JsonMappingException e) {
....
}
}
The code never reach this mapper.
Is there anything we need to do in order to catch these exceptions?
EDIT
Note: I have jus tried being less general and instead of JsonMappingException I use InvalidFormatException in this case the mapper is called. But I still don't understand because InvalidFormatException extends JsonMappingException and should be called as well
Had the same problem.
The problem is that JsonMappingExceptionMapper kicks in before your mapper. The actual exception is of class com.fasterxml.jackson.databind.exc.InvalidFormatException and the mapper defines com.fasterxml.jackson.jaxrs.base.JsonMappingException, so it's more specific to the exception.
You see, Jersey's exception handler looks to find the most accurate handler (see org.glassfish.jersey.internal.ExceptionMapperFactory#find(java.lang.Class, T)).
To override this behavior, simply disable the mapper from being used:
Using XML:
<init-param>
<param-name>jersey.config.server.disableAutoDiscovery</param-name>
<param-value>true</param-value>
</init-param>
Using code: resourceConfig.property(CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true); where resourceConfig is of type org.glassfish.jersey.server.ServerConfig.
You can also write your own specific mapper:
public class MyJsonMappingExceptionMapper implements ExceptionMapper<JsonMappingException>
But I think it's an over kill.
Hi it seems to exits an alternative answer now that does not require to disable Jersey AUTO_DISCOVERY feature.
Just annotate your own exception mapper with a #Priority(1) annotation. The lower the number, the higher the priority. Since Jackson's own mappers do not have any priority annotation, yours will be executed:
#Priority(1)
public class MyJsonMappingExceptionMapper implements ExceptionMapper<JsonMappingException>
Starting in version 2.29.1 [1], if you're registering the JacksonFeature, you can now do so without registering the exception mappers [2]:
register(JacksonFeature.withoutExceptionMappers());
[1] https://github.com/eclipse-ee4j/jersey/pull/4225
[2] https://eclipse-ee4j.github.io/jersey.github.io/apidocs/2.34/jersey/org/glassfish/jersey/jackson/JacksonFeature.html#withoutExceptionMappers--

No exception of type DataAccessException can be thrown; an exception type must be a subclass of Throwable

My source code like below.
It has a error, "No exception of type DataAccessException can be thrown; an exception type must be a subclass of Throwable".
I can't understand why the error ocurrs.
let me know. thx.
package com.sds.afi.cosmos.cmm.db.impl;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.ibatis.SqlMapClientTemplate;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
import org.springframework.stereotype.Repository;
import com.sds.afi.cosmos.cmm.db.MainDao;
#Repository
//#SuppressWarnings("unchecked") // 부적절한 컴파일러의 경고를 제거
public class MainDaoImpl extends SqlMapClientDaoSupport implements MainDao {
#Autowired
private SqlMapClientTemplate sqlMapClientTemplate;
#SuppressWarnings("unchecked")
#Override
public List<HashMap> getUserInfo() throws DataAccessException {
List<HashMap> lists;
lists = sqlMapClientTemplate.queryForList("common.getList");
return lists;
}
}
This can happen if some class in the type-hierarchy of the exception is not on the class-path. In that case, its not possible to verify whether the exception really extends Throwable, whether it is a checked one or not, etc. Hence the errors. e.g superclass of Dataaccessexception : NestedRuntimeException may be missing from the class-path as it is in a differnt jar i.e. spring-core.
Your DataAccessException is not a subclass of Throwable class (extends Throwable). It should be, and without this inheritance, your code is not compilable with the current throws clause.
Here is an example: http://www.osix.net/modules/article/?id=754
I had this same issue when I upgraded to 5.X.X version. I have added Spring-core.jar file and it worked fine for me. Just adding this here because it may help some one. Spring txn jar , dao jar and spring core are must.
This means that in your getUserInfo() method there is no code that throws that exception. So just remove the throws clause from your method declaration.
I was facing same problem.
What I have done wrong was I have created Exception class(by mistake) of my own.
In other programs I was trying to extend Exception class(default) but complier(eclipse)was loading user defined Exception class giving me same error.
So please make sure you are not overriding any default class.

Camel Exception handling doesnt work if exception clause is defined in a separate class

I am trying to build a application with several camel routes which re use many common routes internally.
Hence, I am trying to segregate the routes in several different Route Builder classes and then connecting the routes where needed.
For eg, all routes pertaining to sending emails go into a EmailRouteBuilder class and all routes dealing with a particular JMS Queue go into MyQueueRouteBuilder class.
I suppose this should be alright since Camel doesnt not distinguish between classes and only looks for routes defininition.
In addition, I am also grouping several exception handling routes into a separate ExceptionHandlingRouteBuilder.
I am also connecting all the different classes together by defining the camel context in Spring like so -
<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring">
<propertyPlaceholder id="properties" location="classpath:${env}/autoimport.properties"/>
<!-- Common Routes -->
<routeBuilder ref="emailRouteBuilder" />
<routeBuilder ref="myQueueRouteBuilder" />
<routeBuilder ref="httpRouteBuilder" />
<routeBuilder ref="exceptionsRouteBuilder" />
<routeBuilder ref="customer1RouteBuilder" />
<routeBuilder ref="customer2RouteBuilder" />
</camelContext>
My exceptionsRouteBuilder contains many exception clauses like -
onException(ConnectException.class)
.routeId("connectExceptionEP")
.handled(true)
.log("Caught Exception: ")
.to("direct:gracefulExit");
..
..
..
However, it looks like there is a problem with the exceptions being defined in another class, or for that matter, defined separately out of the main route definition.
I verified this in the logs by looking for the routes being booted ( by routeId ) and also checking when an exception is thrown.
Additionally, to further confirm, I took the http Connect Exception handling route and put that directly in the httpRouteBuilder and lo..! , the exception handling now kicks in just fine for this exception..
Am I missing something here to get all exceptions to work while being nicely defined in its own class. ?
I am using Apache Camel 2.9.0 , but I verified the same behavior also in 2.8.3.
Thanks,
Anand
correct, the onException() clauses only apply to the current RouteBuilder's route definitions...
that said, you can reuse these definitions by having all your RouteBuilders extend the ExceptionRouteBuilder and call super.configure()...something like this
public class MyRouteBuilder extends ExceptionRouteBuilder {
#Override
public void configure() throws Exception {
super.configure();
from("direct:start").throwException(new Exception("error"));
}
}
...
public class ExceptionRouteBuilder implements RouteBuilder {
#Override
public void configure() throws Exception {
onException(Exception.class).handled(true).to("mock:error");
}
}
or even just have a static method in an ExceptionBuilder class to setup the clauses for a given RouteBuilder instance
public class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
ExceptionBuilder.setup(this);
from("direct:start").throwException(new Exception("error"));
}
}
...
public class ExceptionBuilder {
public static void setup(RouteBuilder routeBuilder) {
routeBuilder.onException(Exception.class).handled(true).to("mock:error");
}
}
Based on the accepted answer, I found a cleaner way to implement exception handling, so you don't have to call super.configure() in every route. Just call a method that handles onException in the constructor of the base class.
//Base class that does exception handling
public abstracExceptionRouteBuildert class BaseAbstractRoute extends RouteBuilder {
protected BaseAbstractRoute() {
handleException();
}
private void handleException() {
onException(Exception.class).handled(true).to("mock:error");
}
}
//Extend the base class
public class MyRouteBuilder extends BaseAbstractRoute {
#Override
public void configure() throws Exception {
from("direct:start").throwException(new Exception("error"));
}
}