Archiv für den Autor: Michael Kulla

JavaFX 8: FXML-Controller initialisieren ohne Initializable

JavaFX-Controller

In JavaFX-Anwendungen ist der Controller das P in MVC und stellt die Verbindung zwischen FXML-View und Java-Model her.

Nach Instanziierung des Controllers (entweder durch den FXMLLoader oder programmatisch) erfolgt die Injection der mit @FXML annotierten GUI-Elemente. Danach kann optional eine zusätzliche Initialisierung des Controllers erfolgen, der Controller muß dazu lediglich das Interface Initializable implementieren, und das Ganze sieht in dann etwa so aus:

public class YourController implements Initializable {

    @FXML
    Button doStuffButton;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // ...
    }

}

Die Methode initialize wird nach Instanziierung des Controllers und nach Injection der @FXML-Elemente aufgerufen. Benötigt man die Parameter später noch, werden sie üblicherweise in Instanzvariablen übernommen:

    URL location;
    ResourceBundle resources;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        this.location = location;
        this.resources = resources;
    }

Soweit das Standardvorgehen.

Vereinfachung

Es gibt in JavaFX 8 nun mehrere Möglichkeiten, diesen Code zu vereinfachen.

kein Interface

Die Klasse ist nicht verpflichtet, tatsächlich explizit das Interface Initializable zu implementieren, es genügt, wenn die entsprechende Methode vorhanden ist, also

    public void initialize(URL location, ResourceBundle resources) { ... }

@Override muß dann natürlich verschwinden.

keine Parameter

Werden die beiden Parameter location und resources eigentlich gar nicht benötigt, können sie aus der Signatur verschwinden, Hauptsache, die Methode behält ihren Namen und hat auch sonst keine weiteren Parameter:

    public void initialize() { ... }

Am Verhalten ändert sich nichts, die Methode wird immer noch direkt nach Instanziierung und Injection automatisch aufgerufen.

keine Methode

Schließlich gibt es noch eine dritte Vereinfachungsmöglichkeit.

Wird die initialize-Methode lediglich dazu benötigt, die beiden Parameter location und resources in Instanzvariablen zu übernehmen, dann kann sie auch gleich komplett weggelassen werden. Die beiden Attribute müssen lediglich exakt diese Namen tragen und zusätzlich mit @FXML annotiert werden:

    @FXML
    URL location;

    @FXML
    ResourceBundle resources;

Das genügt. Wird der Controller instanziiert, dann werden neben all den anderen Injections nun auch diese beiden Attribute passend befüllt.

So kann also der Controllercode um ein paar unnötige Zeilen gekürzt werden, die ja ohnehin immer wieder die gleichen wären, aber natürlich muß dann nicht nur der Schreiber, sondern auch der spätere Leser des Codes um diese Möglichkeiten wissen.

Android Studio: Projektstart schlägt fehl

Situation

Ich sollte einen neuen Rechner für die Entwicklung von Android-Apps einrichten. Als Betriebssystem kam Kubuntu 14.10 (64 bit) zum Einsatz, darauf ein JDK 8, und für die eigentliche Entwicklung Android Studio.

Problem

Bei Starten des ersten Projekts zeigte sich allerdings ein unerwartetes Verhalten:

Im Log tauchte fünfmal die Meldung

Android/Sdk/build-tools/22.0.1/aapt: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory

auf, und danach ebensooft

Exception in thread "png-cruncher_3" java.lang.RuntimeException: Timed out while waiting for slave aapt process, try setting environment variable SLAVE_AAPT_TIMEOUT to a value bigger than 5 seconds

(wobei die Zahl am png-cruncher immer mal eine andere war).

Danach passierte dann überhaupt nichts mehr. Gradle meldete in der Statuszeile brav Gradle: Executing Tasks [:app:assembleDebug] , und ließ sich davon auch nicht mehr abbringen. Am Ende konnte ich die IDE nur noch mit einem kill beenden.

Lösung

Wie sich herausstellte, besteht dieses Problem nur auf 64-bit-Systemen. Zwei Bibliotheken müssen zusätzlich in ihren 32-bit-Versionen installiert werden, und dann läuft alles, wie es soll:

sudo apt-get install libstdc++6:i386 zlib1g:i386

NetBeans kann Maven nicht finden

Kürzlich bei der Vorbereitung einer Java-EE-Schulung

Der Kunde wünschte sich als Umgebung:

