Introduction aux Smooks

Introduction aux Smooks

1. Vue d'ensemble

Dans ce didacticiel, nous présenterons lesSmooks framework.

Nous allons décrire de quoi il s'agit, énumérer ses principales fonctionnalités et finalement apprendre à utiliser certaines de ses fonctionnalités les plus avancées.

Tout d’abord, expliquons brièvement ce que le cadre est censé atteindre.

2. Smooks

Smooks est un cadre pour les applications de traitement de données - traitant des données structurées telles que XML ou CSV.

Il fournit à la fois des API et un modèle de configuration nous permettant de définir des transformations entre des formats prédéfinis (par exemple, XML vers CSV, XML vers JSON, etc.).

Nous pouvons également utiliser plusieurs outils pour configurer notre mappage, notamment les scripts FreeMarker ou Groovy.

Outre les transformations, Smooks offre également d'autres fonctionnalités telles que la validation de messages ou le fractionnement de données.

2.1. Principales caractéristiques

Jetons un coup d'œil aux principaux cas d'utilisation de Smooks:

  • Conversion de message - transformation de données de divers formats source en divers formats de sortie

  • Enrichissement du message - Remplir le message avec des données supplémentaires provenant d'une source de données externe telle qu'une base de données.

  • Fractionnement des données - traitement de gros fichiers (GB) et division en petits fichiers

  • Liaison Java - construction et remplissage d'objets Java à partir de messages

  • Validation du message - effectuer des validations telles que regex, ou même créer vos propres règles de validation

3. Configuration initiale

Commençons par la dépendance Maven que nous devons ajouter à nospom.xml:


    org.milyn
    milyn-smooks-all
    1.7.0

La dernière version peut être trouvée surMaven Central.

4. Liaison Java

Commençons maintenant par nous concentrer sur la liaison des messages aux classes Java. Nous allons passer par une simple conversion XML vers Java ici.

4.1. Concepts de base

Nous allons commencer par un exemple simple. Considérez le XML suivant:


    771
    IN_PROGRESS

Pour accomplir cette tâche avec Smooks, nous devons faire deux choses: préparer la configuration des POJO et des Smooks.

Voyons à quoi ressemble notre modèle:

public class Order {

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

Passons maintenant aux mappages Smooks.

Fondamentalement, les mappages sont un fichier XML contenant une logique de transformation. Dans cet article, nous utiliserons trois types de règles différents:

  • bean – définit le mappage d'une section structurée concrète à la classe Java

  • value - définit le mappage pour la propriété particulière du bean. Peut contenir une logique plus avancée comme les décodeurs, qui sont utilisés pour mapper des valeurs sur certains types de données (comme le format de date ou décimal)

  • wiring – nous permet de câbler un haricot à d'autres haricots (par exemple, le haricotSupplier sera câblé au haricotOrder)

Jetons un coup d'œil aux mappages que nous utiliserons dans notre cas ici:




    
        
        
        
            yyyy-MM-dd
        
    

Maintenant, avec la configuration prête, essayons de tester si notre POJO est construit correctement.

Premièrement, nous devons construire un objet Smooks et passer le XML d’entrée sous forme de flux:

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();
    }
}

Et enfin, affirmer si la configuration est faite correctement:

@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. Liaison avancée - Référencement d'autres beans et listes

Étendons notre exemple précédent avec les balisessupplier etorder-items:


    771
    IN_PROGRESS
    
        Company X
        1234567
    
    
        
            1
            PX1234
            9.99
        
        
            1
            RX990
            120.32
        
    

Et maintenant, mettons à jour notre modèle:

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;
    // ...
}

Nous devons également étendre le mappage de configuration avec les définitions de beansupplier etitem.

Notez que nous avons également défini le beanitems séparé, qui contiendra tous les élémentsitem dansArrayList.

Enfin, nous utiliserons l'attribut Smookswiring, pour le regrouper.

