2014-06-24 34 views
12

我在我的REST API中使用Jersey 2.10的Jackson序列化/反序列化功能。澤西島反序列化失敗時異常映射器不工作

我的想法是讓我的REST API總是返回一個標準的JSON錯誤響應。爲此,我有了ExceptionMapper類,它可以爲Jersey應用程序中拋出的任何異常構建適當的json錯誤響應。我也有一個jsp,它生成相同類型的JSON響應,我在web.xml中將其註冊爲錯誤頁面,其中包含可能在Jersey加載之前發生的所有錯誤。

但在這既不是我的異常映射器也不是我的JSON生產的jsp正在一個情況,那就是發送一個壞建制JSON的POST REST端點剛剛返回以下消息時:

HTTP/1.1 400 Bad Request 
Server: Apache-Coyote/1.1 
Access-Control-Allow-Origin: * 
Access-Control-Allow-Methods: GET, POST, DELETE, PUT 
Content-Type: text/plain 
Content-Length: 210 
Date: Tue, 24 Jun 2014 22:14:11 GMT 
Connection: close 

Can not deserialize instance of com.example.rest.User[] out of START_OBJECT token 
at [Source: [email protected]; line: 1, column: 1] 

我如何讓澤西返回我的自定義錯誤響應,而不是這個?

UPDATE:

基於由@Lucasz答案,我做更多的研究,發現有包com.fasterxml.jackson.jaxrs.base(https://github.com/FasterXML/jackson-jaxrs-providers/tree/master/base/src/main/java/com/fasterxml/jackson/jaxrs/base)JsonMappingExceptionMapper裏面定義了兩個異常映射器和JsonParseExceptionMapper似乎隱藏我的自定義映射器。

我該如何註銷這些映射器?

這是我當前如何註冊映射器:

@ApplicationPath("/") 
public class MyApp extends ResourceConfig{ 
    public SyntheticAPIApp() { 
     packages("com.example.resource", "com.example.mapper"); 
     register(org.glassfish.jersey.jackson.JacksonFeature.class); 
    } 
} 
+0

通常,無效的JSON會觸發500內部服務器錯誤響應。它看起來像一些異常映射器工作並將JsonParseExcpetion轉換爲400響應,並從異常消息中獲取正文。 –

+0

但我沒有任何生成文本/純文本響應的異常映射器,似乎有人攔截了該異常,因爲我甚至沒有在日誌中看到它 – raspacorp

回答

23

我有一個例外映射器測試,它象下面這樣:

import javax.ws.rs.core.Response; 
import javax.ws.rs.core.Response.Status; 
import javax.ws.rs.ext.ExceptionMapper; 
import javax.ws.rs.ext.Provider; 

import com.fasterxml.jackson.core.JsonProcessingException; 

@Provider 
public class JsonProcessingExceptionMapper implements ExceptionMapper<JsonProcessingException>{ 

     public static class Error { 
      public String key; 
      public String message; 
     } 

     @Override 
     public Response toResponse(JsonProcessingException exception) { 
      Error error = new Error(); 
      error.key = "bad-json"; 
      error.message = exception.getMessage(); 
      return Response.status(Status.BAD_REQUEST).entity(error).build(); 
     } 
} 

和它的工作。


更新:改變JsonParseException到JsonProcessingException(更一般的)


UPDATE2: 爲了避免註冊不需要的映射器替換

register(org.glassfish.jersey.jackson.JacksonFeature.class); 

register(com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider.class); 

看看JacksonFeature的源代碼,你就會明白髮生了什麼。

+0

您使用的是什麼版本的Jersey和jackson提供程序?我在jersey-media-json-jackson庫中使用球衣2.10。我的方法是接收一個User對象的數組作爲輸入,例如它會接受[{「name」:「John」,...}],但會失敗,如{「name」:「John」,...} ,你的方法是否也接收數組? – raspacorp

+0

@raspacorp我用澤西島2.9.1和jackson-jaxrs-json-provider 2.3.3 –

+0

@raspacorp對它進行了測試我試圖發送一個單一的對象給一個接受列表的方法,而我的映射器沒有工作,但原因是拋出了一個不同的異常(JsonMappingException)。我改變了我的映射器接受JsonProcessingException(基類爲JsonParseException和JsonMappingException),然後它正常工作。 –

1

我有同樣的問題,以前的答案讓我找到了解決方案,但是並沒有爲我分配當前的澤西島(2.22)。起初,我需要使用org.glassfish.jersey.spi.ExtendedExceptionMapper,如https://jersey.java.net/documentation/latest/representations.html中所述。

此外,新澤西州正在檢查異常映射器,這是儘可能接近到拋出的異常(從org.glassfish.jersey.internal.ExceptionMapperFactory):

for (final ExceptionMapperType mapperType : exceptionMapperTypes) { 
     final int d = distance(type, mapperType.exceptionType); 
     if (d >= 0 && d <= minDistance) { 
      final ExceptionMapper<T> candidate = mapperType.mapper.getService(); 

      if (isPreferredCandidate(exceptionInstance, candidate, d == minDistance)) { 
       mapper = candidate; 
       minDistance = d; 
       if (d == 0) { 
        // slight optimization: if the distance is 0, it is already the best case, so we can exit 
        return mapper; 
       } 
      } 
     } 
    } 

因此我需要準確地映射例外,而不是更一般的異常。

最後,我的供應商如下所示:

@Provider 
public final class JsonParseExceptionExceptionHandler implements ExtendedExceptionMapper<JsonParseException> { 
    @Override 
    public Response toResponse(final JsonParseException exception) { 
     exception.printStackTrace(); 
     return Response.status(Response.Status.BAD_REQUEST).entity("JSON nicht in korrektem Format.").build(); 
    } 

    @Override 
    public boolean isMappable(final JsonParseException arg0) { 
     return true; 
    } 
} 
+0

這將工作不可預知,如http://stackoverflow.com/questions/15989212/overriding-included-球衣提供商 解決方案是擺脫bridge jersey-media-json-jackson,並手動註冊「com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider.class」,就像任何其他提供商一樣。 – genobis

1

我用 「傑克遜 - JAXRS JSON的提供商2.8.8」 和JAX-RS 2.0

應用類 - 您需要註冊您的ExceptionMapper實現類:

@ApplicationPath("pathApplication") 
public class ApplicationConfiguration extends Application{ 


    @Override 
    public Set<Class<?>> getClasses() { 

     Set<Class<?>> resources = new HashSet<>(); 
     resources.add(YourJAXRSClass.class); 
     resources.add(JsonJacksonEM.class); //ExceptionMapper class implementation 
     //others resources that you need... 
     return resources; 

    } 


} 

ExceptionMapper類實現:

@Provider 
public class JsonJacksonEM implements ExceptionMapper<JsonParseException>{ 


    @Override 
    public Response toResponse(JsonParseException exception) { 
     //you can return a Response in the way that you want! 
     return Response.ok(new YourObject()).build(); 
    } 


} 
0

我有同樣的問題和解決重寫ExceptionMapper。完善!我需要做的還有一件額外的事情,那就是如何爲我的應用程序重寫JacksonProvider(我不知道它是否與我使用的Jersey版本有關 - - 2.19)。這是我的web.xml部分,它覆蓋它:

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