Im NetBeans-Bundle ist Maven bereits dabei, allerdings in Version 3.0.5. Kein Problem, dachte ich mir, das sollte ja recht einfach sein.

  • aktuelles Maven runterladen
  • auspacken nach C:\
  • in NetBeans “Maven Home” auf das neue Verzeichnis setzen (Menü Tools – Menüeintrag Options – Bereich Java – Tab Maven)
  • fertig.

Beim ersten “Run” kam aber statt des erwarteten Downloading dieses, Downloading jenes ... ein schlichtes

Der Befehl "mvn.bat" ist entweder falsch geschrieben oder konnte nicht gefunden werden.

bzw. auf englisch

'mvn.bat' is not recognized as an internal or external command, operable program or batch file.

Nach etwas Bingen (wenn wir schon mal unter Windows sind) fand ich dann die Ursache: NetBeans verwendet auf Windows-Systemen mvn.bat, um Maven zu starten, jedoch verschwand dieses bereits mit Version 3.3.1 aus der Distribution.

Stattdessen findet sich (die auch vorher bereits vorhandene) Datei mvn.cmd, und damit ist die Lösung dann recht unkompliziert:

  • Die fehlende mvn.bat im Verzeichnis C:\apache-maven-3.3.3\bin-Verzeichnis anlegen
  • und dort diesen Text hineinschreiben

(exakt so)

"%~dp0\mvn.cmd" %*

Jetzt findet NetBeans die mvn.bat, ruft sie auf, die wiederum leitet an mvn.cmd weiter, und alle sind glücklich.

In der Schulung fiel dann zwar kurzzeitig der Beamer aus, aber NetBeans und Maven funktionierten anstandslos.

Open University T802 forum

Notice: You have to be signed in to the Open University website to access some the following links.

If you are studying at the Open University and you’re aiming at an MSc your last module will probably be the T802 Research project. To cite from the module page :

T802 is a compulsory module in our:

  • MSc in Engineering (F46)

T802 is an optional module in our:

  • MSc in Advanced Networking (F56)
  • MSc in Computing (F66)
  • MSc in Environmental Management (F65)
  • MSc in Systems Thinking in Practice (F47)
  • MSc in Technology Management (F36)

This module can also count towards F05, F13, F26, F37, F42 and F43, which are no longer available to new students.

There’s a preparatory website

called Preparing for T802 with a lot of helpful and important information like “Essential actions before the module start” to prepare you for the T802.

Also,

there’s an accompaining forum for current and prospective T802 students where you can find answers to questions like “How to cite from Kindle books (since there are no page numbers)?” or “This is my topic, what do you think?”.

However,

it seems that there are only two ways to find this forum: Either by following a rather long line of module descriptions, forum posts, hyperlinks, some trial and error, fascinating redirects, and even more links, or by accident.

To help you

finding this invisible forum, here’s the link: Preparatory forum “T802 – future studies”.

UPDATE:

I just found out the link above is no more valid. Now the forum can be found here.

So here you are: Another post with another hyperlink to help you to finally find what you were looking for: The comprehensive T802 research project forum site.

Happy happy = new Year(2015)

In Java-EE-Anwendungen immer wieder gern gesehen:

System.exit(0);

Einfach mal ausprobieren.

Derby startet nicht

Immer mal wieder begegnet mir bei einem Kunden eine etwas ältere Java7-Version, was für die meisten Zwecke auch völlig ausreichend ist.

Das Datenbanksystem Derby (bzw. JavaDB) ist seit JDK 6 mit dabei und ist gerade für Demonstrationen und Tests sehr gut geeignet.

Bei konkret JDK 7u51 gibt es jedoch ein Problem: Derby startet nicht.

Stattdessen wird eine AccessControlException geworfen, und die Fehlermeldung lautet

access denied ("java.net.SocketPermission" "localhost:1527" "listen,resolve")

Dieses Verhalten ist seit geraumer Zeit bekannt, an verschiedenen Stellen ausführlich beschrieben, und auch an Lösungsvorschlägen mangelt es nicht. Einige sind korrekt, einige eher Hacks, und einige funktionieren schlichtweg nicht.

Mit 7u51 wurden die Sicherheitsrichtlinien geändert: Vorher durfte jeder Prozeß an jedem Port > 1023 horchen, nun gilt das nur noch für Ports in einem weiter hinten liegenden Bereich (ab irgendwo um 40.000). Derby möchte standardmäßig Port 1527 verwenden, und das geht jetzt nur noch mit entsprechender Erlaubnis.

