JSF+Bean Validation, Groups – switch

Bean Validation (JSR 380) und Jave Server Faces sind inzwischen ein eingespieltes Team und werden in den meisten Projekte eingesetzt. Ein nettes Features welches wir schon in einem älteren Blog-Beitrag beleuchtet haben ( hier ) sind Validierungs-Gruppen mit denen wir unterschiedliche Regel-Sets zusammenstellen können

Wie schon im angesprochenen Artikel erläutert arbeiten wir bei den BeanValidation Groups mit einem Marker-Interface:

public class DemoModel {

    @NotNull(groups = OnTransmit.class)
    @Size(min = 4, groups = OnTransmit.class)
    private String firstname;

    @NotNull(groups = {Default.class, OnTransmit.class})
    @Size(min = 4, groups = {Default.class, OnTransmit.class})
    private String lastname;
}

Diese Gruppen lassen sich dann entwede programmatisch bei der Validierung heranziehen oder seit JSF 2.1 mittels f:validateBean in unserem JSF Template referenzieren. Doch was tun wenn wir dynamisch entscheiden wollen welche Gruppen zur Validierung heran gezogen werden sollen? Sagen wir auf Basis des verwendeten Buttons? Das macht die Sache hier schon etwas schwieriger. JSF bietet hier allerdings eine Möglichkeit, in der faces-config.xml registrieren wir einen globalen Validator:

    <application>
        <default-validators>
            <validator-id>ConditionalBeanValidator</validator-id>
        </default-validators>
        <validator>
            <validator-id>ConditionalBeanValidator</validator-id>
            <validator-class>de.gedoplan.blog.jsf.validation.ConditionalBeanValidator</validator-class>
        </validator>
    </application>
public class ConditionalBeanValidator extends BeanValidator {

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) {
        setValidationGroups(retrieveValidationGroup(context));
        super.validate(context, component, value);
    }

    private String retrieveValidationGroup(FacesContext context) {
        if (context.getExternalContext().getRequestParameterValuesMap().containsKey("GEDTRANSMIT")) {
            return OnTransmit.class.getName();
        }

        return null;

    }
}

Dieser Validator ( implementiert javax.faces.validator.BeanValidator ) kann nun entscheiden/festlegen welche Bean Validation Gruppen verwendet werden sollen, ganz global, ohne das wir jedes einzelne Eingabefeld mit einem entsprechenden Binding versehen müssen. Idealerweise dient dafür ein fachliches Statusfeld, sollte so etwas nicht vorhanden sein ist auch folgendes Vorgehen über einen entsprechenden HTTP Parameter der beim Button angegeben wird denkbar:

                <h:commandButton action="#{demoController.submit()}" value="submit" id="submit"/>
                <h:commandButton action="#{demoController.transmit()}" value="transmit" id="transmit">
                    <f:param name="GEDTRANSMIT" />
                </h:commandButton>

Achtung! An dieser Stelle ist vorsicht geboten = in diesem Beispiel wird die Auswahl der Validierungs-Gruppe über einen Request-Parameter gesteuert, technisch wäre es durch Manipulation des HTTP Requests also möglich die transmit() Methode auf zu rufen ohne das die korrekte Validierung abläuft. Bei kritischen Prozessen sollte hier in der „transmit“ Methode (bzw. in einem entsprechenden Service) die korrekte Validierung (nocheinmal) durchgeführt werden oder zumindest das Vorhandensein des Parameters geprüft werden.

Github? Klaro

https://github.com/GEDOPLAN/jsf-custom-validator

Werbeanzeigen

NetBeans – Ordner ausblenden

Immer mal wieder kommt es vor das wir in unseren Projekt-Ordnern Inhalte vorfinden die nicht teil unserer direkten Arbeiten sind. Das können generierte Bestandteile aus anderen Prozessen sein oder in der Web-Entwicklung so etwas wie der „node-modules“ Ordner ( Projekt Abhänigkeiten ).

Das macht unsere IDE zum einen unnötig langsam da diese Ordner / Strukturen ja genauso analysiert und ausgewertet werden wie unsere eigenen Sourcen und auf der anderen Seite meldet NetBeans hier regelmäßig Fehler auf die wir jedoch keinen Einfluss haben. Es gab einmal ( in PHP Projekten wohl immer noch ) eine Möglichkeit in NetBeans Ordner für die IDE aus zu blenden. Diese Funktion ist leider verschwunden und steht für Java- und HTML5-Projekte nicht zur Verfügung. In einem NetBeans-BugTicket zu dem Thema hat jemand eine schnelle und einfach Lösung entwickelt: https://netbeans.org/bugzilla/show_bug.cgi?id=238709#c28

Durch ein kleine Plugin welches installiert werden kann ( getestet mit NetBeans 8,9 und 10) und das Anlegen einer Datei „.nbignore“ im betreffenden Ordner wird dieser einfach ausgeblendet.

Optimal ist die Lösung sicherlich nicht: der Ordner verschwindet aus der Anzeige der IDE vollständig und kann nur über den normalen Explorer noch bearbeitet werden das muss dem Entwickler bewusst sein. Zudem ist es unschön IDE-spezifische Dateien in unseren Projekten ab zu legen. Eine einfache und prakmatische Lösung ist es trotzdem und allemal besser als falsche Fehlermeldungen. Bleibt zu hoffen das wir diese Funktion eines Tages auch nativ wieder in NetBeans finden werden…


JEE Klassen > TypeScript

Ein JEE Backend ist mit wenig Aufwand über eine JSON basierte REST-Schnittstelle zur Verfügung gestellt. An diesem Punkt kann sich der Java Entwickler zurücklehnen und die Angular Entwickler machen lassen. Als Fullstackentwickler ( oder freundlicher Java Entwickler ) können wir uns ( oder unseren Kollegen ) das Leben leicht leichter machen.

In aller Regel werden wir unsere Angular Anwendung mittels TypeScript schreiben und hier immer wo es geht auf ein typsicheres Vorgehen setzen. Das erfordert es allerdings eigene TypeScript Definitionsdateien zu schreiben welche unsere Datenmodelle ( die wir ja bereits in Java geschrieben haben ) in die TypeScript-Welt bringt. Ein Maven-Plugin welches hier Hilft:

cz.habarta.typescript-generator # typescript-generator-maven-plugin

Dieses registrieren wir in unserer pom.xml, versehen mit einigen zusätzlichen Konfigurationen und wir erhalten eine *.d.ts Datei welche wir in die Angular Entwicklung mit einfließen lassen können:

    <build>
        <plugins>
            <plugin>
                <groupId>cz.habarta.typescript-generator</groupId>
                <artifactId>typescript-generator-maven-plugin</artifactId>
                <version>2.12.476</version>
                <executions>
                    <execution>
                        <id>generate</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <phase>process-classes</phase>
                    </execution>
                </executions>
                <configuration>
                    <jsonLibrary>jackson2</jsonLibrary>
                
                    <classesFromAutomaticJaxrsApplication>true</classesFromAutomaticJaxrsApplication>
                    <outputKind>module</outputKind>
                </configuration>
            </plugin>
        </plugins>
    </build>

Das funktioniert relativ gut, scheitert natürlich wenn wir mittels JSON-Mapper in die Struktur der generierten JSON-Nachricht eingreifen. Zum Beispiel übermitteln wir bei Relationen (User hat eine Liste von Projekten) sehr häufig lediglich die IDs der Projekte. In unseren TypeScript – Modelklassen werden wir aber gemäß Java-Klassen ein Objekt vom Typ „Projekt“ vorfinden. Hier müssen wir entweder manuell eingreifen, die generierten Klassen erweitern / überschreiben. Oder im Programm durch entsprechende Casts gegensteuern.

Angular – eigene ReactiveForm Komponenten

In größeren Projekten werden wir relativ schnell den Punkt erreichen in dem sich der ein oder andere Entwickler denkt: „Moment das hatten wir doch schon mal“. Wenn noch nicht geschehen ist das der Zeitpunkt um für den so identifizierten Bereich / Funktion eine eigene Komponente aus zu bilden. Wenn es sich dabei um ein Form-Element handelt mag es zuerst einmal nicht so offensichtlich sein wie man das am besten bewerkstelligt…

Nehmen wir ein einfaches konkretes Beispiel: in unserer Anwendung haben wir eine Auswahlbox von Benutzern durch die z.B. eine Aufgabe, ein Projekt etc. zugeordnet werden soll. Diese Auswahl von Benutzern wird nun an verschiedenen Stellen der Anwendung benötigt. Also entwickeln wir eine eigenen Komponente, was dank Angular-CLI ja auch ein Kinderspiel ist:

ng generate component UserSelector

