Eclipse, Gradle, Lombok und seltsame ClassNotFoundException
, NoSuchMethodError
und NoSuchFieldError
Disclaimer: ich kann es bisher nicht reproduzieren, das Problem hat aber bereits einige Stunden gekostet. Drei Mal.
Die Voraussetzungen:
- Eclipse
- ein Java-Projekt mit Gradle-Buildskript und Maven-typischem Layout
- evtl. das lombok-Plugin
Die Symptome
- Nach erfolgreichem Import in Eclipse via Gradle-plugin (“Import”->“Existing Gradle Project”) läuft nichts. Das Projekt mag gut und fehlerfrei aussehen, oder auch nicht, spätestens zur Laufzeit hagelt es
ClassNotFoundException
,NoSuchFieldError
oder ähnliche Exceptions. - Es lässt sich innerhalb von Eclipse nicht reparieren (man kann das ganze Projekt manuell konfigurieren, aber das ist nicht der Weg).
- Ein ‘gradle build’ auf der Kommandozeile hat keine Probleme.
Ursachen
Was man dann herausfindet, war mir nur teilweise bekannt:
- Eclipse kompiliert normalerweise nicht über die Gradle-Tasks, im Gegensatz zu etwa IntelliJ.
- Eclipse kompiliert normalerweise nach ./bin/default.
- Das Gradle-plugin konfiguriert Projekte Maven-ähnlich mit Output nach ./bin/main und ./bin/test (aber nicht: build/main und build/test).
- ./bin/default bleibt der “Default output folder”.
- Nachdem das Projekt erfolgreich konfiguriert ist, löscht ein “Project”->“Clean” in Eclipse zwar bin/main und bin/test, aber nicht bin/default. Ok, da wurde ja auch nichts mehr hinkompiliert(?).
- ./bin/default ist für Eclipse weiterhin im Classpath (und Dateien dort überschreiben zufällig solche in ./bin/main).
- ‘gradle clean’ kümmert sich sinnvollerweise gar nicht um die Eclipse ./bin/-Folder.
Wenn man dann weiter sucht, finden sich in ./bin/default einige .class-Files, die vermutlich irgendwann mal mit irgendeinem Stand kompiliert wurden, der nicht mehr passt.
Die Lösung ist also: ./bin/default löschen. Problem solved.
Meine Vermutung ist, dass es beim Import eines Gradle-Projekts nach Eclipse irgendwo eine Art Race Condition gibt. Eclipse versucht schonmal, irgendwas zu kompilieren, ohne dass das Setup vollständig ist. Im Ergebnis bleiben alte .class-Files in ./bin/default liegen und es ist, nun ja, dann halt kaputt.
Evtl. ist auch das Lombok-Plugin beteiligt, ohne habe ich das Problem nie beobachtet.
Aber wie gesagt, reproduzieren kann ich es auch nicht, und drei Fälle sind zu wenig, das ist geraten. Vielleicht hilft es trotzdem jemandem.