JAXRS/Jersey 2 - 验证错误不调用 ExceptionMapper
JAXRS/Jersey 2 - Validation errors does not invoke the ExceptionMapper
使用最新的 Jersey (2.22.1),我已经成功地创建了满足各种需求的自定义验证器。但是我的自定义 ExceptionMapper
(在 web.xml 中注册为 provider
)在发生 ConstraintViolationException 时不会被调用,尽管它被定义为 ExceptionMapper<Throwable>
.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="mywebapp" version="2.5">
<display-name>Some Name - Webapp</display-name>
[...]
<servlet>
<servlet-name>jersey_v2-servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
com.myfirm.web.rest.providers.DefaultExceptionMapper,
com.myfirm.web.rest.endpoints.XxxEndpoint,
com.myfirm.web.rest.endpoints.XxyEndpoint,
com.myfirm.web.rest.endpoints.XyzEndpoint
</param-value>
</init-param>
<init-param>
<param-name>jersey.config.beanValidation.enableOutputValidationErrorEntity.server</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey_v2-servlet</servlet-name>
<url-pattern>/rest/1.0/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jersey_v2-servlet</servlet-name>
<url-pattern>/rest/latest/*</url-pattern>
</servlet-mapping>
[...]
</web-app>
DefaultExceptionMapper
@Provider
public class DefaultExceptionMapper implements ExceptionMapper<Throwable> {
private static final Logger LOG = LoggerFactory.getLogger(DefaultExceptionMapper.class);
@Override
public Response toResponse(Throwable caughtException) {
LOG.warn("Exception caught in the REST layer", caughtException);
Throwable original = caughtException;
// some business logic to convert the exception to a response
// log & return the response
Response response = status(status).entity(entity).build();
return response;
}
@XmlRootElement
public static class Error {
@XmlElement
public String type;
@XmlElement
public String message;
@XmlElement
public String translationKey;
}
}
使用我的调试器,我可以在 class org.glassfish.jersey.server.ServerRuntime 行 596 中看到解析的映射器不是我的,而是 org.glassfish.jersey.server.validation.internal.ValidationExceptionMapper
.
在 ConstraintViolationException
的情况下,我如何告诉 Jersey 使用我的 DefaultExceptionMapper
?
PS: 我试过这里建议的选项:ExceptionMapper not invoked if receiving invalid JSon 没有运气。
将映射器定义为 implements ExceptionMapper<ConstraintViolationException>
使其以某种方式优先于为相同异常类型注册的其他映射器。
我最终得到了 2 个异常映射器,一个用于每个异常,另一个用于 ConstraintViolationException
,两者都扩展了相同的抽象 class.
现在有一个简单的解决方法,就是完全禁用 Jersey 的 bean 验证。这可以通过让您的应用程序 sub class return a 属性 将 ServerProperties.BV_FEATURE_DISABLE 设置为 true 来完成。
例如:
@ApplicationPath("")
public class MyApplication extends Application {
@Override
public Map<String, Object> getProperties() {
return Collections.singletonMap(ServerProperties.BV_FEATURE_DISABLE, true);
}
}
使用最新的 Jersey (2.22.1),我已经成功地创建了满足各种需求的自定义验证器。但是我的自定义 ExceptionMapper
(在 web.xml 中注册为 provider
)在发生 ConstraintViolationException 时不会被调用,尽管它被定义为 ExceptionMapper<Throwable>
.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="mywebapp" version="2.5">
<display-name>Some Name - Webapp</display-name>
[...]
<servlet>
<servlet-name>jersey_v2-servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
com.myfirm.web.rest.providers.DefaultExceptionMapper,
com.myfirm.web.rest.endpoints.XxxEndpoint,
com.myfirm.web.rest.endpoints.XxyEndpoint,
com.myfirm.web.rest.endpoints.XyzEndpoint
</param-value>
</init-param>
<init-param>
<param-name>jersey.config.beanValidation.enableOutputValidationErrorEntity.server</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey_v2-servlet</servlet-name>
<url-pattern>/rest/1.0/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jersey_v2-servlet</servlet-name>
<url-pattern>/rest/latest/*</url-pattern>
</servlet-mapping>
[...]
</web-app>
DefaultExceptionMapper
@Provider
public class DefaultExceptionMapper implements ExceptionMapper<Throwable> {
private static final Logger LOG = LoggerFactory.getLogger(DefaultExceptionMapper.class);
@Override
public Response toResponse(Throwable caughtException) {
LOG.warn("Exception caught in the REST layer", caughtException);
Throwable original = caughtException;
// some business logic to convert the exception to a response
// log & return the response
Response response = status(status).entity(entity).build();
return response;
}
@XmlRootElement
public static class Error {
@XmlElement
public String type;
@XmlElement
public String message;
@XmlElement
public String translationKey;
}
}
使用我的调试器,我可以在 class org.glassfish.jersey.server.ServerRuntime 行 596 中看到解析的映射器不是我的,而是 org.glassfish.jersey.server.validation.internal.ValidationExceptionMapper
.
在 ConstraintViolationException
的情况下,我如何告诉 Jersey 使用我的 DefaultExceptionMapper
?
PS: 我试过这里建议的选项:ExceptionMapper not invoked if receiving invalid JSon 没有运气。
将映射器定义为 implements ExceptionMapper<ConstraintViolationException>
使其以某种方式优先于为相同异常类型注册的其他映射器。
我最终得到了 2 个异常映射器,一个用于每个异常,另一个用于 ConstraintViolationException
,两者都扩展了相同的抽象 class.
现在有一个简单的解决方法,就是完全禁用 Jersey 的 bean 验证。这可以通过让您的应用程序 sub class return a 属性 将 ServerProperties.BV_FEATURE_DISABLE 设置为 true 来完成。
例如:
@ApplicationPath("")
public class MyApplication extends Application {
@Override
public Map<String, Object> getProperties() {
return Collections.singletonMap(ServerProperties.BV_FEATURE_DISABLE, true);
}
}