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.

Vergiss nie, dass auf der anderen Seite ein Mensch sitzt

Das Bildblog hat mir heute in den 6vor9-Nachrichten einen Eintrag von Sascha Pallenberg verlinkt. Der Eintrag ist ein sehr persönlicher Rant gegen Adblock Plus, inhaltlich kann ich wenig dazu sagen, vom Stil her schon sehr seltsam geschrieben.

Und beim Namen “Sascha Pallenberg” war doch was gewesen, kurz gegoogelt – stimmt, er hatte Frau Dingens von Twitter vertrieben (verkürzte, dramatische Darstellung). Nun hatte ich die Details nicht mehr im Kopf, und von der ganzen Fehde nur den Ausgang mitbekommen, also kurz gegoogelt, das Ganze war wohl sehr unerfreulich von allen Seiten.

Aber ich bin darüber auf einen interessanten Text des Gedankenreiters gestoßen: Vergiss nie, dass auf der anderen Seite ein Mensch sitzt. Das ist eine sehr interessante Analyse der Situation mit dem Hinweis darauf, auch mal deeskalierend einzuwirken, nicht alles gewinnen zu wollen, sondern auch mal einfach diskutieren zu können. Fand ich sehr entspannend zu lesen.

[…] Heute, im Jahr 2014, ist das anders. Heute schlichten wir keinen Streit mehr, sondern gießen noch Öl ins Feuer, holen uns Popcorn dazu und genießen das, was kommt. Und wenn das nicht reicht, dann holen wir uns noch andere dazu, die ebenfalls Öl ins Feuer gießen.

[…]

Wie weit darf das „foppen“ denn gehen? Warum habe ich überhaupt das Bedürfnis, jemanden anderen zu foppen? So, wie @sascha_p es beschreibt, habe ich das Gefühl, @FrDingens nervt ihn und er will ihr eine Lektion erteilen. Etwas, das heutzutage viele zu motivieren scheint. Anderen eine Lektion zu erteilen. Sie zu belehren. Sie vorzuführen, um zu zeigen, wie schlecht sie sind.

Mit welchem Ziel eigentlich? […]

Der Artikel enthält interessante Gedanken, ja, ich deeskaliere auch ungern, evtl. muss man halt auch mal zurückfahren, selbst wenn man Recht hat. Insbesondere im Straßenverkehr ist das schwierig, insbesondere, wenn die eigene Gesundheit bedroht wird, aber oft möglich. Mal sehen. Wenn das der “Gegner” nicht dauernd als Schwäche und Eingeständnis einer eigenen Schuld interpretieren würde…

BTW, in den Kommentaren meldet sich auch Sascha Pallenberg zu Wort und macht einen unangenehmen Eindruck: Ich habe recht, alle anderen sind doof, ich kann zwar wenig Argumente dafür finden, die auch noch mies sind, aber habe trotzdem recht.

Wollen wir hoffen, dass er diesen Eintrag nicht findet…

(Quelle: Gedankenreiter, via bildblog)

PS: eigentlich wollte ich schreiben, “Wollen wir hoffen, dass er diesen Eintrag nicht findet, der alte Wichser…”, als “humorvolle” Anspielung auf seinen fapping-Tweet, aber genau das wäre eine unangenehm persönliche Eskalation gewesen, die sich leicht vermeiden lässt. Darum geht es im Artikel des Gedankenreiters. Glaube ich.

WLAN Linuxmint (Ubuntu) auf Acer Aspire S13 S5-371-5693

Bis jetzt hatte ich noch keine Probleme mit Ubuntu-Installationen auf Laptops, vor allem deswegen, weil ich I’s alte, abgelegte Laptops genommen hatte, die gut abgehangen und dementsprechend gut von Linux unterstützt wurden.

Heute nun ein neues Gerät: ein Acer Aspire S13 S5-371-5693.

Zunächst musste ich UEFI-Boot ausschalten, um die normale USB-Installation durchzuführen, sonst hätte ich mich mit UEFI-Boot beschäftigen müssen – geht wohl, ist aber nicht ganz so einfach.

Die Installation klappt dann gut, außer, dass das WLAN nicht funktionierte.

Einige Google-Zeit später:

  1. erst einmal rausfinden, welcher WLAN-Chip verbaut ist. Dazu
    lspci -nnk
    aufrufen, im Ergebnis nach “Wireless Network Adapter” suchen. Für mein Gerät ergab das “Qualcomm Atheros QCA6174”
  2. überprüfen, ob die Firmware für den Adapter korrekt installiert wurde, das ist wohl bei neueren Geräten ein Problem. Dafür nachschauen:
    ll /lib/firmware/ath10k/QCA6174/hw3.0
    bei mir ergab das:
    board.bin
    firmware-4.bin
    notice_ath10k_firmware-4.txt
  3. jetzt im Git-Repository für die Atheros-Firmware nachschauen, ob das die korrekten Dateien sind:
    https://github.com/kvalo/ath10k-firmware
    dort speziell in
    https://github.com/kvalo/ath10k-firmware/tree/master/QCA6174/hw3.0
  4. die drei Dateien waren vorhanden, auch in der richtigen Größe, allerdings gab es im Firmware-Git noch die Datei
    board-2.bin
    die bei mir nicht installiert war.
  5. diese fehlende Datei muss nun in das Firmware-Verzeichnis kopiert werden (mit sudo-Rechten)
  6. jetzt neustarten, das WLAN sollte aktiviert sein
  7. ich musste jetzt die Verbindung versuchen, die klappte nicht sofort, daher bin ich in den Netzwerkmanager gegangen und habe dort die Verbindung rausgesucht und das Passwort erneut eingegeben. Jetzt funktioniert alles.

