switch使用未定义的内部类在tomcat中导致NoClassDefFoundError

时间:2015-03-11 09:26:15

标签: java tomcat

我有一个非常简单的枚举

my.package.data.util

public enum Mode
{
    SQLEXPORT, PREVIEW, PRINT
}

应该使用另一个类作为枚举使用

my.package.program.ComponentController

switch (_mode) { // line 278, _mode is of type my.package.data.util.Mode
case PREVIEW:
    // Do thing for preview
    break;
case SQLEXPORT:
    // Do thing for SQL
    break;
case PRINT:
    // Do thing for print
    break;
default:
    throw new IllegalArgumentException();
}

这两个类位于同一个项目中,并编译为jar文件。

然后,一个Web项目正在使用此库(放在WEB-INF/lib文件夹中)。但是,当需要使用此库时,尤其是那个开关时,会出现NoClassDefFoundError

  

NoClassDefFoundError:my / package / program / ComponentController $ 1

     

at my.package.program.ComponentController.doCall(ComponentController.java:278)

这是我在几个层面上无法理解的:

  1. 为什么Java尝试加载内部类(由$1可见)。 ComponentController中没有内部类,也从来没有。
  2. 为什么Java认为交换机使用此内部类作为其参数
  3. my.package.data.util.Mode班级消失的地方
  4. 这里发生了什么?


    不在原始问题中的其他信息

    • ComponentController扩展了另一个类SessionBuilder。这个类也没有内部类

    我使用ComponentController反编译了javap,并试图在结果字节代码中找到有趣的东西。

    字节代码中确实存在内部类:

    public class my.package.program.ComponentController extends my.other.package.SessionBuilder
      SourceFile: "ComponentController.java"
      InnerClasses:
           static #192 of #2; //class my/package/program/ComponentController$1 of class my/package/program/ComponentController
    

    只要引用my.package.data.util.Mode,就会使用此类:

    #192 = Class              #486          //  my/package/program/ComponentController$1
    #193 = Utf8               
    #194 = Utf8               InnerClasses
    #195 = Utf8               _mode
    #196 = Utf8               Lmy/package/data/util/Mode;
    

    而且,当切换实际发生时:

    183: getstatic     #102                // Field my/package/program/ComponentController$1.$SwitchMap$my$package$data$util$Mode:[I
    186: aload_0       
    187: getfield      #5                  // Field _mode:Lmy/package/data/util/Mode;
    190: invokevirtual #103                // Method my/package/data/util/Mode.ordinal:()I
    193: iaload        
    194: tableswitch   { // 1 to 3
       1: 220
       2: 335
       3: 440
       default: 516
    }
    

    Rich 链接的问题的进一步调查产生了一些有趣的东西:库项目中构建的jar在本地tomcat安装和用于生成{{1}的安装中有所不同}对于生产服务器:

    左:jar中的jar通过eclipse的本地tomcat,右:WEB-INF/lib由ANT构建

    JAR Diff

    现在看来,eclipse在发布到本地tomcat时使用的构建过程与ANT所做的不同(AFAIK只是一个简单的jar调用)


    好吧,现在我只是将ANT创建的javac复制到本地tomcats jar中,一切正常。当然,这意味着在库项目中的每次更改之后,我都必须手动将新的WEB-INF/lib复制到我的tomcat库。

    我在eclipse上将其作为错误报告提交,并将报告任何新闻。

2 个答案:

答案 0 :(得分:6)

根据this问题:

  

...每次在Enum上使用开关时,Sun的Javac 1.6都会创建一个额外的合成类。

根据this问题,你并不孤单。

答案 1 :(得分:1)

根据我的经验,问题是这个新类不是由Eclipse部署的,而是在构建过程中生成的。