繁体   English   中英

带有Java的AWS Lambda抛出由ClassNotFoundException引起的NoClassDefFoundError,该异常未在本地抛出

[英]AWS Lambda with java throwing NoClassDefFoundError caused by ClassNotFoundException which isn't thrown locally

我最近开始使用带有Java的AWS Lambda。

一直很好,直到我开始使用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构建。

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

摘自Dagger仓库

/*
 * 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 ,它将正常运行。

这都是由于我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:

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
  """
)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM