特定 class 的异常 Handling/Mapping
Exception Handling/Mapping for a particular class
我有资源 class,它本身与内部服务对话。此资源充当服务的休息 API。服务层可以抛出意外异常,因此资源应该处理那些已处理的意外异常并记录下来。我正在使用 dropwizard 框架,它又使用球衣。事情是这样的。
@PATH(/user)
@GET
public Response getUser(@QueryParam("id") String userId) {
assertNotNull(userId);
try {
User user = service.getUser(userId);
return Response.ok(user).build();
}
catch (MyOwnException moe) { //basically 400's
return Response.status(400).entity(moe.getMsg()).build();
}
catch (Exception e) { //unexpected exceptions
logger.debug(e.getMessage);
return Response.status(500).entity(moe.getMsg()).build();
}
}
这里的问题是我必须为每个 REST api 端点执行完全相同的异常处理。我可以为这个特定资源做某种异常映射,以便我可以将所有处理逻辑和日志记录放在那里吗?
我知道我可以为球衣中的特定异常构建映射器,但那是针对整个模块的,而不是单个 class.
为什么不将异常处理分解为私有方法?
@PATH(/user)
@GET
public Response getUser(@QueryParam("id") String userId) {
assertNotNull(userId);
return handleExceptions(() -> {
User user = service.getUser(userId);
return Response.ok(user).build();
});
}
private Response handleExceptions(Callable<Response> callable) {
try {
return callable.call();
}
catch (MyOwnException moe) { //basically 400's
return Response.status(400).entity(moe.getMsg()).build();
}
catch (Exception e) { //unexpected exceptions
logger.debug(e.getMessage);
return Response.status(500).entity(e.getMessage()).build();
}
}
请注意,您无法将 ExceptionMapper
注册到资源方法。我已经通过实现 DynamicFeature
来尝试此操作,该 DynamicFeature
正在寻找自定义注释,然后尝试使用 FeatureContext
.
注册自定义 ExceptionMapper
结果令人失望:
WARNING: The given contract (interface javax.ws.rs.ext.ExceptionMapper) of class path.to.CustomExceptionMapper provider cannot be bound to a resource method.
可能不起作用:
但是...
对于资源 class 这实际上很容易。只需在 ResourceConfig
中为资源 class 注册 ExceptionMapper
。对我来说它看起来像:
@ApplicationPath("/")
public class ApplicationResourceConfig extends ResourceConfig {
public ApplicationResourceConfig() {
// [...]
register(YourExceptionMapper.class, YourResource.class);
// [...]
}
}
因此,如果您可以在资源 class 级别上使用它,那么就这样做吧。
否则您可能需要使用方面 (但我看不出有任何理由这样做)。示例:
看点
@Aspect
public class ResourceAspect {
Logger logger = [...]
private static final String RESOURCE = "execution(public !static javax.ws.rs.core.Response path.to.resources..*(..)) && @annotation(path.to.HandleMyOwnException)";
@Around(RESOURCE)
public Object translateRuntimeException(ProceedingJoinPoint p) throws Throwable {
try {
return p.proceed();
} catch (MyOwnException moe) {
return Response.status(400).entity(moe.getMsg()).build();
} catch (Exception e) { //unexpected exceptions
logger.debug(e.getMessage);
return Response.status(500).entity(e.getMessage()).build();
}
}
}
请注意,RESOURCE
配置。此处它适用于 path.to.resources
下的 none static
方法,它返回 Response
并使用 HandleMyOwnException
注释进行注释。
HandleMyOwnException
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HandleMyOwnException {}
资源方法
@GET
@PATH("/user")
@HandleMyOwnException
public Response getUser(@QueryParam("id") String userId) {
assertNotNull(userId);
return Response.ok(service.getUser(userId)).build();
}
pom.xml
<!-- deps -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.2</version> <!-- or newer version -->
</dependency>
<!-- build plugins -->
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<showWeaveInfo>true</showWeaveInfo>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<versionRange>[1.7,)</versionRange>
<goals>
<goal>compile</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
<plugins>
<pluginManagement>
祝你有愉快的一天!
已编辑
~添加了更完整的pom.xml配置
~ 更正了 ResourceAspect
中注释的缺失路径
我有资源 class,它本身与内部服务对话。此资源充当服务的休息 API。服务层可以抛出意外异常,因此资源应该处理那些已处理的意外异常并记录下来。我正在使用 dropwizard 框架,它又使用球衣。事情是这样的。
@PATH(/user)
@GET
public Response getUser(@QueryParam("id") String userId) {
assertNotNull(userId);
try {
User user = service.getUser(userId);
return Response.ok(user).build();
}
catch (MyOwnException moe) { //basically 400's
return Response.status(400).entity(moe.getMsg()).build();
}
catch (Exception e) { //unexpected exceptions
logger.debug(e.getMessage);
return Response.status(500).entity(moe.getMsg()).build();
}
}
这里的问题是我必须为每个 REST api 端点执行完全相同的异常处理。我可以为这个特定资源做某种异常映射,以便我可以将所有处理逻辑和日志记录放在那里吗? 我知道我可以为球衣中的特定异常构建映射器,但那是针对整个模块的,而不是单个 class.
为什么不将异常处理分解为私有方法?
@PATH(/user)
@GET
public Response getUser(@QueryParam("id") String userId) {
assertNotNull(userId);
return handleExceptions(() -> {
User user = service.getUser(userId);
return Response.ok(user).build();
});
}
private Response handleExceptions(Callable<Response> callable) {
try {
return callable.call();
}
catch (MyOwnException moe) { //basically 400's
return Response.status(400).entity(moe.getMsg()).build();
}
catch (Exception e) { //unexpected exceptions
logger.debug(e.getMessage);
return Response.status(500).entity(e.getMessage()).build();
}
}
请注意,您无法将 ExceptionMapper
注册到资源方法。我已经通过实现 DynamicFeature
来尝试此操作,该 DynamicFeature
正在寻找自定义注释,然后尝试使用 FeatureContext
.
ExceptionMapper
结果令人失望:
WARNING: The given contract (interface javax.ws.rs.ext.ExceptionMapper) of class path.to.CustomExceptionMapper provider cannot be bound to a resource method.
可能不起作用:
但是...
对于资源 class 这实际上很容易。只需在 ResourceConfig
中为资源 class 注册 ExceptionMapper
。对我来说它看起来像:
@ApplicationPath("/")
public class ApplicationResourceConfig extends ResourceConfig {
public ApplicationResourceConfig() {
// [...]
register(YourExceptionMapper.class, YourResource.class);
// [...]
}
}
因此,如果您可以在资源 class 级别上使用它,那么就这样做吧。
否则您可能需要使用方面 (但我看不出有任何理由这样做)。示例:
看点
@Aspect
public class ResourceAspect {
Logger logger = [...]
private static final String RESOURCE = "execution(public !static javax.ws.rs.core.Response path.to.resources..*(..)) && @annotation(path.to.HandleMyOwnException)";
@Around(RESOURCE)
public Object translateRuntimeException(ProceedingJoinPoint p) throws Throwable {
try {
return p.proceed();
} catch (MyOwnException moe) {
return Response.status(400).entity(moe.getMsg()).build();
} catch (Exception e) { //unexpected exceptions
logger.debug(e.getMessage);
return Response.status(500).entity(e.getMessage()).build();
}
}
}
请注意,RESOURCE
配置。此处它适用于 path.to.resources
下的 none static
方法,它返回 Response
并使用 HandleMyOwnException
注释进行注释。
HandleMyOwnException
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HandleMyOwnException {}
资源方法
@GET
@PATH("/user")
@HandleMyOwnException
public Response getUser(@QueryParam("id") String userId) {
assertNotNull(userId);
return Response.ok(service.getUser(userId)).build();
}
pom.xml
<!-- deps -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.2</version> <!-- or newer version -->
</dependency>
<!-- build plugins -->
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<showWeaveInfo>true</showWeaveInfo>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<versionRange>[1.7,)</versionRange>
<goals>
<goal>compile</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
<plugins>
<pluginManagement>
祝你有愉快的一天!
已编辑
~添加了更完整的pom.xml配置
~ 更正了 ResourceAspect