<img height="1" width="1" style="display:none;" alt="" src="https://px.ads.linkedin.com/collect/?pid=1195114&amp;fmt=gif">

Best Practice für das Hinzufügen einer Java Dependency zu Mendix

Andrej Gajduk
Andrej Gajduk

Mendix Low-code

Meine Reise mit Mendix begann vor mehr als vier Jahren. Aufgrund der Natur meiner Mendix-Projekte musste ich oft Java-Bibliotheken von Drittanbietern verwenden und basierend auf dieser Erfahrung habe ich vor zwei Jahren einen Blog-Beitrag über die Verwaltung von Java-Abhängigkeiten für Mendix-Module geschrieben. Seitdem habe ich mehr Einblick in diesen Prozess gewonnen und wollte meine Erfahrungen mit Ihnen teilen.

Das Ziel dieses Blog-Beitrags ist es also, meine Erkenntnisse und Best Practices für das Hinzufügen einer Java-Bibliothek zu einem Mendix-Projekt zu dokumentieren und zu zeigen, wie diese in einem praktischen Beispiel angewendet werden können.

Aufgeregt? Los geht's!

Best Practice

Meiner Meinung nach ist der beste Weg, eine Drittanbieter-Abhängigkeit zu Mendix hinzuzufügen, zunächst ein separates reines Java-Projekt aufzusetzen (mit gradle oder maven), das die Abhängigkeit enthält und eine einfach zu bedienende Schnittstelle bietet. Dann verwenden Sie ein Shadow-Plugin, um ein sogenanntes Fat-Jar zu erzeugen, das alle Abhängigkeiten enthält und importieren dieses in Ihr Mendix-Projekt.

Dies ist in gewisser Weise die gleiche Aussage wie in meinem vorherigen Blogbeitrag. Wie Sie jedoch anhand der folgenden Liste sehen werden, lässt sich die Liste der Vorteile dieses Ansatzes erheblich erweitern, wenn Sie die Dinge etwas anders angehen. Hier also mein Überblick über die Vorteilen, die sich aus der Verwendung des obigen Prozesses ergeben:

  1. Automatischer Umgang mit transitiven Abhängigkeiten.
    Fast jede Java-Bibliothek hat andere Java-Bibliotheken, von denen sie abhängt. Diese einzeln herunterzuladen ist umständlich, fehleranfällig und nicht wartbar. Gradle und Maven unterstützen beide von Haus aus das Management von Abhängigkeiten. Sie werden die richtigen Abhängigkeiten für die Bibliothek, die Sie verwenden wollen, finden und herunterladen. Da sich alle Abhängigkeiten in einem Jar befinden, werden alle Abhängigkeiten, die nicht mehr benötigt werden, automatisch beim Build entfernt, was einen einfachen Update-Prozess ermöglicht, im Gegensatz zu vielen Mendix-Modulen, bei denen die Entwickler aufgefordert werden, unbenutzte oder alte Abhängigkeiten beim Upgrade manuell zu löschen.

  2. Vermeiden Sie Versionskonflikte für transitive Abhängigkeiten. Leider kann der Mendix Java Class Loader, der auf OSGI basiert, nicht mit mehreren Versionen einer Abhängigkeit umgehen. Dies kann ein blockierendes Problem sein, wenn die Bibliothek, die Sie verwenden möchten, eine bestimmte Version einer Abhängigkeit laden muss, während die Mendix-Laufzeit oder ein anderes Mendix-Modul eine andere Version der gleichen Abhängigkeit verwendet. Dank des Shadow-Plugins können solche Abhängigkeiten schattiert werden, so dass der Classloader sie gleichzeitig laden kann.

  3. Lernen Sie die Java-Bibliothek isoliert kennen. 
    Die Verwendung einer Bibliothek eines Drittanbieters, mit der Sie nicht vertraut sind, ist allein schon schwierig genug. Der Versuch, es im Kontext eines großen Mendix-Projekts zu tun, ist tausendmal schwieriger. Wenn etwas nicht funktioniert, ist es unmöglich zu sagen, ob der Fehler von der Bibliothek, Ihrem Java-Code, der Integration zwischen Mendix und Java oder der Mendix-App selbst kommt. Auch das Testen und Debuggen ist komplizierter und zeitaufwändiger, wenn Sie jedes Mal eine Mendix-Laufzeit starten müssen.

  4. Code auf die gewünschte Schnittstelle.
    Oftmals hat die Java-Bibliothek eine komplizierte Schnittstelle zu verwenden. Um etwas so Einfaches wie einen Funktionsaufruf durchzuführen, müssen Sie wahrscheinlich die üblichen Verdächtigen durchlaufen: Factories, Builder und Manager, bis Sie ein Objekt haben, mit dem Sie die Methode tatsächlich aufrufen können. Es ist am besten, diese Komplexität auszublenden und einen einfachen Adapter/Facade zu bauen, der die Schnittstelle hat, die Sie wollen und brauchen. Ein zusätzlicher Bonus ist, dass Sie die Bibliothek eines Drittanbieters gegen eine andere austauschen können, ohne die Mendix-Anwendung berühren zu müssen.

  5. Einfaches Einrichten von Unit-Tests, die als Regressionssuite dienen.
    Dies ist so wichtig, dass ich es in dieser Liste zehnmal wiederholen möchte. Wenn etwas in einer komplexen App nicht funktioniert, ist es sehr schwer, den genauen Ort des Fehlers zu lokalisieren. Wenn Sie also einige Tests haben, können Sie sehr einfach überprüfen, ob das Problem in der Bibliothek eines Drittanbieters oder irgendwo anders in Ihrer Mendix-Logik liegt. Ein weiterer guter Grund für Tests ist es, die Risiken zu reduzieren, die mit Änderungen an Ihrem Code oder der Aktualisierung der Bibliothek auf eine neue Version verbunden sind. Sie könnten dies theoretisch in Mendix machen, aber das ist viel komplizierter, ressourcen- und zeitintensiver und schwieriger in Ihren Build-Prozess zu integrieren als mit Gradle oder Maven.

  6. Getrennte Versionskontrolle.
    Dies ist ein kleiner Punkt, aber ich bevorzuge es wirklich, die Abhängigkeiten in separaten Repositories zu halten. Außerdem können Sie ein anderes Versionskontrollsystem (git) verwenden, da Sie nicht durch Mendix (svn) eingeschränkt sind. Und git hat bereits gute Vorlagen sowohl für Gradle- als auch für Maven-Ignorierlisten.

