由于意外异常导致 Bamboo 构建失败

Bamboo build failure due to unexpected exception

我有一个方法可以从 pdf 文件中删除 trim 框。给定方法的路径参数,我用 JetBrains 的“@NotNull”注释对其进行注释:

Path removeTrimBox(@NotNull Path pdfPath) {
 if (!Files.exists(pdfPath)) {
  throw new IllegalArgumentException(myErrorMessage);
 }
 // code removing the trim box follows
}

我还有这个方法的单元测试,需要一个 IllegalArgumentException:

@Test(expected = IllegalArgumentException.class)
public void removeTrimboxNull() throws Exception {
    PdfTools.removeTrimbox(null);
}

虽然我的 checkstyle 抱怨将 null 参数传递给用 NotNull 注释的参数,但测试 运行s 成功。问题是在我将代码推送到 bamboo 服务器之后,构建 运行 显示红色消息:How should I 'teach' my bamboo server to understand this JetBrains annotation?

java.lang.Exception: Unexpected exception, expected "java.lang.IllegalArgumentException" but was "java.lang.NullPointerException".

我的 bamboo 服务器应该 'teach' 理解这个 JetBrains 注释吗?

编辑

这是 pom:

<dependency>
  <groupId>org.jetbrains</groupId>
  <artifactId>annotations</artifactId>
  <version>13.0</version>
</dependency>

EDIT2

使用 Maven 的 'test' 循环到 运行 测试没有导致 NPE,而 bamboo 仍在抱怨。我使用 Intellij IDEA 14.1.4 和 maven 3.2.3.

来自API doc of @NotNull

Apart from documentation purposes this annotation is intended to be used by static analysis tools to validate against probable runtime errors and element contract violations.

这看起来 @NotNull 并不是要在 运行 时抛出 IllegalArgumentException。这意味着您必须检查自己的参数是否为 null,如果是,则抛出一个 IllegalArgumentException

你运行Maven的'test'循环在什么环境下? IntelliJ Idea 内部?也许 @NotNull 仅在您的 IDE 中执行其 "black magic"?

也许你可以使用 AspectJ to create an aspect that checks for null, that also works in environment other than Idea? The following code is inspired by http://twest-log.blogspot.de/2011/07/merkzettel-notnull-check-mit-aspectj.html 但是因为那里的评论是德语的,所以我稍微修改了一下。去那里看一个更完整的例子:

@Aspect
public class CheckArgumentsAspect {

  /**
   * Pointcut for all methods with at least one parameter
   * with the {@link NotNull} annotation.
   */
  @Around("execution(* *(..,@NotNull (*),..))")
  public Object checkArgsForMethod(ProceedingJoinPoint joinPoint)
      throws Throwable {
    if (joinPoint.getSignature() instanceof MethodSignature) {
      MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
      Method method = methodSignature.getMethod();
      Class<?>[] parameterTypes = method.getParameterTypes();
      Annotation[][] parameterAnnotationArray = method.getParameterAnnotations();

      checkParameters(joinPoint.getArgs(), parameterTypes, parameterAnnotationArray, methodSignature.toLongString());
    }
    return joinPoint.proceed();
  }

  private void checkParameters(Object[] parameter, Class<?>[] parameterTypes, Annotation[][] parameterAnnotationArray, String signature) {
    for (int i = 0; i < parameterTypes.length; i++) {
      Annotation[] parameterAnnotations = parameterAnnotationArray[i];
      for (Annotation annotation : parameterAnnotations) {
        if (annotation instanceof NotNull) {
          checkNotNull(parameter[i], parameterTypes[i], i, ((NotNull) annotation).parameterName(), signature);
        }
      }
    }
  }

  private void checkNotNull(Object parameter, Class<?> parameterType, int parameterIndex, String parameterName, String signature) {
    if (parameter == null) {
      if (StringUtils.isBlank(parameterName)) {
        parameterName = "-";
      }
      String longMsg = MessageFormat.format(
          "Error: parameter no.{0} (name: {1}, type: {2}) of {3} is null", parameterIndex + 1, parameterName, parameterType.getName(), signature);
      throw new IllegalArgumentException(longMsg);
    }
  }
}

@NotNull 注释只是一个标记,它不会反映在运行时中。开发人员应该处理 NullPointerException 并提供必要的空检查。

你为此编写任何AspectJ代码真的很麻烦和耗时,这当然对你没有帮助,除非你再次编写逻辑来检查变量是否为空。

许多人将 @NotNull 注释与其不存在的 运行 时间行为混淆。与其他所有开发人员一样,手动处理 NPE :)