仅在开发模式下播放框架 java.lang.NoClassDefFoundError

Posted

技术标签:

【中文标题】仅在开发模式下播放框架 java.lang.NoClassDefFoundError【英文标题】:Play framework java.lang.NoClassDefFoundError only in dev mode 【发布时间】:2013-09-18 17:33:52 【问题描述】:

我正在使用带有 play framework 2.1.3 的 protobufs 没有问题。然后我需要将 protobufs 转换为 JSON,所以我包含了

"com.googlecode.protobuf-java-format" % "protobuf-java-format" % "1.2"

在 Build.scala 中。

试图将任何 protobuf 转换为 JSON 使用

JsonFormat.printToString(message);

这会导致在开发模式下运行时出现以下错误(从 play run 开始)

play.api.Application$$anon$1: Execution exception[[RuntimeException: java.lang.NoClassDefFoundError: com/google/protobuf/InvalidProtocolBufferException]]
...
Caused by: java.lang.NoClassDefFoundError: com/google/protobuf/InvalidProtocolBufferException
...
Caused by: java.lang.ClassNotFoundException: com.google.protobuf.InvalidProtocolBufferException
at java.net.URLClassLoader$1.run(URLClassLoader.java:202) ~[na:1.6.0_51]
at java.security.AccessController.doPrivileged(Native Method) ~[na:1.6.0_51]
at java.net.URLClassLoader.findClass(URLClassLoader.java:190) ~[na:1.6.0_51]
at java.lang.ClassLoader.loadClass(ClassLoader.java:306) ~[na:1.6.0_51]
at java.lang.ClassLoader.loadClass(ClassLoader.java:247) ~[na:1.6.0_51]
at sbt.PlayCommands$$anonfun$53$$anonfun$55$$anon$2.loadClass(PlayCommands.scala:535) ~[na:na]

如果在生产模式下开始播放,我没有任何错误。

如果我将 protobuf-java-format 的源代码放在我的应用程序文件夹中,我已经能够让它在开发模式下工作。作为一个临时解决方案,这是可行的,但我想知道处理这个问题的正确方法。

附加信息: 根据下面的建议,我检查了播放类路径、播放依赖项并搜索了我的系统,但我只包含了一份 jar 副本。

我可以毫无问题地运行:

Exception e = new InvalidProtocolBufferException()

当我尝试使用 protobuf-java-format 库中的任何静态方法时,会抛出 NoClassDefFoundError。例如:

XmlFormat.printToString(message)

在开发模式下不工作,但在生产模式下工作(播放开始)。有趣的是,它说它找不到的类是不同的:

[RuntimeException: java.lang.NoClassDefFoundError: com/google/protobuf/Message]

我在其他地方使用 protobuf 库中的方法没有问题,所以我知道它们被包含在类路径中。

从谷歌,我已经能够找到另一个有类似问题的实例: https://groups.google.com/forum/#!msg/play-framework/i0RNcu8PZOY/J7cy18xsg3oJ

我无法弄清楚如何重构代码以使其正常工作。

【问题讨论】:

【参考方案1】:

您确定该类存在于 1.2 中吗?我看到它存在于 2.3 版中。

http://grepcode.com/file/repo1.maven.org/maven2/com.google.protobuf/protobuf-java/2.3.0/com/google/protobuf/InvalidProtocolBufferException.java

这听起来像是一个类加载器问题,那么 protobuf-java-format jar 位于一个类加载器中,而无法访问另一个 jar。最好的办法是在您运行应用程序时确保这个 jar 和另一个 protobuf jar 在同一个目录中结束,这样它们就在同一个类加载器中。

您可以做的其他事情是在每个类中调用 class 并获取类加载器,并通过获取类加载器的父级以及查看类加载器层次结构的样子来鬼混。

调试时另一个非常有用的方法是 XXXXX.class.getProtectionDomain().getCodeSource().getLocation()

将 XXXXX 替换为 protobuf 中存在的类,例如您的类加载没有问题且 protobuf-java-format 加载有问题的异常类,以及 protobuf-java-format 中的任何类。这将告诉您 JVM 从哪里加载这两个 jar。

【讨论】:

我将 2.3 用于 protobuf 库。 Protobuf java format 是一个单独的项目,用于将 protobuf 序列化为 JSON、XML 或 html 然后简化问题...取出 protobuf-java-format 并添加类似 Exception e = new InvalidProtocolBufferException() 之类的代码,看看它是否首先有效。您如何包含 jar 并且您确定类路径上没有多个版本?确保在文件系统中搜索所有 *.jar 并确认您没有两个版本。 试图包含所有建议的详细信息。我用详细信息编辑了上面的帖子 似乎是类加载器问题。当两个库的包含方式不同时,就会出现问题。例如,如果我在 lib 文件夹中包含 1 个项目,或者将其源代码放在 app 文件夹中,并使用 Build.scala 包含另一个项目,那么我能够在开发模式下始终如一地产生错误。如果我以相同的方式包含两个项目,则在开发模式下不会产生错误。 是的,听起来差不多。一直在发生。上面的代码是如何调试这样的情况,尤其是 ProtectionDomain 的东西。如果它们位于 java 中的不同目录中,则它们很可能以不同的方式加载到不同的类加载器中。通常其中一个目录在另一个目录之上,是每个人都可以访问的父类加载器,另一个是隔离可能使用不同版本的 3rd 方库的不同应用程序。

以上是关于仅在开发模式下播放框架 java.lang.NoClassDefFoundError的主要内容,如果未能解决你的问题,请参考以下文章

我的 iPhone 视频仅在纵向模式下播放

在生产模式下播放框架2.3.8混合内容

仅在 LandscapeLeft 和 LandscapeRight 之间旋转

播放框架2:内存数据库中的h2 mysql兼容模式:转义字符

typescript 仅在开发模式下抛出错误。

我需要在生产模式下运行预编译吗?还是为我做的(播放框架 1.2.6)