Um mir die Zeit und den Aufwand zu sparen, jedesmal wieder von vorn alle üblichen Verdächtigen abzuklappern, schreibe ich hier die von mir präferierte Lösung nieder, auf daß ich sie fortan immer parat haben möge.

Die JDK-Sicherheitsrichtlinien werden in der Datei java.policy gespeichert, die in $JAVA_HOME/jre/lib/security liegt.

Dort kann nun am Ende die neue Erlaubnis eingetragen werden:

grant {
    permission java.net.SocketPermission "localhost:1527", "listen";
};

Derby darf horchen, kann starten, alles wieder gut.

Das Ganze gilt nur für 7u51 – ab der nächsten Version (7u55) enthält die Derby-interne server.policy-Datei die entsprechende Erlaubnis bereits, womit die obige Ergänzung nicht mehr notwendig ist.

Ein erster Markdown-Text

Bisher habe ich dieses Blog nicht wirklich als solches genutzt – genaugenommen habe ich es, abgesehen vom ersten Eintrag damals direkt nach dem Anlegen, überhaupt noch nicht genutzt.

Die Gründe dafür waren immer die gleichen: Keine Zeit, muß arbeiten, Familie/Freunde, Kundentelefonate, Müll runterbringen – das Übliche eben.

Nach sorgfältiger Analyse habe ich nun einen weiteren Grund ausmachen können: Den WordPress-Texteditor.

Meinen ersten Eintrag zu erstellen war damals recht umständlich. Bei jedem Hin- und Herschalten zwischen Text- und HTML-Editor sah alles immer wieder anders aus, die Formatierungen änderten sich scheinbar willkürlich, und das Einfügen von Code und Codeblöcken war noch mal eine zusätzliche Herausforderung, von Syntaxhighlighting ganz zu schweigen. Recht frustierend das. Sicherlich gab es dafür irgendwo einen Schalter oder ein Tutorial; fand ich nicht, und hatte auch keine Zeit (keine Lust?), danach zu suchen.

Immer mal wieder las ich etwas über Markdown, und das sah komfortabel einfach aus. Die anderen Hinderungsgründe gab es natürlich weiterhin, aber heute nun ist es soweit: WordPress-Plugin ausgesucht, installiert, Beispielseite gelesen, losgeschrieben.

In diesem Text sind zwar noch nicht wirklich Formatierungen drin, aber bereits jetzt fühlt es sich anders an: Klarer, auf’s Wesentliche reduziert, eben benutzbar. Das Blog ruft geradezu danach, mit weiteren Texten befüllt zu werden.

Jetzt harre ich einfach mal der Dinge, die da kommen mögen, und dann sollte sich ja bald zeigen, ob es wirklich daran gelegen hatte.

Damit f:ajax funktioniert

Der typische Einsatz des JSF-Tags <f:ajax> sieht ungefähr so aus:

<h:panelGrid columns="1">
    <h:inputText id="in" value="#{echo.text}">
        <f:ajax render="out" event="keyup" />
    </h:inputText>    
    <h:outputText id="out"
                  value="#{echo.upperCase}" />
</h:panelGrid>

Hier wird der eingegebene Text bei jedem Tastendruck per JavaScript an den Server geschickt. Als Antwort kommt dann der Text in Großbuchstaben zurück und wird, wieder mit JavaScript, an der entsprechenden Stelle (h:outputText) in die Webseite eingebaut. Kein Neuladen der ganzen Seite notwendig, alles gut. Es sei denn, es funktioniert nicht, und stattdessen kommt die Fehlermeldung

Eine oder mehrere Ressourcen haben das Ziel ‘head’, aber es wurde keine Komponente ‘head’ in der Ansicht definiert.

Woran liegt’s? Das benötigte JavaScript wird von JSF in den Header der Seite eingefügt, was dann beim Browser etwa so ankommt:

<script type="text/javascript" src="/Echo/javax.faces.resource/jsf.js.xhtml?ln=javax.faces"></script>

Der Punkt ist: Damit das auch tatsächlich passiert, also das <script>-Tag auch wirklich eingefügt wird, muß auch der Header eine JSF-Komponente sein. Also <head> reicht nicht, sondern es muß schon <h:head> sein. Denn nur letzteres kann als echte JSF-Komponente dafür sorgen, daß mehr an den Client geht als nur das reine head-auf und head-zu.