Einführung in Smooks

1. Übersicht

In diesem Tutorial stellen wir das Smooks-Framework vor.

Wir werden beschreiben, was es ist, die wichtigsten Funktionen auflisten und schließlich lernen, wie einige der erweiterten Funktionen verwendet werden.

Lassen Sie uns zunächst kurz erklären, was mit dem Framework erreicht werden soll.

2. Smooks

Smooks ist ein Framework für Datenverarbeitungsanwendungen, das sich mit strukturierten Daten wie XML oder CSV befasst.

Es bietet sowohl APIs als auch ein Konfigurationsmodell, mit dem wir Transformationen zwischen vordefinierten Formaten definieren können (z. B. XML zu CSV, XML zu JSON und mehr).

Wir können auch eine Reihe von Tools verwenden, um unser Mapping einzurichten - einschließlich FreeMarker- oder Groovy-Skripten.

Neben Transformationen bietet Smooks auch andere Funktionen wie Nachrichtenüberprüfungen oder Datenaufteilung.

2.1. Hauptmerkmale

Werfen wir einen Blick auf die Hauptanwendungsfälle von Smooks:

  • Nachrichtenkonvertierung - Umwandlung von Daten aus verschiedenen Quellformaten in verschiedene Ausgabeformate
  • Nachrichtenanreicherung - Füllen Sie die Nachricht mit zusätzlichen Daten aus, die aus einer externen Datenquelle wie einer Datenbank stammen
  • Datenaufteilung - Verarbeitung großer Dateien (GBs) und Aufteilung in kleinere Dateien
  • Java-Bindung - Erstellen und Auffüllen von Java-Objekten aus Nachrichten
  • Nachrichtenvalidierung - Durchführen von Validierungen wie Regex oder Erstellen eigener Validierungsregeln

3. Erstkonfiguration

Beginnen wir mit der Maven-Abhängigkeit, die wir unserer pom.xml hinzufügen müssen :

 org.milyn milyn-smooks-all 1.7.0 

Die neueste Version finden Sie auf Maven Central.

4. Java-Bindung

Beginnen wir nun damit, Nachrichten an Java-Klassen zu binden. Wir werden hier eine einfache XML-zu-Java-Konvertierung durchführen.

4.1. Grundlegendes Konzept

Wir beginnen mit einem einfachen Beispiel. Betrachten Sie das folgende XML:

 771 IN_PROGRESS 

Um diese Aufgabe mit Smooks zu erfüllen, müssen wir zwei Dinge tun: die POJOs und die Smooks-Konfiguration vorbereiten.

Mal sehen, wie unser Modell aussieht:

public class Order { private Date creationDate; private Long number; private Status status; // ... } 
public enum Status { NEW, IN_PROGRESS, FINISHED }

Fahren wir nun mit den Smooks-Zuordnungen fort.

Grundsätzlich handelt es sich bei den Zuordnungen um eine XML-Datei, die Transformationslogik enthält. In diesem Artikel werden drei verschiedene Arten von Regeln verwendet:

  • bean - definiert die Zuordnung eines konkreten strukturierten Abschnitts zur Java-Klasse
  • value - Definiert die Zuordnung für die bestimmte Eigenschaft der Bean. Kann erweiterte Logik wie Decoder enthalten, mit denen Werte bestimmten Datentypen zugeordnet werden (z. B. Datums- oder Dezimalformat).
  • w iring - ermöglicht es uns , eine Bohne zu anderen Bohnen zu verdrahten (zB Lieferant Bean wird verdrahtet werden bestellen Bohne)

Werfen wir einen Blick auf die Zuordnungen, die wir in unserem Fall hier verwenden:

