Wybór języka

Ciekawy Przypadek JEPa 443

Update

Sprawa została rozwiązana, polecam przeczytać wpis z rozwiązaniem.

Notatka: Poniżej pozostawiam oryginalny wpis na wypadek, gdyby ktoś jednak napotkał w przyszłości podobny problem. Czasem łatwiej szukać po problemie ;-)

Podczas przygotowywania demek do wykładu co tam w Javie 21 piszczy dla zaprzyjaźnionych JUGów, natknąłem się na ciekawy przypadek JEP 443: Unnamed Patterns and Variables (Preview). Udało się go wydestylować i zreplikować.

Przygotowywałem prosty przykład dla tego JEPa. Jest on oczywiście bardzo przydatny (JEP, przykład mniej) i na pewno poprawi możliwości Javy do wyróżniania się w scenariuszach programowania zorientowanych na przetważanie na danych.

JEP ten nie dotyczy tylko instrukcji switch i if, ale także lambd, bloków catch i tak dalej. Spójrzmy na poniższy kod, aby pokazać, o co mi chodzi…

1String s = "abc";
2try {
3    int i = Integer.parseInt(s);
4    System.out.println("Parsed " + i);
5} catch (NumberFormatException _ignored) {
6    System.out.println("Bad number: " + s);
7}

Jak widzimy, w linii 5 staramy się jasno stwierdzić, że nie obchodzi nas faktyczny wyjątek, który otrzymaliśmy. Obchodzi nas tylko jego klasa. Wszelako, jak wszyscy wiemy, nawet poważne nazwy nie zatrzymają innych przed (nad)używaniem tak nazwanych rzeczy (patrzę na was, fani sun.misc.Unsafe!).

Dlatego postanawiamy grać ostrożnie i wdrożyć JEP 443, pisząc catch (NumberFormatException _). W ten sposób kompilator zapewni, że nikt nie wywoła _ignored.printStackTrace(); czy coś w tym stylu… I kod wygląda tak:

1String s = "abc";
2try {
3    int i = Integer.parseInt(s);
4    System.out.println("Parsed " + i);
5} catch (NumberFormatException _) {
6    System.out.println("Bad number: " + s);
7}

Zatem przygotowałem ten kod, nacisnąłem przycisk Run w IDE, i… nie działał tak, jak się spodziewałem. Spodziewałem się oczywiście:

1Bad number: abc

A dostałem

1Error: LinkageError occurred while loading main class [class.name.here]
2java.lang.ClassFormatError: Illegal field name "" in class [class/name/here]

Ale że co?

curious case of a button

Na szczęście moje pierwsze IDE, gdy zaczynałem naukę Javy w 2003 roku, to był notepad.exe, więc od razu wywołałem:

1java --enable-preview --source 21 ./src/main/java/all/packages/of/JEP443Demo.java

… i teraz zadziałało zgodnie z oczekiwaniami! Zobaczyłem:

1Bad number: abc

(oczywiście z ostrzeżeniem dotyczącym preview features).

Również w jshellu działa bez zarzutu:

jshell

Wygląda więc na to, że JEP 443 nie lubi działać w tym przypadku z… Mavenem i Gradlem. Nadal nie wiem, jaka jest właściwie przyczyna i któremu narzędziu można to przypisać.

Zawsze, gdy próbuję MAVEN_OPTS="--enable-preview" ./mvnw clean compile exec:java lub ./gradlew clean compileJava run w moim małym projekcie reprodukcyjnym, kończy się to błędem wymienionym powyżej.

Tworzenie pliku JAR za pomocą ./mvnw package lub ./gradlew assemble działa, build kończy się sukcesem (brak zgłoszonych błędów).
A następnie próba użycia go za pomocą java --enable-preview -jar ./path/to/artifact.jar kończy się tym samym błędem.

Nawet gdy pozbywam się narzędzi budowania takich jak Maven czy Gradle i polegam tylko na IntelliJ IDEA, wynik pozostaje taki sam: java.lang.ClassFormatError: Illegal field name "" in class ....

Ręczne odpalanie javac i java śmiga bez problemu, ale jakakolwiek automatyzacja już nie działa.

Także tego…

[To be continued.]

Wybór języka