Schritt-für-Schritt-Anleitung

Um die obige Best Practice zu untermauern, gehen wir die Schritte für das Hinzufügen einer konkreten Bibliothek eines Drittanbieters durch. Wie wäre es mit einem Markdown-Parser ? Das eine Modul  im Mendix App Store zur Markdown-Konvertierung ist mittlerweile 7 Jahre alt und verwendet eine veraltete Bibliothek, die nicht mehr gepflegt wird, so dass dies ein schönes Upgrade wäre.

Das Ziel ist es, diese Bibliothek in einem Mendix-Projekt zu verwenden, um Markdown-Text in HTML zu konvertieren. Das Endergebnis sollte in etwa so aussehen: https://markdownconverter-sandbox.mxapps.io/.

Voraussetzungen

Ich werde Gradle für diese Anleitung verwenden. Maven kann allerdings genau dasselbe.

Gradle v5.5: kann mit Hilfe des offiziellen Tutorials installiert werden. Neuere oder ältere Versionen sollten auch funktionieren, aber dies ist diejenige, die in diesem Tutorial verwendet wird. Es ist ein Kommandozeilen-Tool, das sich um die Verwaltung von Abhängigkeiten, Shadowing und Building kümmert.

 

Schritt 1: Initialisieren Sie das Projekt

Erstellen Sie ein neues Git-Projekt in einem leeren Verzeichnis. Öffnen Sie dann ein Befehlszeilenfenster und geben Sie ein:

gradle init 

Dadurch wird der Prozess der Einrichtung eines Gradle-Projekts gestartet. Folgen Sie den Anweisungen und wählen Sie sorgfältig aus. Ich empfehle die unten stehenden Auswahlmöglichkeiten, aber Sie haben vielleicht andere Präferenzen:

  • Projekttyp: 3: Bibliothek (keine Notwendigkeit für eine Hauptmethode)
  • Sprache: 3: java
  • Build-Skript: 1: groovy
  • Test-Framework: 1: JUnit4

Nach Beendigung des init -Befehls hätte er eine Projektdateistruktur ähnlich wie folgende erzeugt:

best practice for adding a java dependency to Mendix_1

Einige wichtige Orte, die wir verwenden werden, sind:

  • src \ main - hier kommt der Java-Code hin
  • src \ test - hier kommt der Testcode hin
  • build.gradle - definiert Abhängigkeiten, Plugins und mehr

Schritt 2: Hinzufügen einer Abhängigkeit über Gradle

Der einfachste Weg, dies zu tun, ist, zum Maven Repository zu gehen und nach der Abhängigkeit zu suchen, die Sie hinzufügen möchten. Zum Beispiel ist dies die flexmark-Abhängigkeit. Auf dieser Seite gibt es ein Code-Snippet mit dem Befehl, den Sie verwenden können, um diese Abhängigkeit zu Ihrem Gradle-Projekt hinzuzufügen.

compile group: 'com.vladsch.flexmark', name: 'flexmark-all', version: '0.62.2'