      yyyy-MM-dd   

Versuchen wir nun mit der Konfiguration zu testen, ob unser POJO korrekt aufgebaut ist.

Zuerst müssen wir ein Smooks-Objekt erstellen und Eingabe-XML als Stream übergeben:

public Order converOrderXMLToOrderObject(String path) throws IOException, SAXException { Smooks smooks = new Smooks( this.class.getResourceAsStream("/smooks-mapping.xml")); try { JavaResult javaResult = new JavaResult(); smooks.filterSource(new StreamSource(this.class .getResourceAsStream(path)), javaResult); return (Order) javaResult.getBean("order"); } finally { smooks.close(); } }

Stellen Sie schließlich fest, ob die Konfiguration ordnungsgemäß durchgeführt wurde:

@Test public void givenOrderXML_whenConvert_thenPOJOsConstructedCorrectly() throws Exception { XMLToJavaConverter xmlToJavaOrderConverter = new XMLToJavaConverter(); Order order = xmlToJavaOrderConverter .converOrderXMLToOrderObject("/order.xml"); assertThat(order.getNumber(), is(771L)); assertThat(order.getStatus(), is(Status.IN_PROGRESS)); assertThat( order.getCreationDate(), is(new SimpleDateFormat("yyyy-MM-dd").parse("2018-01-14")); }

4.2. Erweiterte Bindung - Referenzieren anderer Bohnen und Listen

Erweitern wir unser vorheriges Beispiel um Lieferanten- und Bestellartikel- Tags:

 771 IN_PROGRESS  Company X 1234567    1 PX1234 9.99   1 RX990 120.32   

Und jetzt aktualisieren wir unser Modell:

public class Order { // .. private Supplier supplier; private List items; // ... }
public class Item { private String code; private Double price; private Integer quantity; // ... } 
public class Supplier { private String name; private String phoneNumber; // ... }

Wir müssen auch die Konfigurationszuordnung um die Lieferanten- und Artikel- Bean-Definitionen erweitern.

Beachten Sie, dass wir haben auch getrennt definiert Artikel Bohne, die alle halten Artikel Elemente in Arraylist .

Schließlich werden wir das Smooks- Verkabelungsattribut verwenden , um alles zusammen zu bündeln.

Sehen Sie sich an, wie Zuordnungen in diesem Fall aussehen:

      yyyy-MM-dd                 

Abschließend fügen wir unserem vorherigen Test einige Aussagen hinzu:

assertThat( order.getSupplier(), is(new Supplier("Company X", "1234567"))); assertThat(order.getItems(), containsInAnyOrder( new Item("PX1234", 9.99,1), new Item("RX990", 120.32,1)));

5. Nachrichtenüberprüfung

Smooks verfügt über einen Validierungsmechanismus, der auf Regeln basiert. Werfen wir einen Blick darauf, wie sie verwendet werden.

Die Definition der Regeln wird in der Konfigurationsdatei gespeichert, die im Tag ruleBases verschachtelt ist und viele ruleBase- Elemente enthalten kann .

Jedes ruleBase- Element muss die folgenden Eigenschaften haben:

  • name – unique name, used just for reference
  • src – path to the rule source file
  • provider – fully qualified class name, which implements RuleProvider interface

Smooks comes with two providers out of the box: RegexProvider and MVELProvider.

The first one is used to validate individual fields in regex-like style.

The second one is used to perform more complicated validation in the global scope of the document. Let's see them in action.

5.1. RegexProvider

Let's use RegexProvider to validate two things: the format of the customer name, and phone number. RegexProvider as a source requires a Java properties file, which should contain regex validation in key-value fashion.

In order to meet our requirements, we'll use the following setup:

supplierName=[A-Za-z0-9]* supplierPhone=^[0-9\\-\\+]{9,15}$

5.2. MVELProvider

We'll use MVELProvider to validate if the total price for each order-item is less then 200. As a source, we'll prepare a CSV file with two columns: rule name and MVEL expression.

In order to check if the price is correct, we need the following entry:

"max_total","orderItem.quantity * orderItem.price < 200.00"

5.3. Validation Configuration

Once we've prepared the source files for ruleBases, we'll move on to implementing concrete validations.

A validation is another tag in Smooks configuration, which contains the following attributes:

  • executeOn – path to the validated element
  • name – reference to the ruleBase
  • onFail – specifies what action will be taken when validation fails

Let's apply validation rules to our Smooks configuration file and check how it looks like (note that if we want to use the MVELProvider, we're forced to use Java binding, so that's why we've imported previous Smooks configuration):

Now, with the configuration ready, let's try to test if validation will fail on supplier's phone number.

Again, we have to construct Smooks object and pass input XML as a stream:

public ValidationResult validate(String path) throws IOException, SAXException { Smooks smooks = new Smooks(OrderValidator.class .getResourceAsStream("/smooks/smooks-validation.xml")); try { StringResult xmlResult = new StringResult(); JavaResult javaResult = new JavaResult(); ValidationResult validationResult = new ValidationResult(); smooks.filterSource(new StreamSource(OrderValidator.class .getResourceAsStream(path)), xmlResult, javaResult, validationResult); return validationResult; } finally { smooks.close(); } } 

And finally assert, if validation error occurred:

@Test public void givenIncorrectOrderXML_whenValidate_thenExpectValidationErrors() throws Exception { OrderValidator orderValidator = new OrderValidator(); ValidationResult validationResult = orderValidator .validate("/smooks/order.xml"); assertThat(validationResult.getErrors(), hasSize(1)); assertThat( validationResult.getErrors().get(0).getFailRuleResult().getRuleName(), is("supplierPhone")); }

6. Message Conversion

The next thing we want to do is convert the message from one format to another.

In Smooks, this technique is also called templating and it supports:

  • FreeMarker (preferred option)
  • XSL
  • String template

In our example, we'll use the FreeMarker engine to convert XML message to something very similar to EDIFACT, and even prepare a template for the email message based on XML order.

Let's see how to prepare a template for EDIFACT:

UNA:+.? ' UNH+${order.number}+${order.status}+${order.creationDate?date}' CTA+${supplier.name}+${supplier.phoneNumber}'  LIN+${item.quantity}+${item.code}+${item.price}' 

And for the email message:

Hi, Order number #${order.number} created on ${order.creationDate?date} is currently in ${order.status} status. Consider contacting the supplier "${supplier.name}" with phone number: "${supplier.phoneNumber}". Order items:  ${item.quantity} X ${item.code} (total price ${item.price * item.quantity}) 

The Smooks configuration is very basic this time (just remember to import the previous configuration in order to import Java binding settings):

    /path/to/template.ftl  

Dieses Mal müssen wir nur ein StringResult an die Smooks-Engine übergeben:

Smooks smooks = new Smooks(config); StringResult stringResult = new StringResult(); smooks.filterSource(new StreamSource(OrderConverter.class .getResourceAsStream(path)), stringResult); return stringResult.toString();

Und wir können es natürlich testen:

@Test public void givenOrderXML_whenApplyEDITemplate_thenConvertedToEDIFACT() throws Exception { OrderConverter orderConverter = new OrderConverter(); String edifact = orderConverter.convertOrderXMLtoEDIFACT( "/smooks/order.xml"); assertThat(edifact,is(EDIFACT_MESSAGE)); }

7. Fazit

In diesem Tutorial haben wir uns darauf konzentriert, wie Nachrichten in verschiedene Formate konvertiert oder mithilfe von Smooks in Java-Objekte umgewandelt werden. Wir haben auch gesehen, wie Validierungen basierend auf Regex- oder Geschäftslogikregeln durchgeführt werden.

Wie immer ist der gesamte hier verwendete Code auf GitHub zu finden.