So einfach ist es in diesem Beispiel jedoch erst einmal nicht. Das Ziel soll es ja sein unsere Komponente als Teil eines Formulars zu verwenden und eine Deklaration analog zu den Standard-HTML Elementen zu erreichen:

<form [formGroup]="form">
  <label for="user">Benutzer: </label>
  <app-user-selector formControlName="userId" id="user"></app-user-selector>
  <label for="comment">Kommentar: </label>
  <input type="text" id="comment" formControlName="comment"/>
</form>

app.component.html > Verwendung unserer Komponente

wir wollen hier einen ReactiveForm-Ansatz verfolgen bei dem die Registrierung von Datenmodel und Validatoren in der Komponentenklasse geschieht, dazu wird hier der Name des Controls mittels ‚formControlName‘ eingesetzt. Die Alternative wäre der Einsatz von „ngModel“

In unserem Projekt setzen wir PrimeNG als Komponentenbibliothek ein, unsere UserSelector Komponente wird also lediglich eine Art Wrapper, hier das Template:

<span [formGroup]="form">
  <p-dropdown
    [options]="users"
    optionLabel="name"
    class="form-control"
    [autoDisplayFirst]="false"
    dataKey="id"
    formControlName="value"
  ></p-dropdown>
</span>

user-selector-component.html > Template unserer Komponente

wir verwenden hier eine PrimeNG Komponente ‚p-dropdown‘. Für unsere eigene Komponente spannend ist hier die Erzeugung einer eigenen FormGroup innerhalb unserer Komponente, das ermöglicht uns die PrimeNG Komponente innerhalb „ganz normal“ mit unserer Komponenten-Klasse zu verbinden

import { Component, OnInit, forwardRef } from '@angular/core';
import { FormGroup, ControlValueAccessor, NG_VALUE_ACCESSOR, FormBuilder } from '@angular/forms';
import { DemoService } from '../demo.service';

// 1
@Component({
  selector: 'app-user-selector',
  templateUrl: './user-selector.component.html',
  styleUrls: ['./user-selector.component.css'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => UserSelectorComponent),
      multi: true
    }
  ]
})
//2
export class UserSelectorComponent implements ControlValueAccessor {
  users: any[];

  form: FormGroup;

  //3
  constructor(private service: DemoService, builder: FormBuilder) {
    service.getAll().subscribe(r => (this.users = r));

    this.form = builder.group({
      value: ['']
    });
    //4
    this.form.controls.value.valueChanges.subscribe(c => {
      this.onChange(c.id);
    });
  }

  //5
  writeValue(obj: number): void {
    if (obj) {
      const value = this.users.find(e => e.id == obj);
      if (value) this.form.patchValue({ value });
    }
  }

  //6
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  onChange: any = () => {};
  onTouched: any = () => {};
}

user-selector-component.ts > Komponentenklasse

1. die Metadaten für unsere Komponente. Neu an dieser Stelle ist die Registrierung unserer Komponente als Value-Accessor über das Provider Array, sehr einfach ausgedrückt ist dieses Deklaration bei jeder dieser Komponenten technisch bedingt genau so zu deklarieren ( sehr spannende Angular-Hintergrund-Themen zu dieser Deklaration: ‚Multi Providers‘ und ‚forwardRef‘ )

2. wir Implementieren das Interface ControlValueAccessor

3. Konstruktor. Neben einem Demo-Service ( der uns die Daten für unsere Liste ermittelt), lassen wir uns auch den FormBuilder von Anuglar injizieren um die FormGroup auf zu bauen

4. hier wird es spannender: wir registrieren einen Change-Listener an unserer internen FormControl ( die PrimeNG Dropdown-Liste ). Wenn der User hier eine Änderungen vornimmt wollen wir dieses Event „weiter geben“ und den Verwender unserer Komponente informieren, dazu wird die Methode onChange ( Interface ) verwendet. ( In unserem Beispiel nehmen wir hier auch eine Umwandlung vor: unserer DropDown-Liste liefert ein komplexes User-Objekt, in unserer Anwendung, also in den anderen fachlichen Objekten verwenden wir lediglich die Id.

5. writeValue ( Interface ) ist die Methode welche aufgerufen wir um ein Objekt welches aus dem Model kommt in der UI darzustellen, also beim Rendern oder bei Änderungen der Form. Wir bekommen an dieser Stelle die Id des bereits selektierten Benutzers, anhand dessen wir das komplexe User-Objekt aus unserem Array ermitteln und unser internes Formular damit aktualisieren.

6. Interface Methoden um die Registrierungen von EventListenern zu ermöglichen

Das war’s damit haben wir eine Komponente welche ganz einfach in unseren Formularen eingesetzt werden kann. Auf diese Weise lassen sich natürlich auch gänzlich eigene Komponenten ( ohne PrimeNG ) implementieren oder wesentlich komplexere wiederverwendbare Komponenten.

Noch mal gucken? > GITHUB

Angular strukturiert 2/2 – @NgModule

Umfangreiche Angular Projekte bestehen in aller Regel aus sehr vielen Komponenten und Service-Klassen die in eine sinnvolle Struktur gebracht werden müssen. Darüber hinaus macht es auch aus Performance Gründen Sinn die eigene Anwendung zu unterteilen. Im ersten Teil haben wir einen Blick auf die Organisation mittels Workspace geworfen. Heute schauen wir uns die Verwendung von Modulen an.

Jede Angular Anwendung besteht aus einem NgModule. Bei genauerer Betrachtung eher aus sehr vielen Modulen, ist doch auch die Core-Bibliothek von Angular in Modulen aufgeteilt ( BrowserModule. FormsModule … ) die wir bei Bedarf importieren. Aber auch unsere eigene Anwendung können wir mittels Module in einzelne Blöcke unterteilen. Neben der besseren Struktur unserer Anwendung hat das noch einen ganz entscheidenden Vorteil: Performance. Wir können komplexe Angular Anwendung in fachliche Teilbereiche gliedern und für jeden dieser Teile ein eigenes Modul implementieren. Ein User der unsere Anwendung aufruft wird nun nicht beim ersten Zugriff unsere gesamte Anwendung laden müssen sondern nur den Bereich ( Modul ) den er gerade anfragt. Erst wenn der User über entsprechende Navigation auf andere Bereiche zugreift werden diese Anwendungsteile geladen. Hier in Kürze wie das geht:

1. ng new [app-name]

Neue Anwendung erzeugen, die in unserem Beispiel nur die Startseite beinhaltet +  gemeinesame Komponente + gemeinsame Services

2. ng generate module [module-1]

Neues Modul generieren, z.B. „materials“ oder „customers“ oder „users“

3. Routing anpassen

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home', component: HomeComponent },
  { path: 'customer', 
   loadChildren: './customers/customers.module#CustomersModule' },
  { path: 'material', 
   loadChildren: './materials/materials.module#MaterialsModule' }
];

