Java: C/C++ über JNI einbinden

Neulich musste ich eine DLL aus Java heraus ansprechen. Zur Wahl stehen JNI und JNA, wobei JNA “nur” ein Wrapper für JNI ist – und bei mir nicht funktioniert hat. In der Theorie ist JNI aber auch nicht schwer, allerdings legt Visual Studio einem mir Steine in den Weg. Ein Grund mehr, bei Java zu bleiben.

Der Java-Teil ist dann auch denkbar einfach:

Diese DllBridge wird dann in eine Headerdatei übersetzt:

Und diese Header-Datei dann in “das” C/C++-Projekt kopiert. An “das” Projekt kommt man wie folgt:

  • Visual Studio installieren; ich habe Visual Studio Community 2017 mit den Standardkomponenten genommen
  • Neues C++/Win32-Projekt anlegen, im Dialog unter “Anwendungseinstellungen” den Anwendungstyp “DLL” wählen
  • Ich habe das Projekt testweise MyDll genannt, die entstehende .dll heißt später genauso

Nachdem man die DllBridge.h in das Projekt kopiert und über Rechtsklick > Include In Project eingebunden hat, kann man ihre Methoden implementieren. O.g. Code erzeugt genau eine Methode Java_DllBridge_hello, siehe DllBridge.h. Deren Implementierung in der .c-Datei:

Alleine die Importe und die korrekte Version von MessageBox herauszufinden, hat sicher eine Stunde gedauert 😡 Oh, Stichwort “Importe”: jni.h wird vom  JDK mitgebracht, die entsprechenden Ordner muss man in VS bekannt machen. Das funktioniert nicht über einen Symlink, sondern über die Projekteinstellungen, indem man unter Configuration Properties > C/C++ > General > Additional Include Directories diese drei Verzeichnisse hinzufügt (Rekursion wäre ja auch zu einfach.):

  • C:\Program Files (x86)\Java\jdk1.8.0_121\include
  • C:\Program Files (x86)\Java\jdk1.8.0_121\include\win32
  • C:\Program Files (x86)\Java\jdk1.8.0_121\include\win32\bridge
    PS Ja: Das ist ein 32-Bit-Java, weil ich letztlich eine 32Bit dll ansprechen will.

Das Ganze sollte jetzt bauen (Build > Build solution, oder STRG+Shift+B) und eine <Projektname>.dll erzeugen, siehe Konsolenausgabe. Der Name der .dll muss dem im initialen Java-Code entsprechen.

Ein Aufruf von

öffnet dann die MessageBox:

Sowie die erwartete Ausgabe auf der Konsole. Für reine C-Anbindung könnte man hier aufhören.

Interessant wird es nun, wenn man langlebigere C++-Objekte von Java aus referenzieren möchte. Idee:

  • Eine Klasse auf Java-Seite, die die dll lädt, sowie die nativen Methoden bereitstellt, und eine Klasse auf C++-Seite, die diese implementiert
  • Die C++-Klasse wird initialisiert, ihren Pointer gibt man in Form einer long an Java zurück (bzw. jlong, vgl. hier), vermutlich ist das die Speicheradresse
  • Über diese long kann Java dann das Objekt referenzieren
  • Braucht man das C++-Objekt nicht mehr, wird es deleted.

(via, längeres Beispiel, Danke Nils!)

Hier sieht das so aus:

Bzw. in C++:

Aufruf in Java dann:

Last but not least die andere Richtung, also C++ nach Java. Die Methode

lässt sich von C++ aus aufrufen über

Weiterführendes dazu hier.

hth

PostgreSQL: Entity ID GenerationType migrieren

Angenommen, man möchte die ID einer Entity von

auf

migrieren, und dazu explizit eine Sequence in der Datenbank anlegen. Ein Migrationsskript könnte dann so aussehen:

Aaaber: IDs können negativ sein:

org.postgresql.util.PSQLException: ERROR: setval: value -91 is out of bounds for sequence “foo_bar_id_sequence” (1..9223372036854775807)

😄

Naheligende Lösung wäre, das SELECT in

zu ändern. setval geht allerdings per default aber beim nächsten Wert los, im Fall “1” (wenn gar keine oder nur negative IDs vorhanden sind) also bei 2. Das ist nicht direkt schlimm, aber uncool. Eine (umständliche!) Lösung ist eine Fallunterscheidung – und falls man die Migration viele viele male durchführen muss, verpackt man die Fallunterscheidung in einer FUNCTION:

Aufruf dann per:

Deutlich einfacher ist allerdings:

