关于异常原因的 Jersey Exception Mapper
Jersey Exception Mapper on exception cause
我正在编写一个 Jersey 应用程序,我使用 Hibernate 作为后端。我需要通过异常映射器捕获一个特定错误,该错误由底层 JDBC 驱动程序 (MySqlDataTruncation
) 抛出。不幸的是,Hibernate 接受了这个异常并将它包装在一个通用的 HibernateException
.
中
我已经有一个通用的 HibernateException
映射器,它 return 是一个 500 错误。调用它来映射所有 HibernateException
s,包括由 MySqlDataTruncation
异常引起的。
我想注册一个新的异常映射器,它应该处理由 MySqlDataTruncation
错误和 return 400 错误引起的 HibernateException
s。注册一个 ExceptionMapper<MySqlDataTruncation>
似乎没有捕捉到任何我想要的异常。
在 ExceptionMapper<HibernateExceeption>
中检查原因似乎很麻烦。这是唯一的解决方案吗?
Checking the cause in the ExceptionMapper seems
hacky.
完全没有。原因是通过 public 方法提供的。这是异常概念的一部分,异常可以提供有关其原因的信息。
找出原因。如果需要,甚至可以深入几层。如果您不想在主处理程序中处理 MySqlDataTruncation
,请创建一个单独的 class 并从主处理程序委托给它。
实际上,Jersey 似乎已经预测到了这个确切的问题,并创建了一个系统来有条件地处理 ExceptionMapper
中的一些异常而不是其他异常。虽然在通用异常映射器中检查原因是完全有效的,但这似乎使代码更清晰。
只需让他们的 ExceptionMapper
实现 org.glassfish.jersey.spi.ExtendedExceptionMapper
而不是通常的 javax.ws.rs.ext.ExceptionMapper
接口。
ExtendedExceptionMapper
界面是这样的:
/**
* Extension of a {@link ExceptionMapper exception mapper interface}. The exception mapping
* providers can extend from this interface to add jersey specific functionality to these
* providers.
*
* @author Miroslav Fuksa
*
* @param <T> A type of the exception processed by the exception mapper.
*/
public interface ExtendedExceptionMapper<T extends Throwable> extends ExceptionMapper<T> {
/**
* Determine whether this provider is able to process a supplied exception instance.
* <p>
* This method is called only on those exception mapping providers that are able to
* process the type of the {@code exception} as defined by the JAX-RS
* {@link ExceptionMapper} contract. By returning {@code false} this method can reject
* any given exception instance and change the default JAX-RS exception mapper
* selection behaviour.
* </p>
*
* @param exception exception instance which should be processed.
* @return {@code true} if the mapper is able to map the particular exception instance,
* {@code false} otherwise.
*/
public boolean isMappable(T exception);
}
这个特定案例中的实现可能类似于:
public class MySqlDataTruncationExceptionMapper implements ExtendedExceptionMapper<HibernateException> {
@Override
public boolean isMappable(HibernateException top) {
return top.getCause() instanceof MySqlDataTruncation;
}
@Override
public Response toResponse(HibernateException top) {
MySqlDataTruncation e = (MySqlDataTruncation) top.getCause();
// No possibility of a ClassCastException because we already checked
// that `top.getCause() instanceof MySqlDataTruncation`
// Do stuff with `e` to return a response:
return Response.status(Status.REQUEST_ENTITY_TOO_LARGE).entity(e.getMessage()).build();
}
}
注意:我还没有实际测试过这个(我最后做了其他事情,由于时间限制现在不能改变它),以及使用这个解决方案的 YMMV。
我正在编写一个 Jersey 应用程序,我使用 Hibernate 作为后端。我需要通过异常映射器捕获一个特定错误,该错误由底层 JDBC 驱动程序 (MySqlDataTruncation
) 抛出。不幸的是,Hibernate 接受了这个异常并将它包装在一个通用的 HibernateException
.
我已经有一个通用的 HibernateException
映射器,它 return 是一个 500 错误。调用它来映射所有 HibernateException
s,包括由 MySqlDataTruncation
异常引起的。
我想注册一个新的异常映射器,它应该处理由 MySqlDataTruncation
错误和 return 400 错误引起的 HibernateException
s。注册一个 ExceptionMapper<MySqlDataTruncation>
似乎没有捕捉到任何我想要的异常。
在 ExceptionMapper<HibernateExceeption>
中检查原因似乎很麻烦。这是唯一的解决方案吗?
Checking the cause in the ExceptionMapper seems hacky.
完全没有。原因是通过 public 方法提供的。这是异常概念的一部分,异常可以提供有关其原因的信息。
找出原因。如果需要,甚至可以深入几层。如果您不想在主处理程序中处理 MySqlDataTruncation
,请创建一个单独的 class 并从主处理程序委托给它。
实际上,Jersey 似乎已经预测到了这个确切的问题,并创建了一个系统来有条件地处理 ExceptionMapper
中的一些异常而不是其他异常。虽然在通用异常映射器中检查原因是完全有效的,但这似乎使代码更清晰。
只需让他们的 ExceptionMapper
实现 org.glassfish.jersey.spi.ExtendedExceptionMapper
而不是通常的 javax.ws.rs.ext.ExceptionMapper
接口。
ExtendedExceptionMapper
界面是这样的:
/**
* Extension of a {@link ExceptionMapper exception mapper interface}. The exception mapping
* providers can extend from this interface to add jersey specific functionality to these
* providers.
*
* @author Miroslav Fuksa
*
* @param <T> A type of the exception processed by the exception mapper.
*/
public interface ExtendedExceptionMapper<T extends Throwable> extends ExceptionMapper<T> {
/**
* Determine whether this provider is able to process a supplied exception instance.
* <p>
* This method is called only on those exception mapping providers that are able to
* process the type of the {@code exception} as defined by the JAX-RS
* {@link ExceptionMapper} contract. By returning {@code false} this method can reject
* any given exception instance and change the default JAX-RS exception mapper
* selection behaviour.
* </p>
*
* @param exception exception instance which should be processed.
* @return {@code true} if the mapper is able to map the particular exception instance,
* {@code false} otherwise.
*/
public boolean isMappable(T exception);
}
这个特定案例中的实现可能类似于:
public class MySqlDataTruncationExceptionMapper implements ExtendedExceptionMapper<HibernateException> {
@Override
public boolean isMappable(HibernateException top) {
return top.getCause() instanceof MySqlDataTruncation;
}
@Override
public Response toResponse(HibernateException top) {
MySqlDataTruncation e = (MySqlDataTruncation) top.getCause();
// No possibility of a ClassCastException because we already checked
// that `top.getCause() instanceof MySqlDataTruncation`
// Do stuff with `e` to return a response:
return Response.status(Status.REQUEST_ENTITY_TOO_LARGE).entity(e.getMessage()).build();
}
}
注意:我还没有实际测试过这个(我最后做了其他事情,由于时间限制现在不能改变它),以及使用这个解决方案的 YMMV。