I have a very simple enumeration
my.package.data.util
public enum Mode
{
SQLEXPORT, PREVIEW, PRINT
}
Which is used in another class as enums should be used
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();
}
These two classes are in the same project and are compiled into a jar
file.
A web project is then using this library (placed into the WEB-INF/lib
folder). But, when the time comes to use this library, and most specifically that switch, a NoClassDefFoundError
occurs:
NoClassDefFoundError: my/package/program/ComponentController$1
at my.package.program.ComponentController.doCall(ComponentController.java:278)
This is something I cannot understand on several levels:
- Why Java tries to load an inner class (as visible by the
$1
). There is no inner class present inComponentController
, and never has been. - Why Java thinkgs the switch is using this internal class as its argument
- Where the
my.package.data.util.Mode
class vanished
What is happening here?
Further information not in the original question
ComponentController
extends another class,SessionBuilder
. This class also has no inner classes
I decompiled the ComponentController
using javap
and tried to find interesting things in the resulting byte code.
It appears that there is indeed an inner class in the byte code:
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
This class is used whenever my.package.data.util.Mode
is referenced:
#192 = Class #486 // my/package/program/ComponentController$1
#193 = Utf8
#194 = Utf8 InnerClasses
#195 = Utf8 _mode
#196 = Utf8 Lmy/package/data/util/Mode;
And also, when the switch actually occurs:
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
}
Further investigation into the questions linked by Rich produced something interesting: The built jar
from the library project differ in the local tomcat installation and the one used to produce the jar
for the production server:
Left: jar in WEB-INF/lib
via local tomcat by eclipse, Right: jar
as built by ANT
It now seems like the build process used by eclipse when publishing to a local tomcat differs from what ANT does (which is AFAIK just a simple javac
call)
Alright, now I just copied the jar
created by ANT into the local tomcats WEB-INF/lib
and everything works fine. Of course, this means that after every change in the library project, I have to manually copy the new jar
to my tomcat lib.
I filed this as a bug report at eclipse and will report back with any news.