2011-04-29 24 views
12

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.Jersey/Jackson Excepción de problema con ExceptionMapper

Tengo el problema de que si el formato de jackson incorrecto se envía 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 "apellido" de atributo y envío "sursname" en la cadena JSON al servidor, me sale:

Unrecognized field "sursname" (Class XY), not marked as ignorable at [Source: [email protected]; line: 1, column: 49] (through reference chain: XY["sursname"]) 

Eso es bastante bien, pero me gustaría tener mi propio contenido de la respuesta, por ejemplo mi propio código de error. Ya escribí ExceptionMapper personalizado que debe asignar 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 la excepción Jackson se lanza antes de llamar a mi método de servicio web, así que no tienen ninguna posibilidad de hacer un mapa?

¿Alguien tiene una idea? Muchas gracias y perdón por mi inglés;)

Respuesta

1

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á seguro de que su 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.

-1

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 su ayuda!

2

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 ocurrió en mi método JAX-RS y en su lugar ocurrió en el JacksonJsonProvider. La solución en mi caso era extender JacksonJsonProvider, detectar las excepciones específicas de Jackson json y volver a lanzarlas como WebApplicationException.

Aquí es mi método readFrom overriden para mi extendida JacksonJsonProvider:

@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()); 
     } 
    } 
13

La razón de que su encargo ExceptionMapper no detectar las excepciones se debe a que la biblioteca Jackson ofrece sus propios creadores de mapas de excepción, que detecta la excepción antes de que se sería atrapado por tu 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. See this issue on their GitHub.

Para resolver este problema, debe asegurarse de que ninguno de los correlacionadores de excepciones integrados esté registrado.Si está utilizando los Jackson-jaxrs proveedores de biblioteca para JSON: Jackson-jaxrs JSON-proveedor, asegúrese de que son solamente registrarse ya sea JacksonJaxbJsonProvider.class o JacksonJsonProvider.class en su clase de aplicación:

public class MyApplication extends ResourceConfig { 
    public MyApplication() { 
     register(JacksonJaxbJsonProvider.class) 
    } 
} 

ser conscientes de la JacksonFeature.class, en que registra el construido en ExceptionMappers. Además, aléjese 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.

+3

Me acabo de pasar bastante tiempo con este problema, leer muchas discusiones al respecto, sobre todo mencionar exceptionmappers. Finalmente tropecé con su respuesta, que es la única que encontré que explica el problema correctamente, por qué los mapeadores de excepciones no siempre funcionan y tienen una solución simple. ¡Gracias! Debe ser el mercado como respuesta aceptada. – patman

+1

¡La mejor respuesta de todas! Registrar solo JacksonJsonProvider.class funciona para mí, pero no JacksonJaxbJsonProvider.class. Esta realmente debería ser la respuesta aceptada. – wolf97084

0

Tuve el mismo problema y solucioné 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 anule:

<init-param> 
<param-name>jersey.config.server.provider.classnames</param-name> 
    <param-value> 
     com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider 
    </param-value>