FALSE sorgt dafür, dass nicht der nächste Wert genommen wird, sondern genau dieser – und “+ 1” vermeidet einen Wert von 0, der ebenfalls out of bounds wäre.

Danke an Nils für’s vereinfachen! 🙂 Die umständliche Version bleibt trotzdem online als Template für PG Functions.

Mockito: Parametrisierte Übergabeparameter prüfen

Den Typ eines Parameters prüft man so:

Aber was, wenn man auf einen bestimmten Übergabeparameter und dessen parametrisierten Typ prüfen will?

Quelle, und, und.

Selenium: Testen, ob ein PDF im Browser angezeigt wird

Das ist tatsächlich nicht so trivial, aber der Reihe nach:

Wer danach googelt, findet erstaunlich (?) häufig den Ansatz, die URL auf endsWith(“.pdf”) zu prüfen 😳 Das sagt natürlich nichts darüber, ob das PDF auch dargestellt wird (oder ob es das richtige PDF ist), aber als erste Näherung habe ich das übernommen. Allerdings prüfe ich die URL etwas genauer, und vergleiche sie mit der URL, deren PDF-Ausgabe backendseitig bereits inhaltlich geprüft wird:

Kurz hatte ich dann überlegt, auf den Content Type zu prüfen, aber da kann natürlich alles drin stehen. Die o.g. Bedingungen stellt das ebenfalls nicht sicher.

Dann gibt es Ansätze, STRG+A/STRG+C zu nutzen (Beispiel), um den Inhalt des PDF zu verifizieren – funktioniert nicht mit jedem OS/Browser.

Dann, ebenfalls häufig genannt: PDFBox. Finde ich gut, so kommt man an den Inhalt des PDFs und kann sicherstellen, dass es das richtige PDF ist:

Nachteil: Dass die URL [ein|das richtige] PDF ausliefert, sagt natürlich nichts darüber, dass das im Browser dargestellt wird 🙃

Also: Screenshot machen. Allerdings nicht die Selenium-Methode, denn aus Browser-Sicht ist die Seite “leer”, das PDF wird von einem Plugin gerendert. Die Lösung dazu: Robot.

ACHTUNG: Das geht nicht in einer “headless”-Umgebung, wie man sie bsplw. auf vielen CI-Servern findet:

java.awt.AWTException: headless environment

Mit einem waitFor, bis das PDF tatsächlich gerendert wurde (denn das ist ungleich “die Seite wurde geladen”):

und einem kleinen Trick, um statt des Bildschirms nur den Browserinhalt zu screenshoten:

Auf Basis des Bildes kann man nun sicherstellen, dass keine weiße Seite gerendert wurde…

…oder halt irgendwas. Man könnte auch PNG-Vergleiche machen. Inhaltlich, wie gesagt, würde man mit PDFBox testen, darum ging es hier aber nicht.

HTH.

Spring: /resources durchsuchen

Problem: Wie kann ich einen resources-Ordner durchsuchen – in der IDE, im .jar und aus jUnit-Test heraus1?

Lösung: PathMatchingResourcePatternResolver.getResources(String locationPattern)

Beispiel:

von, via

1Wo getClass().getResource(MY_FOLDER + "someFile.def"); funktioniert, aber getClass().getResource(MY_FOLDER); nicht2.

2wtf.

Spring: JSON aus HttpServletRequest

Vorab: Ja, es gibt @RequestBody. Und es ist hässlich. Ich habe es nicht mal eingebaut. Aber ich musste es googlen und will das nicht noch mal tun müssen:

PS zu Zeile 2 und zu Zeile 4.

Java: Anonymes Initialisieren von Listen

Listen:

Sie können “einzeilig” initialisiert werden:

Aber: Was, wenn ich sie mit anonymen Klassen initialisieren will?

Geht nicht, weil die anonyme Klasse Foo beerbt, und damit kommt Java nicht klar. Aber

geht. Hässlich, aber es geht. 🙂 Ein bisschen schöner (weil lesbarer) geht es mit Guava, aber im Grunde ist das genauso umständlich:

Weitere Vorschläge?

Java: Datei im Systemeditor öffnen

Googelt man “open file” etc., geht es meistens darum, eine Datei einzulesen. In meinem konkreten Fall wollte ich sie aber öffnen, also bsplw. ein PDF im Reader. Lösung:

Achtung: Eventuelle Handles müssen geschlossen werden, oder es gibt ein

There was an error opening this document. This file is already open or in use by another application.

Für einen OutputStream sieht das so aus: