特定类

时间:2016-04-02 08:26:13

标签: java exception-handling jersey dropwizard

我有资源类,它本身与内部服务进行对话。此资源用作服务的rest 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端点执行完全相同的异常处理。我可以为此特定资源执行某种异常映射,以便我可以将所有处理逻辑和日志记录放在那里吗? 我知道我可以为球衣中的特定异常构建一个映射器,但这对于整个模块而言不是一个单独的类。

2 个答案:

答案 0 :(得分:3)

为什么不将异常处理分解为私有方法?

@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();
    }
}

答案 1 :(得分:3)

您无法向资源方法注册ExceptionMapper。我通过实施DynamicFeature来寻找自定义注释,然后尝试使用ExceptionMapper注册自定义FeatureContext来尝试此操作。

结果是幻想破灭:
WARNING: The given contract (interface javax.ws.rs.ext.ExceptionMapper) of class path.to.CustomExceptionMapper provider cannot be bound to a resource method.

可能不起作用:
<击>但是......

<击>

对于资源类,这实际上很简单。只需在ExceptionMapper内为您的资源类注册ResourceConfig即可。对我来说,它看起来像:

@ApplicationPath("/")
public class ApplicationResourceConfig extends ResourceConfig {
    public ApplicationResourceConfig() {
        // [...]
        register(YourExceptionMapper.class, YourResource.class);
        // [...]
    }
}

因此,如果你可以在资源类级别上使用它,那就这样做吧。

否则你可能需要使用Aspects (但我没有看到任何理由这样做) 。例如:

方面

@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配置。这适用于none static下的path.to.resources方法,这些方法返回Response并使用HandleMyOwnException注释进行了语音处理。

HandleMyOwnException

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HandleMyOwnException {}

ResourceMethod

@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>

度过美好的一天!

EDITED

〜添加了更完整的pom.xml配置
〜更正了ResourceAspect中注释的缺失路径