Jetez un coup d'œil à l'apparence des mappages dans ce cas:




    
        
        
        
            yyyy-MM-dd
        
        
        
    

    
        
        
    

    
        
    
    
        
        
        
    

Enfin, nous ajouterons quelques affirmations à notre test précédent:

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. Validation des messages

Smooks est livré avec un mécanisme de validation basé sur des règles. Voyons comment ils sont utilisés.

La définition des règles est stockée dans le fichier de configuration, imbriqué dans la baliseruleBases, qui peut contenir de nombreux élémentsruleBase.

Chaque élémentruleBase doit avoir les propriétés suivantes:

  • Nom unique dename –, utilisé juste pour référence

  • Cheminsrc – vers le fichier source de la règle

  • provider - nom de classe complet, qui implémente l'interfaceRuleProvider

Smooks est livré avec deux fournisseurs prêts à l'emploi:RegexProvider etMVELProvider.

Le premier est utilisé pour valider des champs individuels dans un style de type regex.

La seconde est utilisée pour effectuer une validation plus complexe dans la portée globale du document. Voyons-les en action.

5.1. RegexProvider

UtilisonsRegexProvider pour valider deux choses: le format du nom du client et le numéro de téléphone. RegexProvider en tant que source nécessite un fichier de propriétés Java, quishould contain regex validation in key-value fashion.

Afin de répondre à nos exigences, nous utiliserons la configuration suivante:

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

5.2. MVELProvider

Nous utiliseronsMVELProvider pour valider si le prix total de chaqueorder-item est inférieur à 200. En tant que source, nous préparerons un fichier CSV avec deux colonnes: le nom de la règle et l'expression MVEL.

Afin de vérifier si le prix est correct, nous avons besoin de l'entrée suivante:

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

5.3. Configuration de la validation

Une fois que nous aurons préparé les fichiers source pourruleBases, nous passerons à la mise en œuvre de validations concrètes.

Une validation est une autre balise dans la configuration de Smooks, qui contient les attributs suivants:

  • executeOn - chemin vers l'élément validé

  • name - référence auxruleBase

  • onFail - spécifie quelle action sera entreprise lorsque la validation échoue

Appliquons les règles de validation à notre fichier de configuration Smooks et vérifions à quoi il ressemble (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):




    

    
        
        
    

    
    
    

Maintenant que la configuration est prête, essayons de tester si la validation échouera sur le numéro de téléphone du fournisseur.

Encore une fois, nous devons construire l'objetSmooks et passer le XML d'entrée en tant que flux:

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();
    }
}

Et enfin affirmer, si une erreur de validation survient:

@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. Conversion de message

Nous souhaitons ensuite convertir le message d’un format à un autre.

In Smooks, this technique is also called templating et il prend en charge:

  • FreeMarker (option préférée)

  • XSL

  • ModèleString

Dans notre exemple, nous allons utiliser le moteur FreeMarker pour convertir un message XML en quelque chose de très similaire à EDIFACT, et même préparer un modèle pour l'e-mail basé sur l'ordre XML.

Voyons comment préparer un modèle pour EDIFACT:

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

Et pour le message électronique:

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:
<#list items as item>
${item.quantity} X ${item.code} (total price ${item.price * item.quantity})

La configuration de Smooks est très basique cette fois (n'oubliez pas d'importer la configuration précédente pour importer les paramètres de liaison Java):




    

    
        /path/to/template.ftl
    

Cette fois, nous devons simplement passer unStringResult au moteur Smooks:

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

Et nous pouvons bien sûr le tester:

@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. Conclusion

Dans ce tutoriel, nous nous sommes concentrés sur la conversion de messages en différents formats, ou leur transformation en objets Java à l'aide de Smooks. Nous avons également vu comment effectuer des validations basées sur des règles de regex ou de logique métier.

Comme toujours, tout le code utilisé ici peut être trouvéover on GitHub.