Der spannende Teil ist hier die Deklaration der Navigation auf die neuen Module, über die Eigenschaft „loadChildren“ wird hier der relative Pfad zur Module Datei angegeben + der Klassenname des Moduls (getrennt mittels „#“). Der Build Prozess resultiert dann in separaten JavaScript Dateien für die jedes Modul welche nur beim auslösen der entsprechenden Navigation abgerufen wird.

Zusammen mit Teil 1 hier auf github

Angular strukturiert 1/2 – workspace

Umfangreiche Angular Projekte bestehen in aller Regel aus sehr vielen Komponenten und Service-Klassen die in eine sinnvolle Struktur gebracht werden müssen. Darüber hinaus macht es auch aus Performance Gründen Sinn die eigene Anwendung zu unterteilen. Im ersten Teil werfen wir einen Blick auf die Organisation mittels Workspace.

In allen unseren Projekten werden wir den ein oder anderen Service Implementieren oder Komponenten ausprägen die nicht nur für das vorliegende Projekt interessant sind, sondern auch für anderen unternehmenseigene Projekte. Eine solche eigene Basis-Bibliothek lässt sich natürlich als eigenständiges NPM-Packet entwickeln und über ein internes Node-Repository ausliefern. Insbesondere zur frühen Entwicklungszeit, wenn sich noch viel in den Bibliotheken tut verkompliziert dieses Vorgehen aber die Bereitstellung und Verwendung. Eine Alternative (die sich aber später ebenfalls problemlos als NPM-Paket veröffentlichen lässt) ist seit der Version 6 in Angular-CLI vorhanden: „Libraries“ .

Die Grundidee ist einfach: ein einzelnes Angular-Projekt  (workspace)  dient als Basis für die Entwicklung unserer Anwendungen und Bibliotheken. Für jede Bibliothek ( library) oder Anwendung( application ) werden über entsprechende CLI-Befehle eigenständige Bestandteile generiert. Hier das grundsätzliche Vorgehen mittels Angular-CLI Befehle:

1.  ng new [workspacename]

Optional kann hier die Option: –create-application=false gewählt werden um die Demo-Anwendung nicht initialisieren zu lassen

2. ng generate library [name-1] –prefix=[prefix]

Eine erste Bibliothek, die wir später in unseren Projekten verwenden können. Hier entwickeln wir die gemeinsamen Komponenten und Services.

3. ng build [name-1]

Bibliothek bauen, optional kann hier auch das Flag –watch aktiviert werden um bei Änderungen den Build-Prozess zu triggern

4. ng generate application [name-2]

Eine Anwendung generieren. Hier arbeiten wir wie gewohnt, können aber auf die Services/Komponenten unserer Library zugreifen (nicht vergessen das Utils-Module zu importieren)

5. ng serve [name-2]

Entwicklungs-Server starten für definierte Anwendung…

Sowohl die Bibliotheken, als auch die einzelnen Anwendungen können später ganz autonom verteilt oder deployt werden. Im zweiten Teil werfen wir einen Blick auf die strukturierung mittels NgModule.

Bis dahin:

https://github.com/GEDOPLAN/anuglar-modulesD

Angular, i18n mit ngx-translate

Internationalisierung. Eine typische Aufgaben bei der Implementierung von Web-Anwendungen. Diese Anforderung macht auch vor Angular nicht halt. Hier bieten sich dem Entwickler gleich zwei Möglichkeiten: im ersten Teil haben wir die Möglichkeiten der Core-Bibliothek betrachtet, heute werfen wir einen Blick auf eine zusätzliche Bibliothek: ngx-translate.

i18n-2

@ngx-translate/core kann wie gewohnt per npm-Install im eigenen Projekt integriert werden. Ab hier ist die Verwendung (vielleicht im vergleich zur Core-Variante) relativ gut nach zu vollziehen. Anstatt den Build-Prozess für unterschiedliche Sprachen zu manipulieren werden die Texte hier zur Laufzeit umgewandelt. Damit das funktioniert muss das entsprechende Modul registiert und konfiguirert werden:

import {TranslateModule} from '@ngx-translate/core';


@NgModule({
  imports: [
      TranslateModule.forRoot()
  ],
   ...

Grundsätzlich wäre damit der Service schon einsatzbereit, müsste aber „manuell“ mit Übersetzungen versehen werden. In aller Regel wollen wir hier aber die Übersetzungen in einer separaten Datei vorhalten. Im Fall von ngx-translate geschieht das in einer JSON-Struktur.

{
  TITLE: 'Willkommen',
  HOME: {
    TEXT: 'Hallo Welt',
    FOOTER: 'verwendete Sprache: {{loc}}'
  }

Wie diese zugreifbar gemacht wird, wird über so genannte „TranslateLoader“ entschieden. Dabei handelt es sich um ein simples Interfaces welches entweder selber implementiert werden kann oder man greift z.B. auf den HTTPLoader (@ngx-translate/http-loader) zurück. Als Beispiel einer Implementierung wäre auch eine lokale Variante denkbar:

export class I18nLoader implements TranslateLoader {
  getTranslation(lang: string): Observable {
    if (lang === 'de') {
      return of(de);
    } else {
      return of(en);
    }
  }
}

---- Registrierung ----    
TranslateModule.forRoot({
  loader: {
    provide: TranslateLoader,
    useClass: I18nLoader
  }
})

(nicht für Produktion gedacht, alle Übersetzungen der Anwendungen würden immer zum Browser übertragen werden!)

Damit sind wir schon in der Lage unsere Übersetzungen ein zu setzen. Dies geschieht entweder:

im Template mittels Pipes

{{ 'HOME.TEXT' | translate }}
{{ 'HOME.FOOTER' | translate: { loc: 'de' } }}

oder im Code mittels Service

constructor(private translateService: TranslateService) {
  this.locale = translateService.getBrowserLang();
  translateService.use(this.locale);
  translateService.get('TITLE').subscribe(t => console.log('ngx: ' + t));
}

Das Vorgehen mittels ngx-translate ist sicherlich etwas weniger komplex in der Verwendung und Konfiguration und bietet genug Flexibilität um auch im Projektalltag gut einsetzbar zu sein. Ein Nachteil müssen wir uns allerdings bewusst machen: die Übersetzungen zur Laufzeit durchführen zu lassen kostet (zumindest ein wenig) Zeit, sodass mit der (komplizierteren?) Core-Variante ein leichter Performance-Vorteil vorliegt.

Live! In Farbe! auf github