2015-03-11 10 views
6

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:

  1. Dlaczego Java próbuje załadować klasa wewnętrzna (widoczna po $1). Nie ma klasy wewnętrznej obecnej w ComponentController i nigdy nie było.
  2. Dlaczego Java thinkgs przełącznik jest przy użyciu tej wewnętrznej klasy jako argument
  3. 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

JAR Diff

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.

+1

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

+0

Ponieważ linia 278 to 'switch (_mode)', dodam tę informację do kodu w pytaniu –

+0

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

Odpowiedz

6

Według this pytanie:

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

A według this pytanie nie jesteś sam.

+0

OK, widzę, jak można to zrobić. Następnie pojawia się pytanie: Dlaczego to nie działa w moim przypadku? –

0

Z mojego doświadczenia wynika, że ​​ta nowa klasa nie jest wdrażana przez Eclipse, ale generowana jest w procesie budowania.