Java import-Fehler von QName

Die Umstellung von Java 8 auf Java 9+ ist ja sowieso schon mühselig, wenn man aber ganz exotische Fehler bekommt…

Bei mir ging folgender Import nicht:

import javax.xml.namespace.QName;

Erstaunlicherweise ist QName eine Java-Standardklasse, sie wurde per Autocomplete auch gefunden, dann aber als not found gekennzeichnet.

Der Fehler war, dass im Classpath die Maven-Abhängigkeiten vor der JRE-Library standen. Wenn man das ändert (in eclipse bei Java Build Path und Order/Export vertauschen, auch wenn die nicht angekreuzt sind!), dann funktioniert es wieder.

WTF?

Offensichtlich schießt eine Maven-Abhängigkeit da quer, die aber erst beim Kompilieren zuschlägt. Wie soll man da drauf kommen.

Zum Glück gibt es StackOverflow, aber auch dort nur eine Antwort zum Thema. Kann sogar sein, dass das erst ab Java 10 oder 11 auftritt, so genau hab ich nicht geforscht.

Also nochmal: WTF?

Get checked items of a TreeView in JavaFX

JavaFX provides an easy way to implement Java GUIs. Unfortunately, some methods or concepts are missing.

I used a TreeView component with CheckBoxTreeItems. When evaluating the input I want to get all checked items from the TreeView, resp. its SelectionModel.

The standard method getSelectedItems just returns the selected items, when selecting means the last clicked (i.e. selected) element.

Thus I had to write my own code for traversing the tree and collecting all checked elements. This is not difficult, but a bit tiresome, as there are many methods missing that have to be implemented.

If you’re interested in the code, see

https://gitlab.com/ekleinod/edgeutils/blob/master/edgeutils/src/main/java/de/edgesoft/edgeutils/javafx/TreeViewUtils.java

for my implementation. As I state in the documentation, using Kotlin should provide means to extend the TreeView class itself, but this is future talk.

Kritik: It Came From The Desert

It Came From The Desert ist ein leider sehr zahmer Fun-Trash-Monster-Film mit Riesenameisen basierend auf dem gleichnamigen Computerspiel von Cinemaware, das ich nie gespielt habe.

Wir begleiten zwei Helden, die ihre Prinzessin retten dürfen, die zwischendurch sogar mal kurz aus ihrer Rolle ausbrechen darf. Dabei bemüht sich der Film, die Klischees, die man erwartet und die auch aufgebaut werden, ein klein wenig zu dekonstruieren. Das ist selbstreferentiell, wie auch die vielen Film”anspielungen”, aber durchaus ok, wenn man sich drauf einlässt.

Leider mangelt es dem Film an Stringenz. Der Anfang ist gut, danach hängt die Handlung ein wenig und die Effekte werden immer schlechter. Die innere Logik auch, was schade ist.

Die Schauspieler sind gut, sie füllen ihre Rollen aus, die leider etwas zu klischeehaft ausfallen, das Rumjammern unseres zweiten Haupthelden nervt schon gewaltig.

Fazit: nicht gelangweilt, aber auch kein großer Wurf, evtl. besser zu einer Party genießen.

eclipse-Probleme beim Kompilieren von Tests

Ich hatte das Problem, das nach einem Update von eclipse meine Testklassen nicht mehr kompilierten, da die JUnit-5-Testklassen (per maven eingebunden)  nicht gefunden wurden.

Ich vermutete erst JUnit als Übeltäter, eine Kompilierung über maven funktionierte jedoch.

Stack Overflow ist mein Freund: in eclipse wurde ein neues Attribut eingeführt, das die Testklassen identifiziert, vorher ging das automatisch, wenn man sie in ein Verzeichnis “test” gelegt hat. Da die Klassen nun nicht mehr als Testklassen gekennzeichnet waren, wurden auch die JUnit-Klassen nicht geladen, da diese per maven im scope “test” definiert wurden.

Eigentlich logisch, wenn man es weiß.

Also in eclipse die Projekteigenschaften aufrufen, dort im Java Build Path in den Sources bei Contains Test Sources “Yes” durch Doppelklick einstellen.

Kompiliert immer noch nicht, aber ein Fehler weniger ist ein Fehler weniger…

Java 10 und JavaFX, Oracle Java und OpenJDK

Es ist manchmal ein Kreuz mit Java.

Zunächst muss man sich unter Linux (wahrscheinlich auch unter Windows, wer weiß), entscheiden, ob man mit Oracle Java oder OpenJDK entwickelt.

Das ist solange kein Unterschied, bis man JavaFX einsetzen will, das XML-basierte GUI-Elemente zur Verfügung stellt. JavaFX ist bei Oracle bei Java 8 und 9 dabei, bei OpenJDK muss man das extra installieren oder sich sein OpenJDK selbst compilieren. Ich will ja eigentlich nur Java programmieren, also Oracle Java genommen (damals Java 8), weil das JavaFX enthält und unter Linux funktioniert.

