Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

switch causes NoClassDefFoundError in tomcat using undefined inner classes

Tags:

java

tomcat

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:

  1. Why Java tries to load an inner class (as visible by the $1). There is no inner class present in ComponentController, and never has been.
  2. Why Java thinkgs the switch is using this internal class as its argument
  3. 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

JAR Diff

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.

like image 262
F.P Avatar asked Mar 11 '15 09:03

F.P


2 Answers

According to this question:

...Sun's Javac 1.6 creates an additional synthetic class each time you use a switch on an Enum.

And according to this question you aren't alone.

like image 191
Rich Avatar answered Oct 26 '22 12:10

Rich


From my experience, the problem is that this new class is not deployed by Eclipse, but it is generated in the build process.

like image 27
Jose Manuel Gomez Alvarez Avatar answered Oct 26 '22 10:10

Jose Manuel Gomez Alvarez