[英]Jackson JsonParseExceptionMapper and JsonMappingExceptionMapper shadows custom mapper
我的項目使用Spring Boot + Jersey 2。
我為JsonParseException創建了自定義的Jackson映射器,但沒有被調用,而是使用了標准的Jackson JsonParseExceptionMapper。
我的自定義映射器:
package com.rmn.gfc.common.providers;
import ...
@Provider
public class JsonParseExceptionHandler implements ExceptionMapper<JsonParseException> {
@Override
public Response toResponse(JsonParseException exception) {
return Response
.status(Response.Status.BAD_REQUEST)
// entity ...
.build();
}
}
我這樣注冊我的映射器:
@Component
public class OrderServiceResourceConfig extends ResourceConfig {
public OrderServiceResourceConfig() {
packages("com.rmn.gfc.common.providers");
}
}
我確定映射器注冊是可以的,因為此程序包中的其他自定義映射器正在工作,但是Jersey標准的JsonParseExceptionMapper遮蓋了JsonParseException的映射器。
如何在實現中覆蓋標准的Jackson Jackson JsonParseExceptionMapper?
JacksonFeature
JacksonFeature
注冊了傑克遜的例外默認異常映射器如果JacksonJaxbJsonProvider
未注冊。 而這正是您所不想要的。
參見源代碼的相關部分:
// Register Jackson. if (!config.isRegistered(JacksonJaxbJsonProvider.class)) { // add the default Jackson exception mappers context.register(JsonParseExceptionMapper.class); context.register(JsonMappingExceptionMapper.class); ... }
JacksonFeature
如果Spring Boot的JerseyAutoConfiguration
類位於類路徑中,則它將注冊JacksonFeature
。 參見源代碼的相關部分:
@ConditionalOnClass(JacksonFeature.class) @ConditionalOnSingleCandidate(ObjectMapper.class) @Configuration static class JacksonResourceConfigCustomizer { ... @Bean public ResourceConfigCustomizer resourceConfigCustomizer( final ObjectMapper objectMapper) { addJaxbAnnotationIntrospectorIfPresent(objectMapper); return (ResourceConfig config) -> { config.register(JacksonFeature.class); config.register(new ObjectMapperContextResolver(objectMapper), ContextResolver.class); }; } ... }
解決方法是,您可以注冊JacksonJaxbJsonProvider
,然后注冊自定義異常映射器(或僅使用@Provider
進行注釋,以使Jersey自動發現它們):
@Component
public class OrderServiceResourceConfig extends ResourceConfig {
public OrderServiceResourceConfig() {
packages("com.rmn.gfc.common.providers");
register(JacksonJaxbJsonProvider.class);
// Register other providers
}
}
查看文檔中有關JacksonJaxbJsonProvider
:
JSON內容類型提供程序已自動配置為同時使用Jackson和JAXB批注(按優先級順序)。 其他方面與
JacksonJsonProvider
相同。
或者,您可以擺脫jersey-media-json-jackson
工件,而使用jackson-jaxrs-json-provider
。 這樣,您將擺脫JacksonFeature
,然后可以注冊自己的異常映射器。
有人在這個答案中提到過。
請參閱以下來自JAX-RS 2.1規范的報價:
4.1.3優先級
應用程序提供的提供程序使開發人員能夠擴展和定制JAX-RS運行時。 因此,如果需要單個提供程序,則始終應首選由應用程序提供的提供程序,而不是預先打包的提供程序。
應用程序提供的提供程序可以使用
@Priority
進行注釋。 如果兩個或更多提供者是某個任務的候選者,則選擇優先級最高的提供者:在這種情況下,最高優先級被定義為值最低的提供者 。 也就是說,@Priority(1)
高於@Priority(10)
。 如果兩個或多個提供者有資格並且具有相同的優先級,則以與實現相關的方式選擇一個。所有應用程序提供的提供程序的默認優先級是
javax.ws.rs.Priorities.USER
。 關於優先級的一般規則對於過濾器和攔截器是不同的,因為這些提供程序被收集到鏈中。
就像在Kysil Ivan的答案中指出的那樣,編寫您自己的異常映射器,並將其設置為高優先級,例如1
。 如果使用自動發現,只需使用@Provider
和@Priority
對其進行注釋。
@Provider
@Priority(1)
public class JsonParseExceptionMapper implements ExceptionMapper<JsonParseException> {
...
}
如果您手動注冊提供商,則可以為您的提供商設置綁定優先級 :
@ApplicationPath("/")
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(JsonParseExceptionMapper.class, 1);
}
}
我找到了適合我的解決方案。
在自定義映射器上使用javax.annotation.Priority
使其覆蓋Jackson的默認映射器,例如:
@Provider
@Priority(1)
public class JsonParseExceptionHandler implements ExceptionMapper<JsonParseException> {
// ...
}
或,如果通過ResourceConfig注冊JAX-RS組件,則可以這樣指定優先級:
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(JsonMappingExceptionHandler.class, 1);
register(JsonParseExceptionHandler.class, 1);
// ...
}
}
數字越小優先級越高。
javax.ws.rs.Priorities
具有一些用於優先級的預定義常量。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.