Als Java 9 rauskam habe ich das erst mal ignoriert, weil es mir von der Sprache her außer Modulen nicht viel bringt und in die wollte ich mich erst einarbeiten, wenn Version 1 meines Programms steht. Außerdem startet Java 9 mit Java 8 compilierte jar-Dateien nicht, ich hätte mich also tatsächlich einarbeiten müssen, unabhängig davon, ob ich Module nutze oder nicht – war mir zu mühselig.

Jetzt ist ein Fehler im Double-Spinner aufgetreten (es wird eine Exception geworfen, wenn ein leerer Text eingegeben wird). Dieser Fehler ist ab Java 9 behoben.

Im Gegensatz zu früher kann man seit Java 9 OpenJDK tatsächlich gleichwertig zu Oracle Java benutzen, da ist Oracle wohl etwas offener geworden. Außerdem soll alle halbe Jahre eine neue Java-Version rauskommen.

Daher habe ich mit Vorfreude OpenJDK 11 installiert (das bis Oktober ein Java 10 installiert – fragt nicht) und sofort gemerkt, dass das Programm nicht kompiliert, weil die JavaFX-Klassen fehlen. Wie jetzt – ich dachte, OpenJDK ist gleichwertig?

Das ist so, dass ab Java 10 sowohl bei Oracle als auch bei OpenJDK JavaFX nicht mehr enthalten ist. Bei beiden Distributionen muss man JavaFX separat installieren. Das soll wohl die Entwicklung separieren und dynamischer gestalten, gerade im Hinblick auf die mit Java 9 eingeführte Modularisierung. Langfristig soll JavaFX auch auch als Maven- oder Gradle-Dependency zur Verfügung stehen.

Steht es aber nicht, ich müsste also entweder ein OpenJDK selbst compilieren (glaubt mir, die Anleitungen sind nicht vertrauenserweckend) oder auf Oracle Java 8 oder 9 zurückgehen. Außerdem ist unklar, ob JavaFX bleibt oder mit Oracles Entscheidung endet. Beides sind realistische Optionen, ich hoffe natürlich langfristig auf eine Dependency.

Konkret werde ich auf Oracle Java 8 zurückgehen, einen üblen Hack für den Spinner-Bug implementieren und Version 1 fertigstellen. Immerhin nutze ich so eine Umgebung, die ich beherrsche.

Dann werde ich mir die Modularisierung ansehen und schauen, inwieweit ich beim dann vorhandenen Java 11 schmerzfrei JavaFX integrieren kann.

Lernzeit dafür: zwei Tage und ein Komplettupdate meines Rechners.

Ich will doch nur programmieren…

Laptop-Tastatur bei Acer Aspire VN 7 teilweise ausgefallen

Wir hatten das Problem, dass bei der Tastatur unseres Acer Aspire VN 7 die Tastatur teilweise ausgefallen war, vor allem die links sitzenden Tasten waren betroffen. Zunächst dachte ich an einen Defekt, aber vor einem Austausch will man ja auch die nichtteuren Alternativen ausgelotet haben.

Eine schnelle Google-Suche ergab die Möglichkeit, dass irgendwelche Stützkondensatoren nicht entladen wurden und den Fehler verursachen könnten. Zum Entladen einfach den Akku entfernen, lange auf die An-Taste drücken, Netzstecker rein, anschalten und dann gucken, ob es wieder geht.

Kein Problem, dachten wie, bis wir den Aufbau des Laptops ansahen und merkten, dass der Akku nicht zugänglich ist, ohne das Laptop aufzuschrauben.

Also erst mal ein umfangreiches Backup angestoßen, damit im Fall der Fälle (Laptop aufschrauben ist immer ein Risiko) kein Datenverlust entsteht. Erschwert wurde das dadurch, dass die Tastatur ja nur teilweise funktionierte, also eine externe oder die Bildschirmtastatur herhalten musste.

Nach diesen Vorbereitungen ging es beruhigt an die Arbeit. Die Schrauben entfernen ging leicht, wie aber jetzt das Ganze aufbekommen? Googeln brachte dieses wirklich hilfreiche Video zutage: “Acer Aspire V15 Nitro Black Edition VN7-591G-77A9 – SSD Einbau (Deutsch)“, das den Einbau gut erklärt und zeigt.

Im Endeffekt versucht man, das Gehäuse von der Tastatur zu lösen, indem man in die Lücke mit den Fingernägeln reingeht und dann zieht. Man muss nur kleine Verhakungen lösen. Im Video gut zu sehen.

Den Akku muss man jetzt nicht extra entfernen, es reicht, das Verbindungskabel zur Platine abzuziehen. Dann rechts oben den An-Knopf lange drücken. Lange ist ungefähr 3-10 Sekunden, wenn man die Mühe des Aufschraubens investiert hat – lieber länger als zu kurz.

Jetzt mit dem Netzstecker probieren, ob das Laptop startet und die Tasten wieder funktionieren. Vorsicht: 220 V möglichst nicht anfassen.

Wir hatten Glück: die Tasten funktionieren wieder. Also ausgeschaltet, Netzstecker raus, Akkukabel rein, nochmal probiert. Hat immer noch funktioniert.

