Mam bardzo proste wyliczenieprzełącznik powoduje NoClassDefFoundError w tomcat używając niezdefiniowanych klas wewnętrznych
my.package.data.util
public enum Mode
{
SQLEXPORT, PREVIEW, PRINT
}
który jest używany w innej klasy jako teksty stałe powinny być używane
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();
}
Te dwie klasy są w tym samym projekcie i są wkompilowane w plik jar
.
Projekt internetowy korzysta z tej biblioteki (umieszczonej w folderze WEB-INF/lib
). Jednak, gdy przychodzi czas, aby korzystać z tej biblioteki, a najbardziej specyficznie że switcha, NoClassDefFoundError
następuje:
NoClassDefFoundError: my/package/program/ComponentController$1
at my.package.program.ComponentController.doCall(ComponentController.java:278)
To jest coś, czego nie może zrozumieć, na kilku poziomach:
- Dlaczego Java próbuje załadować klasa wewnętrzna (widoczna po
$1
). Nie ma klasy wewnętrznej obecnej wComponentController
i nigdy nie było. - Dlaczego Java thinkgs przełącznik jest przy użyciu tej wewnętrznej klasy jako argument
- gdzie klasa
my.package.data.util.Mode
zniknął
Co się tu dzieje?
Dalsze informacje nie zawarte w pierwotnym pytaniu
ComponentController
rozszerza innej klasy,SessionBuilder
. Ta klasa ma również żadnych wewnętrznych klas
I dekompilowana się ComponentController
użyciu javap
i starał się znaleźć ciekawe rzeczy w otrzymanej kodu bajtowego.
Wydaje się, że rzeczywiście istnieje wewnętrzna klasa w kodu bajtowego:
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
Ta klasa jest używana, gdy my.package.data.util.Mode
odwołuje:
#192 = Class #486 // my/package/program/ComponentController$1
#193 = Utf8
#194 = Utf8 InnerClasses
#195 = Utf8 _mode
#196 = Utf8 Lmy/package/data/util/Mode;
A także, gdy przełącznik faktycznie występuje:
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
}
Dalsze dochodzenie w kwestii połączonych Rich produkowane coś ciekawego: Wbudowany jar
z projektu bibliotecznego różnić w instalacji tomcat lokalnej i tej używanej do produkcji jar
na serwerze produkcyjnym:
Lewicy: słoik WEB-INF/lib
pośrednictwem lokalnego tomcat przez zaćmienie, po prawej: jar
jak zbudowany przez ANT
wydaje się teraz jak proces kompilacji używanej przez zaćmienie podczas publikowania do lokalnego tomcat d iffers od tego, co robi ANT (co jest AFAIK tylko prosty javac
wezwanie)
Dobra, teraz po prostu skopiowane jar
stworzony przez ANT do lokalnych kocury WEB-INF/lib
i wszystko działa poprawnie. Oczywiście oznacza to, że po każdej zmianie w projekcie bibliotecznym muszę ręcznie skopiować nową jar
do mojej biblioteki tomcat.
Złożyłem to jako raport o błędzie w czasie zaćmienia i będę zgłaszał wszelkie nowości.
W jaki sposób powiązano fakt, że ten błąd wynika z tego przełącznika? Myślę, że punktem zainteresowania brakującego kodu w pytaniu jest wiersz 278 pliku ComponentController. – benzonico
Ponieważ linia 278 to 'switch (_mode)', dodam tę informację do kodu w pytaniu –
Czy próbowałeś dekompilować .jar, aby zobaczyć, co zrobił javac? Wygląda na to, że javac przetłumaczył enum - czy jest to jedyne miejsce, w którym jest używane? – Rich