Ich hoffe, das war es mit Schwierigkeiten, ich vermute mal, der Bug wird in einem halben Jahr ausgemerzt sein, allerdings war das nur 1/2 Studen Arbeit, also im Gesamtkontext kein großes Problem.

Go hugo – eher nicht

hugo ist ein in Go geschriebener statischer Webseitengenerator, der als Template-Engine ebenfalls Go einsetzt.

Derzeit habe ich mit Jekyll Erfahrung, dort gefällt mir die Mächtigkeit der Templatesprache nicht, die einige Sachen sehr gut macht, etwas komplexere Berechnungen aber extrem erschwert.

Also ein Wochenende mit hugo, der Versuch, eine einfache Webseite mit statischen und dynamischen Inhalten aufzusetzen.

Inhalte und Layout waren mir klar, ich musste diese “bloß” umsetzen. Der Aufbau von Themes bei Hugo ist durchaus logisch, der Einsatz von “partials” für Templatefragmente ist einfach und überzeugend, die gute Strukturierung einer Webseite ist einfach möglich. Die Templatesprache ist ok, soweit ich das ausprobiert habe, die Variablen sind sinnvoll gesetzt.

Aber.

Die Dokumentation ist mies. Es werden beispielsweise alle Variablen mit ihren Inhalten aufgelistet. Wenn ich aber eine Map aller Sections habe (.Site.Sections), so müsste ich für deren Einsatz auch wissen, was genau gespeichert wird, welche Metadaten erfasst werden etc. Und genau das ist nicht beschrieben. Oder der Einsatz von Parametern bei “partials”: irgendwie kann man ein “dict” einsetzen, oder “Scratch”, aber wann, warum, wie?

Eine google-Suche zu den Problemen ergibt schnell Treffer (sehr viele Treffer), bei denen sehr häufig erwähnt wird, dass das eine häufig gestellte Frage ist. Und dass eine Dokumentation auch nicht alles leisten kann.

Ja, es ist mir bewusst, dass ich ein kostenloses Produkt einsetze und daher schraube ich meine Ansprüche auch zurück. Andererseits habe ich für die Startseite ca. 8 Stunden gebraucht, es funktioniert noch nicht alles und die anderen Seiten habe ich noch nicht begonnen. Einige Probleme mit der Programmierung haben 1-2 Stunden gebraucht, bis ich eine Lösung hatte, die dann einfach, aber nicht dokumentiert war.

Daher gehe ich wieder auf Jekyll mit seinen Unzulänglichkeiten zurück, einfach, weil Hugo den Anspruch der Einfachheit nicht erfüllt und meine Zeit auch etwas wert ist. Und die zugegeben erstaunliche Geschwindigkeit fällt bei meinen überschauberen Seitenmengen nicht so stark ins Gewicht, gerade bei einem statischen Webseitengenerator.

Fazit: gute Ansätze, für Anfänger zu flache Lernkurve, was die Programmierung angeht.

Apropos Tomb Raider

Nachdem wir gestern Mojin sahen und der ein sehr guter Tomb Raider gewesen wäre, dachte ich an den Trailer den ich letztens gesehen hatte. Ein Tomb-Raider-Trailer vom Feinsten, der nicht auf Laras Brüste starrt, oder eine Duschszene zeigt oder so was, sondern eine Bad-Ass-Lara, die was kann, Tombs raidet und wahrscheinlich auch Bären erpfeilt. Cool. Das würde ein guter Tomb-Raider-Film werden. Aber lass Studios ran und obige Szenen werden garantiert wieder eingebaut. Warum auch immer.

Kritik: The Chronicles of Riddick: Assault on Dark Athena

The Chronicles of Riddick: Assault on Dark Athena ist der Nachfolger von Escape from Butcher Bay und auch der Abschluss der “Chronicles Of Riddick”-Computerspielreihe.

Das Spiel setzt die Flucht von Riddick fort, diesmal auf der Dark Athena und dem Planeten Aguerra Prime. Dabei muss Riddick wieder schleichen, töten und sich voranarbeiten, um vom Schiff und danach vom Planeten zu entkommen.

Das Spiel übernimmt die Handlungsmöglichkeiten des Vorgängers, meiner Meinung nach wurden Kampfstrategien etwas mehr betont in dem Sinne, dass es bei vielen Kämpfen es nötig war, eine Strategie zu finden, um dem Ganzen lebend zu entkommen. Insgesamt aber fair, relativ frustfrei und nicht sonderlich schwierig, lediglich drei Stellen stachen beim Schwierigkeitsgrad deutlich hervor.

Das Ganze wirkt wie ein Aufguss des ersten Spiels, ist es wohl auch, aber gut gemacht. Nicht originell, aber das brauche ich dann auch nicht. Butcher Bay hat mir gefallen und Dark Athena eben auch.

Kurz noch: Sprache und Musik sind herausragend. Die Speicherpunkte sind sehr fair verteilt.

Fazit: gutes Spiel, sehr solide.