java - Jersey/Jackson Excepción problema con ExceptionMapper
exception-handling (5)
Gracias por su ayuda, un ExceptionMapper para JsonParseException no ayudó. Quité los archivos de jackson jar de mi proyecto e incluí las fuentes de jackson. Luego modifiqué ord.codehaus.jackson.jaxrs.JsonParseExceptionMapper y JacksonMappingExceptionMapper para devolver el contenido de mi respuesta personalizada. No estoy contento con eso, ¡pero funciona ahora!
¡Gracias por tu ayuda!
Estoy usando Jersey para proporcionar un servicio REST de Java al mundo exterior. Ofrezco algunas funciones que toman JSON y uso el marco de Jackson en combinación con Jersey para convertirlos en POJO.
Tengo el problema de que si se envía un formato de jackson incorrecto al servidor, la respuesta (contenido de la respuesta http) es una descripción de excepción específica de jackson. Si tengo un POJO con un atributo "apellido" y envío "sursname" en la cadena json al servidor, obtengo:
Unrecognized field "sursname" (Class XY), not marked as ignorable at [Source: sun.net.httpserver.FixedLengthInputStream@903025; line: 1, column: 49] (through reference chain: XY["sursname"])
Eso está bastante bien, pero me gustaría tener mi propio contenido de respuesta, por ejemplo, mi propio código de error. Ya escribí un ExceptionMapper personalizado que debe mapear todos los Throwables.
@Provider
public class WebserviceExceptionMapper implements ExceptionMapper<Throwable> {
@Override
public Response toResponse(Exception e) {
e.printStackTrace();
return Response.status(400).entity("{/"errorcode/":/"CRITICAL_ERROR/"}").type(MediaType.APPLICATION_JSON).build();
}
}
Parece que se lanza la excepción de jackson antes de que se llame a mi método de servicio web, por lo que no tengo ninguna posibilidad de mapearlo.
¿Alguien tiene alguna idea? Muchas gracias y perdón por mi inglés;)
La razón por la cual su ExceptionMapper personalizado no capta las excepciones es porque la biblioteca de Jackson proporciona sus propios mapeadores de excepciones, que atrapa la excepción antes de que sea atrapada por su mapeador de excepción genereal.
Algunos sugieren que debe implementar sus propios mapeadores de excepciones para JsonParseExceptionMapper y JacksonMappingExceptionMapper, pero eso, sin embargo, dará resultados inconsistentes. Vea este problema en su GitHub .
Para resolver este problema, debe asegurarse de que ninguno de los mapeadores de excepciones integrados esté registrado. Si está utilizando la biblioteca de proveedores de jackson-jaxrs para JSON: jackson-jaxrs-json-provider , asegúrese de registrar solo JacksonJaxbJsonProvider.class o JacksonJsonProvider.class en su clase de aplicación:
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(JacksonJaxbJsonProvider.class)
}
}
Tenga en cuenta la clase JacksonFeature.class , ya que registra el construido en ExceptionMappers. También manténgase alejado de la biblioteca jersey-media-json-jackson , que automáticamente agregará algunos mapeadores de excepción incorporados, sin que tenga que hacer nada en absoluto.
Me encontré con un problema similar hace un tiempo mientras usaba Jackson y Apache CXF. No se llamaron a los mapeadores de excepciones si la excepción no se produjo en mi método JAX-RS y en cambio ocurrió en JacksonJsonProvider
. La solución en mi caso fue extender JacksonJsonProvider
, detectar las excepciones específicas de Jackson json y volver a lanzarlas como WebApplicationException
.
Aquí está mi método readFrom modificado para mi JacksonJsonProvider
extendido:
@Override
public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException {
try {
return super.readFrom(type, genericType, annotations, mediaType, httpHeaders, entityStream);
} catch (JsonParseException jpe) {
throw new WebApplicationException(jpe, Response.status(Status.BAD_REQUEST)
.entity(new ErrorEntity("Malformed json passed to server: /n" + jpe.getMessage())).build());
} catch (JsonMappingException jme) {
throw new WebApplicationException(jme, Response
.status(Status.BAD_REQUEST)
.entity(new ErrorEntity("Malformed json passed to server, incorrect data type used: /n"
+ jme.getMessage())).build());
}
}
Por supuesto, la excepción de Jackson es lanzada antes: se llama al proveedor de Jackson para crear un objeto que está esperando en su método. Sin embargo, con ExceptionMapper debe poder asignar no solo sus excepciones, sino también la excepción de los proveedores.
¿Estás seguro de que tu proveedor está registrado? ¿Se lo llama si arroja una excepción de su método y no del proveedor?
Si la respuesta a la pregunta anterior es "sí", intente implementar ExceptionMapper para una excepción concreta en lugar de Throwable.
Tuve el mismo problema y resolví el OverScripting ExceptionMapper. ¡Perfecto! Una cosa adicional que tenía que hacer y que no entendía al 100% era cómo anular el JacksonProvider para mi aplicación (no sé si estaba relacionado con la versión de Jersey que estaba usando - 2.19). Aquí está mi parte web.xml que lo anula:
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider
</param-value>