AWS Lambda与java抛出由ClassNotFoundException引起的NoClassDefFoundError,它不会在本地抛出

时间:2016-07-01 02:57:13

标签: java amazon-web-services jar aws-lambda bazel

我最近开始玩AWS Lambda with Java。

一直顺利,直到我开始使用Dagger 2进行注射。

现在Lambda抛出以下错误:

{
  "errorMessage": "dagger/internal/Preconditions",
  "errorType": "java.lang.NoClassDefFoundError",
  "stackTrace": [
    "com.company.server.user.SignUpActionAws.handler(SignUpActionAws.java:27)",
    "sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
    "sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
    "sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
    "java.lang.reflect.Method.invoke(Method.java:498)"
  ],
  "cause": {
    "errorMessage": "dagger.internal.Preconditions",
    "errorType": "java.lang.ClassNotFoundException",
    "stackTrace": [
      "java.net.URLClassLoader.findClass(URLClassLoader.java:381)",
      "java.lang.ClassLoader.loadClass(ClassLoader.java:424)",
      "java.lang.ClassLoader.loadClass(ClassLoader.java:357)",
      "com.company.server.user.SignUpActionAws.handler(SignUpActionAws.java:27)",
      "sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
      "sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
      "sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
      "java.lang.reflect.Method.invoke(Method.java:498)"
    ]
  }
}

但是,在本地运行java -jar myjar.jar时不会发生这种情况。我还使用jar tvf myjar.jar检查了班级在哪里。

我使用Bazel构建。

我检查过的其他问题表明,这可能是由于依赖项不可用,但是,该类的内容没有依赖关系。

取自the Dagger repo

/*
 * Copyright (C) 2016 Google, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package dagger.internal;

/**
 * An adaptation of Guava's {@code com.google.common.base.Preconditions} that is specially tailored
 * to support checks applied in Dagger's generated code.
 */
public final class Preconditions {
  /**
   * Ensures that an object reference passed as a parameter to the calling method is not null.
   *
   * @param reference an object reference
   * @return the non-null reference that was validated
   * @throws NullPointerException if {@code reference} is null
   */
  public static <T> T checkNotNull(T reference) {
    if (reference == null) {
      throw new NullPointerException();
    }
    return reference;
  }

  /**
   * Ensures that an object reference passed as a parameter to the calling method is not null.
   *
   * @param reference an object reference
   * @param errorMessage the exception message to use if the check fails
   * @return the non-null reference that was validated
   * @throws NullPointerException if {@code reference} is null
   */
  public static <T> T checkNotNull(T reference, String errorMessage) {
    if (reference == null) {
      throw new NullPointerException(errorMessage);
    }
    return reference;
  }

  private Preconditions() {}
}

在运行自包含jar时,可能导致AWS在本地环境中出现的问题?

提前致谢

编辑1: 这是最小的BUILD文件:

java_binary(
  name = "bin",
  srcs = glob(["Action.java"]),
  main_class = "com.company.Action",
  deps = [
    "//external:aws-lambda",
    "//external:dagger",
  ]
)

这是WORKSPACE文件:

bind(name = "aws-lambda", actual = "@com_amazonaws_aws_lambda_java_core//jar")
maven_jar(
  name = "com_amazonaws_aws_lambda_java_core",
  artifact = "com.amazonaws:aws-lambda-java-core:1.1.0"
)
bind(name = "dagger", actual = "@com_google_dagger//jar")
maven_jar(
  name = "com_google_dagger",
  artifact = "com.google.dagger:dagger:2.5",
)

这是Action.java(注意,我直接使用Preconditions使其成为最小的实现,在我的实际代码中,它在尝试构建组件时失败):

package com.company;

import com.amazonaws.services.lambda.runtime.Context;

public class Action {
  public static void main(String[] s) {
    Action.handler(null, null);
  }

  public static String handler(String request, Context context) {
    dagger.internal.Preconditions.checkNotNull(new Object(), "Test");
    return null;
  }
}

如果您运行bazel build //src/main/com/company:bin_deploy.jar并将其上传到AWS Lambda函数,它将失败。如果您在本地运行bazel run //src/main/com/company:binjava -jar bazel-bin/src/main/com/company/bin_deploy.jar,它将正常运行。

1 个答案:

答案 0 :(得分:0)

这完全归功于我的jar里面的dagger文件夹中的权限。所有其他文件夹(例如com,org,mozilla)都有755,但不是dagger文件夹。我解压缩了我的jar,运行了两个命令将目录转换为755,将文件转换为644,然后将其压缩回来。

更改权限的命令:

From inside the unzipped directory:
find . -type f -exec chmod 644 {} +
find . -type d -exec chmod 755 {} +

当Bazel构建它时,我不知道为什么它与其他目录不同。但这就是问题所在。

对于未来的Bazel搜索者,以下是我现在正在使用的规则:

genrule(
  name = "target-aws",
  srcs = ["target_deploy.jar"],
  outs = ["target-aws.jar"],
  cmd = """
  unzip -q $< -d t
  cd t
  find . -type f -exec chmod 644 {} +
  find . -type d -exec chmod 755 {} +
  zip ../$@ -q -r .
  rm -rf t
  """
)