Switch raises NoClassDefFoundError in tomcat using undefined inner classes

I have a very simple listing

my.package.data.util

public enum Mode { SQLEXPORT, PREVIEW, PRINT } 

What is used in another class, since enumerations 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 compiled into a jar file.

Then the web project uses this library (placed in the WEB-INF/lib folder). But, when the time comes to use this library and, in particular, this switch, NoClassDefFoundError appears:

NoClassDefFoundError: my / package / program / ComponentController $ 1

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

This is something that I cannot understand at several levels:

  • Why is Java trying to load the inner class (as seen at $1 ). There is no inner class in the ComponentController , and it has never been.
  • Why does Java think the switch uses this inner class as an argument
  • If the class my.package.data.util.Mode disappeared.

What's going on here?


Additional information is not in the original question

  • ComponentController extends another class, SessionBuilder . This class also has no inner classes.

I decompiled ComponentController using javap and tried to find interesting things in the resulting byte code.

It looks like there really is 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 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 transition 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 research on issues related to Rich caused something interesting: the jar built from the library project differs by the local installation of tomcat and the one used to create the jar for the production server:

Left: jar in WEB-INF/lib via local tomcat using eclipse, right: jar , like ANT built

Jar diff

Now it seems that the build process used by eclipse when publishing to the local tomcat is different from what ANT does (this is AFAIK just a simple javac call)


Ok, now I just copied the jar created by ANT to the local WEB-INF/lib cats, 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 an error report in eclipse and report any news.

+6
source share
2 answers

In accordance with this question:

... Sun Javac 1.6 creates an extra synthetic class every time you use the Enum switch.

And in accordance with this question you are not alone.

+6
source

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

0
source

Source: https://habr.com/ru/post/983634/


All Articles