Sensei Feature-Highlight: Bibliotheksumfang

Veröffentlicht Jun 09, 2021
von Nick Van Haver
FALLSTUDIE

Sensei Feature-Highlight: Bibliotheksumfang

Veröffentlicht Jun 09, 2021
von Nick Van Haver
Ressource anzeigen
Ressource anzeigen

Abhängigkeiten flexibel managen

Die Scope-Funktionalität von Sensei war schon immer ein Favorit der Entwickler. Mit der Möglichkeit, den Anwendungsbereich eines Rezepts zu erweitern oder einzuschränken, konnten Entwicklungsteams die Verwendung des Rezepts an einzelne Projekte und Branchen innerhalb ihrer Organisationen anpassen - was den Entwicklern die Möglichkeit gab, ihre Erfahrung zu personalisieren.

Und verständlicherweise steht sie im Mittelpunkt der kontinuierlichen Innovationsprozesse von Sensei. Während eines Innovations-Brainstormings zur Erweiterung des "Scope" (ja, Wortspiel beabsichtigt) kam eine Frage auf: 

"Ich habe versucht, ein Rezept für ... zu erstellen, aber seit Version x hat das Framework die Funktion veraltet. Ich bin mir nicht sicher, ob es noch sinnvoll ist, ein Rezept zu erstellen. Was denken Sie?"

Natürlich ist dies nicht das erste Mal, dass wir gezögert haben, ein Rezept zu erstellen. Während das Rezept als Bereitstellung redundanter Informationen angesehen werden könnte, glauben wir, dass es wertvoll ist, etwas zu erstellen, das auf eine begrenzte Anzahl von Versionen der beteiligten Abhängigkeit anwendbar ist. Und deshalb haben wir den Library-Bereich erstellt.

Mit dem Bibliotheksumfang können wir prüfen, ob eine Abhängigkeit im Projekt vorhanden ist und Sensei Rezepte bedingt anwenden. Dies bietet große Flexibilität, wenn Teams durch Legacy-Code und Abhängigkeiten navigieren.

Viele von Ihnen kennen vielleicht den Bibliotheksbereich, der bereits unter Allgemeine Einstellungen verfügbar ist. Was ist das also, fragen Sie? Wir haben dafür gesorgt, dass der Bibliotheksbereich in YAML vorhanden ist, genau wie die Suche. Dies schafft ein besseres Benutzererlebnis und unterbricht nicht den Fluss beim Erstellen des Rezepts, bei dem Sie sonst zu den Allgemeinen Einstellungen und zurück navigieren müssten, um die Metadaten zu aktualisieren. Weitere dieser Scopes werden in YAML Einzug halten, aber wir haben mit dem Library Scope begonnen.

Lassen Sie uns also anhand eines Beispiels ein wenig tiefer in die Funktionsweise eintauchen.

Bibliotheksumfang, der auf hibernate-jpamodelgen angewendet wird

Stellen Sie sich den folgenden Fall vor: 

Wir möchten eine Spring Web REST-API erstellen, mit der wir einige Daten abfragen können. Gemäß den Best Practices erstellen wir ein Modell für die Entität, die wir abfragen wollen. Als Nächstes fügen wir eine Abhängigkeit zum Hibernate ORM hinzu, damit wir uns nicht mit der Datenbankstruktur herumschlagen müssen. Der ORM übernimmt das für uns. Außerdem müssen wir einen Dienst erstellen, der die Daten aus der Datenzugriffsschicht (CRUD-Repositories usw.) für den Controller bereitstellt. Schließlich erstellen wir die Controller-Klasse für unsere API, in der wir die zulässigen Abfragen als Endpunkte bereitstellen.

Um zu vermeiden, dass wir für jedes abfragbare Feld unterschiedliche Endpunkte bereitstellen müssen, entscheiden wir uns stattdessen für die Verwendung von JPA 2-Spezifikationen. Dazu erstellen wir eine Spezifikation im Controller aus der Anfrage-URL. Diese Spezifikation beschreibt, wie die Entitäten, nach denen wir suchen, aussehen sollen. In der Klasse `Specification` selbst implementieren wir die Methode `toPredicate`, um anzugeben, wie die Spezifikation validiert werden kann.

Aber wir stehen vor einem Problem in der Methode "toPredicate". Um das Prädikat zu konstruieren, müssen wir die Namen der zu vergleichenden Spalten in der Datenbank kennen. Da wir aber ein ORM verwenden, haben wir diese Spalten nicht in einem separaten Modell. Also kommt der JPA 2 Metamodel Generator() von Hibernate zur Rettung! Dieser hilft dabei, ein Metamodell für die Entitäten zu generieren, die wir angefordert haben. Diese Metamodelle ermöglichen es uns, die Spaltennamen als Eigenschaften zu referenzieren, anstatt sie hart zu kodieren.