Kopieren Sie diesen Codeschnipsel und fügen Sie ihn der Datei build.gradle  unter dependencies hinzu. Sie können andere Kompilierabhängigkeiten, die Gradle automatisch hinzugefügt hat, entfernen, sie sind nur als Beispiel da, aber stellen Sie sicher, dass Sie die Testabhängigkeit drin lassen, sonst werden die Tests nicht funktionieren.

 

Schritt 3: Schreiben und implementieren Sie eine Schnittstelle zur Bibliothek des Drittanbieters

Schließlich ist es an der Zeit, etwas Code zu schreiben. Sie können jeden Editor oder jede IDE verwenden, aber ich habe festgestellt, dass IntelliJ am zuverlässigsten mit gradle arbeitet. Das ist wichtig, denn ohne den Klassenpfad aufzulösen, um die Gradle-Abhängigkeiten zu finden, wird Ihr Code nicht kompiliert und wirft viele Fehler (und keine Autovervollständigung) auf.

Im Folgenden finden Sie eine einfache Schnittstelle für die Umwandlung von Markdown in HTML und eine Klasse, die diese implementiert (die ich größtenteils von hier  kopiert habe).

package flexmark.mendix;

import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.data.MutableDataSet;

public interface MarkdownToHTMLConverter {

// main method
String convert(String markdown);

// factory method
static MarkdownToHTMLConverter create() {
return new FlexmarkConverter();
}
}

class FlexmarkConverter implements MarkdownToHTMLConverter {

@Override
public String convert(String markdown) {
MutableDataSet options = new MutableDataSet();
Parser parser = Parser.builder(options).build();
HtmlRenderer renderer = HtmlRenderer.builder(options).build();
Node document = parser.parse(markdown);
String html = renderer.render(document);
return html;
}
}
Beachten Sie, dass Kategorien und Schnittstellen generell nicht in derselben Datei stehen sollten, ich habe es nur der Kürze halber getan.
 

Schritt 4: Schreiben von Unit-Tests

Da dies ein Bibliotheksprojekt ist, hat es keine Hauptkategorie. Der einfachste Weg zu überprüfen, ob etwas funktioniert, ist das Schreiben eines Tests. Das ist eigentlich perfekt, weil es uns dazu zwingt, Tests zu schreiben, die wir immer dann verwenden können, wenn wir in der Zukunft Änderungen vornehmen, um zu überprüfen, ob alles korrekt funktioniert.

Für den Zweck dieses Beitrags werde ich einen einzelnen einfachen Test hinzufügen. Für den produktiven Einsatz sollten Sie sicherstellen, dass Ihre Tests alle Aspekte der Bibliothek abdecken, die Sie verwenden wollen, und dass sie realistischen Input haben. Aber übertreiben Sie es nicht, das Ziel ist nicht, die Bibliothek selbst zu testen, da sie wahrscheinlich schon gut getestet ist.

package flexmark.mendix;

import org.junit.Assert;
import org.junit.Test;

public class MarkdownToHTMLConverterTest {

@Test public void basicTest() {
MarkdownToHTMLConverter converter = MarkdownToHTMLConverter.createConverter();
Assert.assertEquals("<p>This is <em>Sparta</em></p>\n", converter.convert("This is *Sparta*"));
}

}

Der Test kann aus IntelliJ heraus gestartet werden, indem man auf den kleinen grünen Run-Button klickt. Wenn die Tests gut ausfallen, ist der nächste Schritt das Paketieren (Build) der Bibliothek, damit sie in unser Mendix-Projekt importiert werden kann.

 

Schritt 5: Erstellen eines Fat Jars

Diese Funktion ist nicht standardmäßig in Gradle enthalten, daher müssen wir zuerst ein Gradle-Plugin installieren.

Fügen Sie den folgenden Codeschnipsel oben in der Datei  build.gradle  unter plugins  (oberhalb von java) ein:

id 'com.github.johnrengelman.shadow' version '5.1.0'

Dadurch wird das Plugin zum Projekt hinzugefügt und wir können neue Befehle mit Gradle verwenden. Geben Sie in einem Befehlszeilenfenster ein:

gradle shadowJar

Dadurch wird eine einzelne jar-Datei erzeugt, die alle Abhängigkeiten unter build\\libs\\ enthält. Dieser Vorgang muss jedes Mal wiederholt werden, wenn Sie Änderungen am Code oder an den Abhängigkeiten vornehmen.

 

Schritt 6: Shadowing

Shadowing ist der Prozess der Umbenennung von Java-Paketen auf Bytecode-Ebene, damit zwei Pakete mit demselben Namen in einer Java-App verwendet werden können. Dies wird in der Regel gemacht, um Versionskonflikte zwischen zwei verschiedenen Versionen eines Pakets zu vermeiden. In Gradle können Pakete durch Hinzufügen des folgenden Schnipsels am Ende der build.gradle -Datei beschattet werden. 