Jetzt das Gehäuse wieder vorsichtig aufgesetzt und alles zusammengedrückt (man hört das einrasten). Alle Schrauben wieder reindrehen, noch einmal testen und fertig.

Wir haben Glück gehabt, es waren tatsächlich die Kondensatoren und das ließ sich beheben, außerdem ist der Rechner frisch gebackupt.

Java: Instanzen von Generics

Ab und an habe ich das Problem, bei Klassen mit Generics eine Instanz des Generics erstellen zu wollen. Das funktioniert leider nicht direkt:

T newObject = new T();

Also muss man um das Problem herumprogrammieren.

Üblicherweise wird die Übergabe einer Klasse empfohlen, die für die Instanziierung genutzt wird. Die Lösung finde ich häßlich, unschön und unelegant.

Java 8 bietet mit der Einführung von Lambdas und entsprechenden Hilfsklassen eine elegantere Möglichkeit, die ich derzeit bevorzuge.

Ich habe das Problem und die Lösungen auf ekkart.de beschrieben: http://www.ekkart.de/computer/programmierung/java/generics.html

Hier die von mir präferierte Lösung:

public class GenericClass<T extends Object> {

  private Supplier<T> instanceCall = null;

  public void init(final Supplier<T> theInstanceCall) {
    instanceCall = theInstanceCall;
  }

  public T getInstance() {
    return instanceCall.get();
  }

}

public class ObjectFactory {
  public Integer createInteger() {
    return new Integer();
  }
}

public class Test {

  public void testGenerics() {
    GenericClass<Integer> testObject = new GenericClass<>();
    ObjectFactory factory = new ObjectFactory();
    testObject.init(factory::createInteger);
    Integer a = testObject.getInstance();
  }

}

WordPress-Plugin Postpone-Posts

Ich hab wieder ein WordPress-Plugin geschrieben, diesmal etwas sinnvoller als mein letztes.

Das Postpone-Posts-Plugin verschiebt alle zukünftigen Beiträge um x Tage (x wählbar). Das soll es mir erleichtern, Beiträge vorzuschreiben und nicht mühsam einzeln zu verschieben, wenn etwas dazwischenkommt. Wir werden sehen, ob das klappt.

Das Plugin liegt auf WordPress.org unter https://wordpress.org/plugins/postpone-posts/, der Quellcode in github unter https://github.com/ekleinod/postpone-posts.

Entwickelt habe ich das mit Texteditor und Docker. Texteditor (jEdit) für die Plugin-Datei, Docker für die Entwicklungsumgebung, ohne mir den Rechner mit Datenbank, Server etc. vollzumüllen.

Docker ist tatsächlich recht einfach nutzbar, die Doku ist ok, meine Notizen dazu stehen unter http://www.ekkart.de/computer/wordpress/plugins.html

Die Plugin-Entwicklung selbst ist relativ einfach (das Problem war auch nicht schwierig), die WordPress-API ist durchaus vernünftig aufgebaut und halbwegs gut dokumentiert, es gibt ein Plugin-Entwicklungshandbuch.

Das “halbwegs” ist dabei das oft ein Problem, viele Dinge werden nicht wirklich gut erklärt, das ist beim Verstehen einer API eher schlecht. Zu den meisten Problemen gibt es im Handbuch oder unter der API-Beschreibung Beispielcode oder in Google eine schnelle Antwort. Ich kann trotzdem nur empfehlen, mit einem sehr einfachen Plugin mit der Entwicklung zu beginnen.

Kurz zur Entwicklung

Der Code des Plugins ist in github abgelegt.

Ich habe allen Code in eine Klasse gepackt, um Namensprobleme mit existierenden Funktionen zu vermeiden. Die Entscheidung funktioniert für mein Plugin, dessen Funktionalität wenig Code umfasst. Bei einem größeren Projekt würde ich evtl. eher mit Präfixen für Funktionen arbeiten, um den Code in einzelnen Dateien kapseln zu können. Oder mehrere Klassen verwenden, das käme auf den Versuch an.

Was ich sehr verwirrend fand, waren die verschiedenen IDs, Slots und sonstigen Bezeichner, die für die Nutzung der API und der Hooks nötig sind. Deshalb sind diese Dinge meist exzessiv kommentiert, damit ich mich da wieder reinfitzen kann.

Die Lokalisierung und Internationalisierung war erstaunlich problemlos möglich. Ich hatte Datumausgaben sowieso in einer eigenen Methode gekapselt, die ich nur einmal anpassen musste. Für Texte habe ich auch gleich die __-Methoden genutzt. Für die Singular/Plural-Unterscheidung und Nummerformatierung gibt es ebenfalls eigene Methoden, die ich erst später gefunden habe. Sie einzubauen war aber auch kein Problem. Für die Internationalisierung der reinen Texte gibt es ein gutes Werkzeug – poedit.

Insgesamt war es eine gute Idee, ein einfaches Problem mit relativ wenig Code anzugehen, die Funktionalität fertigzubauen und die Schleifen (i18n etc.) erst später umzusetzen. Zu lange darf man mit den Schleifen aber auch nicht warten, um nicht zu viel Code umstellen zu müssen.