Erstellen des Rezepts Sensei

Jetzt, wo wir die Metamodelle generiert haben, wollen wir sie sinnvoll einsetzen. Sensei kann jedem, der an dem Projekt arbeitet, helfen, indem es ihn daran erinnert, das Metamodell zu verwenden, und sicherstellt, dass die Spaltennamen nirgendwo hardcodiert sind. Lassen Sie uns das also in die Praxis umsetzen.

Zunächst werfen wir einen Blick auf die Methode `toPredicate`.

Zur Prädikatsmethode

Dieses einfache Prädikat vergleicht nur den Namen unserer Entität. Wir können es mit "und"-Klauseln erweitern, aber für den Zweck dieses Rezepts ist diese "einfache" Prüfung ausreichend.

Für die Suchkomponente des Rezepts wollen wir die Methode `get()` des Root-Parameters aufrufen, also wählen wir die Option `methodcall` aus dem Dropdown. Als nächstes wollen wir die Suche auf einen Methodenaufruf mit dem Namen `get` beschränken, dessen Signatur in der Schnittstelle `Path` des Pakets `javax.persistence.criteria` deklariert ist. Da die Methode überladen wurde, müssen wir der Suche auch mitteilen, dass unser Rezept nur für die Variante gilt, die einen einzelnen String als Argument nimmt. Um das Problem mit den Spaltennamen im Code zu beheben, möchten wir stattdessen ein Argument vom Typ `SingularAttribute` verwenden, demselben Typ, der vom Metamodell-Generator bereitgestellt wird.

Einstellen der Suchkriterien für das Rezept

Das Rezept, das wir bisher erstellt haben, wird auf jeder Codebasis ausgelöst, die die JPA 2 `Path`-Schnittstelle verwendet, unabhängig davon, ob die Codebasis für die Verwendung des Hibernate Model Generator eingerichtet ist. Wenn diese Bibliothek im Projekt vorhanden ist, möchten wir dem Benutzer anzeigen, dass sie verwendet werden soll, also fügen wir dem Rezept einen Bibliotheksbereich hinzu.

Einschränkung des Suchumfangs für dieses Rezept

Und schließlich ist unser Rezept nun fertig.

Testrezept MethodeAufruf

Mit diesem Rezept wird jedes Auftreten von `Path#get`, das einen String-Wert als Argument verwendet, gekennzeichnet. Wie Sie an dem hervorgehobenen Beispielcode im obigen Screenshot erkennen können, funktioniert dieses Rezept auch dann, wenn der literale Name des Spaltennamens in einer Zwischenvariablen gespeichert ist.

Hinweis - Wir können den Bibliotheksbereich auch invertieren, um den Fall zu behandeln, dass die Bibliothek nicht verfügbar ist, indem wir dem Bereich eine "not"-Klausel voranstellen.

Fazit

Wie wir im obigen Beispiel gesehen haben, können wir mit dieser neuen Funktion nützlichere Rezepte erstellen, indem wir sie basierend auf dem Vorhandensein von Abhängigkeiten im Projekt anwenden. Um die Leistungsfähigkeit noch weiter zu erhöhen, haben wir mehr Optionen als im Beispiel gezeigt aufgenommen, wie z. B. nicht nur zu prüfen, ob die Abhängigkeit vorhanden ist, sondern auch Bedingungen auf die spezifische Version der Abhängigkeit anzuwenden. 

Die Hauptanwendungsfälle, die wir für diese Funktion sehen, sind das Verhindern, dass Rezepte doppelte Informationen bereitstellen, das Erkennen von Problemen im Zusammenhang mit bestimmten Versionen von Abhängigkeiten, aber auch die Durchführung von Migrationen von einer Abhängigkeitsversion zur nächsten. Wir freuen uns darauf, von Ihnen zu hören, welche Anwendungen Sie für diese Funktion sehen.

Wie bei allen Funktionen von Sensei finden Sie weitere Informationen über den Umfang der Bibliothek in der Referenzdokumentation.

Ressource anzeigen
Ressource anzeigen

Autor

Nick Van Haver

Sie wollen mehr?

Tauchen Sie ein in unsere neuesten Erkenntnisse über sichere Kodierung im Blog.

Unsere umfangreiche Ressourcenbibliothek zielt darauf ab, die menschliche Herangehensweise an eine sichere Weiterbildung im Bereich der Programmierung zu stärken.

Blog ansehen
Sie wollen mehr?

Holen Sie sich die neuesten Forschungsergebnisse zur entwicklergesteuerten Sicherheit