shadowJar { relocate 'org.apache', 'flexmark.mendix.org.apache' }

Dies wird alle Java-Pakete, die mit  org.apache  beginnen, in flexmark.mendix.org.apache  umbenennen. Um zu bestätigen, dass die Umbenennung funktioniert hat, prüfen Sie den Inhalt der jar-Datei mit einem Zip-Inspektor wie 7-zip.

Um zukunftssicher zu sein, ist es am besten, alle Abhängigkeiten zu überschatten, auch solche, die heute vielleicht kein Problem verursachen. Mehrere Abhängigkeiten können durch Hinzufügen mehrerer  relocate-Zeilen beschattet werden.

Leider behandelt Shadowing keine Bibliotheken, die sich auf Reflection verlassen. Wenn Sie also auf ein Problem beim Laden von Klassen stoßen, kann es erforderlich sein, den Shadowing-Modus für die betroffenen Bibliotheken aufzuheben.

 

Schritt 7: Verwendung der Bibliothek in Mendix

Kopieren Sie das fat jar aus  build\\libs\\  in Ihr Mendix-Projektverzeichnis in den Ordner  userlib 

Erstellen Sie dann eine Mendix-Java-Aktion, damit die Java-Bibliothek aus einem Microflow heraus aufgerufen werden kann. Die Anzahl und Art der Parameter und Rückgabewerte wird je nach Anwendungsfall variieren. Das Entwerfen von guten Java-Aktionen verdient wahrscheinlich einen eigenen Blog-Beitrag. Hier werde ich nur einen Trick erwähnen:

Benennen Sie die Parameter mit einem Unterstrich am Ende. Dies verhindert ein bekanntes Mendix-Problem, bei dem ein Parametername, der ein reserviertes Wort ist, in Java als Suffix verwendet wird. Der Unterstrich verhindert dies und ist beim Aufruf der Java-Aktion in einem Microflow eigentlich nicht sichtbar.

best practice for adding a java dependency to Mendix_2

Rufen Sie schließlich die Schnittstelle, die in Schritt 3 codiert wurde, von der Java-Aktion aus auf. Da wir eine Fassade verwenden, um die Komplexität der Drittanbieter-Bibliothek zu verbergen, besteht dieser Teil oft nur aus ein oder zwei Zeilen.

import flexmark.mendix.MarkdownToHTMLConverter;
 
// LINES OMMITED FOR BREVITY

@java.lang.Override
public java.lang.String executeAction() throws Exception
{
// BEGIN USER CODE
MarkdownToHTMLConverter converter = MarkdownToHTMLConverter.create();
return converter.convert(Markdown_);
// END USER CODE
}

Damit ist die Schritt-für-Schritt-Anleitung abgeschlossen. Den gesamten Quellcode finden Sie unter https://github.com/gajduk/flexmark-mendix.

 

Zusammenfassung

Das Hinzufügen von Java-Bibliotheken zu Mendix kann ziemlich knifflig sein. Einfach Dinge in den userlib-Ordner zu werfen, kann zu Problemen führen. Im Laufe der Jahre bin ich auf viele Probleme gestoßen, die mich dazu gebracht haben, den oben beschriebenen Prozess zu entwickeln.

Mein Prozess ist bei weitem nicht perfekt, wenn Sie also Verbesserungsvorschläge haben, kontaktieren Sie mich bitte über Mendix Slack oder per E-Mail, es wäre toll mehr zu erfahren.

Wie sieht Ihr Prozess für das Hinzufügen von Drittanbieter-Abhängigkeiten aus?

Ich hoffe, dass Ihnen dieser Blog-Beitrag gefallen hat und dass er Ihnen hilft, einfacher mit Java-Abhängigkeiten zu arbeiten.

Andrej Gajduk

Andrej Gajduk

Andrej Gajduk is a consultant at Mansystems with over 7 years of experience in software development. Currently, he is a lead developer for Application Test Suite.

Zusammenhängende Posts

Best Practices für das Schreiben von Custom Actions in Mendix

Da sogenannte Actions die wichtigste Art der Verwendung vieler App-Store-Module sind, lohnt es sich, etwas Zeit und Gedanken in die Gestaltung guter ...

Lesen Sie mehr

Wie Sie Ihrer Mendix App in 5 Minuten ein Dark Theme hinzufügen?

Ja, ich weiß, der Titel scheint ein bisschen zu schön, um wahr zu sein. Jede Web-App hat eine Menge an benutzerdefiniertem Styling und ...

Lesen Sie mehr

Progressive Web Apps: Chancen durch mobile Interaktion

Progressive Web Apps (PWAs) finden in E-Commerce und Industrie bereits breite Anwendung, während sie im Einzelhandel noch nicht so häufig anzutreffen ...

Lesen Sie mehr