Smooksの紹介

Smooksの概要

1. 概要

このチュートリアルでは、Smooks frameworkを紹介します。

それが何であるかを説明し、その主要な機能をリストし、最終的にはそのより高度な機能のいくつかを使用する方法を学びます。

まず、フレームワークが何を達成することを意味するのかを簡単に説明しましょう。

2. スムークス

Smooksは、XMLやCSVなどの構造化データを処理するデータ処理アプリケーションのフレームワークです。

APIと構成モデルの両方を提供し、定義済みの形式(XMLからCSV、XMLからJSONなど)間の変換を定義できます。

FreeMarkerやGroovyスクリプトなど、マッピングをセットアップするための多くのツールを使用することもできます。

変換に加えて、Smooksはメッセージ検証やデータ分割などの他の機能も提供します。

2.1. 主な機能

Smooksの主なユースケースを見てみましょう。

  • メッセージ変換–さまざまなソース形式からさまざまな出力形式へのデータの変換

  • メッセージの強化-データベースなどの外部データソースから取得した追加データでメッセージを埋めます

  • データの分割-大きなファイル(GB)を処理し、それらを小さなファイルに分割します

  • Javaバインディング–メッセージからJavaオブジェクトを構築および入力する

  • メッセージの検証-正規表現のような検証を実行するか、独自の検証ルールを作成する

3. 初期設定

pom.xmlに追加する必要のあるMaven依存関係から始めましょう。


    org.milyn
    milyn-smooks-all
    1.7.0

最新バージョンはMaven Centralにあります。

4. Javaバインディング

それでは、メッセージをJavaクラスにバインドすることに焦点を当てることから始めましょう。 ここでは、単純なXMLからJavaへの変換について説明します。

4.1. 基本概念

簡単な例から始めましょう。 次のXMLを検討してください。


    771
    IN_PROGRESS

Smooksでこのタスクを実行するには、2つのことを行う必要があります。POJOの準備とSmooks構成です。

モデルがどのように見えるか見てみましょう。

public class Order {

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

それでは、Smooksマッピングに移りましょう。

基本的に、マッピングは変換ロジックを含むXMLファイルです。 この記事では、次の3種類のルールを使用します。

  • bean –は、具体的な構造化セクションのJavaクラスへのマッピングを定義します。

  • value –Beanの特定のプロパティのマッピングを定義します。 値を特定のデータ型(日付や10進数形式など)にマップするために使用されるデコーダーなどのより高度なロジックを含めることができます

  • wiring –を使用すると、Beanを他のBeanにワイヤリングできます(たとえば、Supplier BeanはOrder Beanにワイヤリングされます)

ここでこのケースで使用するマッピングを見てみましょう。




    
        
        
        
            yyyy-MM-dd
        
    

構成の準備ができたら、POJOが正しく構築されているかどうかをテストしてみましょう。

まず、Smooksオブジェクトを構築し、入力XMLをストリームとして渡す必要があります。

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

最後に、構成が適切に行われたかどうかを確認します。

@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. 高度なバインディング–他のBeanとリストの参照

前の例をsupplierタグとorder-itemsタグで拡張してみましょう。


    771
    IN_PROGRESS
    
        Company X
        1234567
    
    
        
            1
            PX1234
            9.99
        
        
            1
            RX990
            120.32
        
    

それでは、モデルを更新しましょう。

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

また、supplierおよびitemBean定義を使用して構成マッピングを拡張する必要があります。

分離されたitems Beanも定義していることに注意してください。これは、ArrayList内のすべてのitem要素を保持します。

最後に、Smookswiring属性を使用して、すべてをバンドルします。

この場合のマッピングの様子を見てください。




    
        
        
        
            yyyy-MM-dd
        
        
        
    

    
        
        
    

    
        
    
    
        
        
        
    

最後に、前のテストにいくつかのアサーションを追加します。

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. メッセージの検証

Smooksには、ルールに基づいた検証メカニズムが付属しています。 それらがどのように使用されるかを見てみましょう。

ルールの定義は構成ファイルに保存され、ruleBasesタグにネストされます。このタグには、多くのruleBase要素を含めることができます。

ruleBase要素には、次のプロパティが必要です。

  • name –の一意の名前。参照用にのみ使用されます

  • ルールソースファイルへのsrc –パス

  • providerRuleProviderインターフェースを実装する完全修飾クラス名

Smooksには、すぐに使用できる2つのプロバイダー(RegexProviderMVELProvider)が付属しています。

最初のものは、正規表現のようなスタイルで個々のフィールドを検証するために使用されます。

2つ目は、ドキュメントのグローバルスコープでより複雑な検証を実行するために使用されます。 それらの動作を見てみましょう。

5.1. RegexProvider

RegexProviderを使用して、顧客名の形式と電話番号の2つを検証してみましょう。 ソースとしてのRegexProviderには、should contain regex validation in key-value fashionであるJavaプロパティファイルが必要です。

要件を満たすために、次の設定を使用します。

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

5.2. MVELProvider

MVELProviderを使用して、各order-itemの合計価格が200未満であるかどうかを検証します。 ソースとして、ルール名とMVEL式の2つの列を持つCSVファイルを準備します。

価格が正しいかどうかを確認するには、次のエントリが必要です。

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

5.3. 検証構成

ruleBasesのソースファイルを準備したら、具体的な検証の実装に進みます。

検証はSmooks構成の別のタグであり、次の属性が含まれています。

  • executeOn –検証された要素へのパス

  • nameruleBaseへの参照

  • onFail –検証が失敗したときに実行されるアクションを指定します

Smooks構成ファイルに検証ルールを適用して、それがどのように見えるかを確認しましょう(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):




    

    
        
        
    

    
    
    

構成の準備ができたら、サプライヤの電話番号で検証が失敗するかどうかをテストしてみましょう。

ここでも、Smooksオブジェクトを作成し、入力XMLをストリームとして渡す必要があります。

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

そして最後に、検証エラーが発生した場合にアサートします。

@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. メッセージ変換

次に行うことは、メッセージをある形式から別の形式に変換することです。

In Smooks, this technique is also called templatingおよびそれは以下をサポートします:

  • FreeMarker(推奨オプション)

  • XSL

  • Stringテンプレート

この例では、FreeMarkerエンジンを使用して、XMLメッセージをEDIFACTに非常によく似たものに変換し、XMLの順序に基づいて電子メールメッセージのテンプレートを準備します。

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}'

また、電子メールメッセージの場合:

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

今回のSmooksの構成は非常に基本的なものです(Javaバインディング設定をインポートするには、以前の構成をインポートすることを忘れないでください)。




    

    
        /path/to/template.ftl
    

今回は、StringResultをSmooksエンジンに渡す必要があります。

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

もちろん、テストすることもできます。

@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. 結論

このチュートリアルでは、Smooksを使用してメッセージをさまざまな形式に変換する方法、またはJavaオブジェクトに変換する方法に焦点を当てました。 また、正規表現またはビジネスロジックルールに基づいて検証を実行する方法も確認しました。

いつものように、ここで使用されるすべてのコードはover on GitHubで見つけることができます。