Unsere umfangreiche Ressourcenbibliothek ist voll von hilfreichen Ressourcen, von Whitepapers bis hin zu Webinaren, die Ihnen den Einstieg in die entwicklungsorientierte sichere Programmierung erleichtern. Erforschen Sie sie jetzt.

Ressourcendrehscheibe

Sensei Feature-Highlight: Bibliotheksumfang

Veröffentlicht Jun 09, 2021
Von Nick Van Haver

Abhängigkeiten flexibel managen

Die Scope-Funktionalität von Sensei war schon immer ein Favorit der Entwickler. Mit der Möglichkeit, den Anwendungsbereich eines Rezepts zu erweitern oder einzuschränken, konnten Entwicklungsteams die Verwendung des Rezepts an einzelne Projekte und Branchen innerhalb ihrer Organisationen anpassen - was den Entwicklern die Möglichkeit gab, ihre Erfahrung zu personalisieren.

Und verständlicherweise steht sie im Mittelpunkt der kontinuierlichen Innovationsprozesse von Sensei. Während eines Innovations-Brainstormings zur Erweiterung des "Scope" (ja, Wortspiel beabsichtigt) kam eine Frage auf: 

"Ich habe versucht, ein Rezept für ... zu erstellen, aber seit Version x hat das Framework die Funktion veraltet. Ich bin mir nicht sicher, ob es noch sinnvoll ist, ein Rezept zu erstellen. Was denken Sie?"

Natürlich ist dies nicht das erste Mal, dass wir gezögert haben, ein Rezept zu erstellen. Während das Rezept als Bereitstellung redundanter Informationen angesehen werden könnte, glauben wir, dass es wertvoll ist, etwas zu erstellen, das auf eine begrenzte Anzahl von Versionen der beteiligten Abhängigkeit anwendbar ist. Und deshalb haben wir den Library-Bereich erstellt.

Mit dem Bibliotheksumfang können wir prüfen, ob eine Abhängigkeit im Projekt vorhanden ist und Sensei Rezepte bedingt anwenden. Dies bietet große Flexibilität, wenn Teams durch Legacy-Code und Abhängigkeiten navigieren.

Viele von Ihnen kennen vielleicht den Bibliotheksbereich, der bereits unter Allgemeine Einstellungen verfügbar ist. Was ist das also, fragen Sie? Wir haben dafür gesorgt, dass der Bibliotheksbereich in YAML vorhanden ist, genau wie die Suche. Dies schafft ein besseres Benutzererlebnis und unterbricht nicht den Fluss beim Erstellen des Rezepts, bei dem Sie sonst zu den Allgemeinen Einstellungen und zurück navigieren müssten, um die Metadaten zu aktualisieren. Weitere dieser Scopes werden in YAML Einzug halten, aber wir haben mit dem Library Scope begonnen.

Lassen Sie uns also anhand eines Beispiels ein wenig tiefer in die Funktionsweise eintauchen.

Bibliotheksumfang, der auf hibernate-jpamodelgen angewendet wird

Stellen Sie sich den folgenden Fall vor: 

Wir möchten eine Spring Web REST-API erstellen, mit der wir einige Daten abfragen können. Gemäß den Best Practices erstellen wir ein Modell für die Entität, die wir abfragen wollen. Als Nächstes fügen wir eine Abhängigkeit zum Hibernate ORM hinzu, damit wir uns nicht mit der Datenbankstruktur herumschlagen müssen. Der ORM übernimmt das für uns. Außerdem müssen wir einen Dienst erstellen, der die Daten aus der Datenzugriffsschicht (CRUD-Repositories usw.) für den Controller bereitstellt. Schließlich erstellen wir die Controller-Klasse für unsere API, in der wir die zulässigen Abfragen als Endpunkte bereitstellen.

Um zu vermeiden, dass wir für jedes abfragbare Feld unterschiedliche Endpunkte bereitstellen müssen, entscheiden wir uns stattdessen für die Verwendung von JPA 2-Spezifikationen. Dazu erstellen wir eine Spezifikation im Controller aus der Anfrage-URL. Diese Spezifikation beschreibt, wie die Entitäten, nach denen wir suchen, aussehen sollen. In der Klasse `Specification` selbst implementieren wir die Methode `toPredicate`, um anzugeben, wie die Spezifikation validiert werden kann.

Aber wir stehen vor einem Problem in der Methode "toPredicate". Um das Prädikat zu konstruieren, müssen wir die Namen der zu vergleichenden Spalten in der Datenbank kennen. Da wir aber ein ORM verwenden, haben wir diese Spalten nicht in einem separaten Modell. Also kommt der JPA 2 Metamodel Generator() von Hibernate zur Rettung! Dieser hilft dabei, ein Metamodell für die Entitäten zu generieren, die wir angefordert haben. Diese Metamodelle ermöglichen es uns, die Spaltennamen als Eigenschaften zu referenzieren, anstatt sie hart zu kodieren.

Erstellen des Rezepts Sensei

Jetzt, wo wir die Metamodelle generiert haben, wollen wir sie sinnvoll einsetzen. Sensei kann jedem, der an dem Projekt arbeitet, helfen, indem es ihn daran erinnert, das Metamodell zu verwenden, und sicherstellt, dass die Spaltennamen nirgendwo hardcodiert sind. Lassen Sie uns das also in die Praxis umsetzen.

Zunächst werfen wir einen Blick auf die Methode `toPredicate`.

Zur Prädikatsmethode

Dieses einfache Prädikat vergleicht nur den Namen unserer Entität. Wir können es mit "und"-Klauseln erweitern, aber für den Zweck dieses Rezepts ist diese "einfache" Prüfung ausreichend.

Für die Suchkomponente des Rezepts wollen wir die Methode `get()` des Root-Parameters aufrufen, also wählen wir die Option `methodcall` aus dem Dropdown. Als nächstes wollen wir die Suche auf einen Methodenaufruf mit dem Namen `get` beschränken, dessen Signatur in der Schnittstelle `Path` des Pakets `javax.persistence.criteria` deklariert ist. Da die Methode überladen wurde, müssen wir der Suche auch mitteilen, dass unser Rezept nur für die Variante gilt, die einen einzelnen String als Argument nimmt. Um das Problem mit den Spaltennamen im Code zu beheben, möchten wir stattdessen ein Argument vom Typ `SingularAttribute` verwenden, demselben Typ, der vom Metamodell-Generator bereitgestellt wird.

Einstellen der Suchkriterien für das Rezept

Das Rezept, das wir bisher erstellt haben, wird auf jeder Codebasis ausgelöst, die die JPA 2 `Path`-Schnittstelle verwendet, unabhängig davon, ob die Codebasis für die Verwendung des Hibernate Model Generator eingerichtet ist. Wenn diese Bibliothek im Projekt vorhanden ist, möchten wir dem Benutzer anzeigen, dass sie verwendet werden soll, also fügen wir dem Rezept einen Bibliotheksbereich hinzu.

Einschränkung des Suchumfangs für dieses Rezept

Und schließlich ist unser Rezept nun fertig.

Testrezept MethodeAufruf

Mit diesem Rezept wird jedes Auftreten von `Path#get`, das einen String-Wert als Argument verwendet, gekennzeichnet. Wie Sie an dem hervorgehobenen Beispielcode im obigen Screenshot erkennen können, funktioniert dieses Rezept auch dann, wenn der literale Name des Spaltennamens in einer Zwischenvariablen gespeichert ist.

Hinweis - Wir können den Bibliotheksbereich auch invertieren, um den Fall zu behandeln, dass die Bibliothek nicht verfügbar ist, indem wir dem Bereich eine "not"-Klausel voranstellen.

Fazit

Wie wir im obigen Beispiel gesehen haben, können wir mit dieser neuen Funktion nützlichere Rezepte erstellen, indem wir sie basierend auf dem Vorhandensein von Abhängigkeiten im Projekt anwenden. Um die Leistungsfähigkeit noch weiter zu erhöhen, haben wir mehr Optionen als im Beispiel gezeigt aufgenommen, wie z. B. nicht nur zu prüfen, ob die Abhängigkeit vorhanden ist, sondern auch Bedingungen auf die spezifische Version der Abhängigkeit anzuwenden. 

Die Hauptanwendungsfälle, die wir für diese Funktion sehen, sind das Verhindern, dass Rezepte doppelte Informationen bereitstellen, das Erkennen von Problemen im Zusammenhang mit bestimmten Versionen von Abhängigkeiten, aber auch die Durchführung von Migrationen von einer Abhängigkeitsversion zur nächsten. Wir freuen uns darauf, von Ihnen zu hören, welche Anwendungen Sie für diese Funktion sehen.

Wie bei allen Funktionen von Sensei finden Sie weitere Informationen über den Umfang der Bibliothek in der Referenzdokumentation.

Wir bitten Sie um Ihre Erlaubnis, Ihnen Informationen über unsere Produkte und/oder verwandte Themen der sicheren Codierung zuzusenden. Wir werden Ihre persönlichen Daten immer mit äußerster Sorgfalt behandeln und sie niemals zu Marketingzwecken an andere Unternehmen verkaufen.

Senden
Um das Formular abzuschicken, aktivieren Sie bitte "Analytics"-Cookies. Sie können die Cookies wieder deaktivieren, sobald Sie fertig sind.