Pengantar Smooks

1. Ikhtisar

Dalam tutorial ini, kami akan memperkenalkan kerangka kerja Smooks.

Kami akan menjelaskan apa itu, membuat daftar fitur utamanya, dan akhirnya mempelajari cara menggunakan beberapa fungsionalitas yang lebih canggih.

Pertama-tama, mari kita jelaskan secara singkat apa yang ingin dicapai kerangka kerja.

2. Asap

Smooks adalah kerangka kerja untuk aplikasi pemrosesan data - menangani data terstruktur seperti XML atau CSV.

Ini menyediakan API dan model konfigurasi yang memungkinkan kita untuk menentukan transformasi antara format yang telah ditentukan (misalnya XML ke CSV, XML ke JSON, dan lainnya).

Kami juga dapat menggunakan sejumlah alat untuk menyiapkan pemetaan kami - termasuk skrip FreeMarker atau Groovy.

Selain transformasi, Smooks juga memberikan fitur lain seperti validasi pesan atau pemisahan data.

2.1. Fitur Utama

Mari kita lihat kasus penggunaan utama Smooks:

  • Konversi pesan - transformasi data dari berbagai format sumber ke berbagai format keluaran
  • Pengayaan pesan - mengisi pesan dengan data tambahan, yang berasal dari sumber data eksternal seperti database
  • Pemisahan data - memproses file besar (GB) dan membaginya menjadi yang lebih kecil
  • Pengikatan Java - membuat dan mengisi objek Java dari pesan
  • Validasi pesan - melakukan validasi seperti regex, atau bahkan membuat aturan validasi Anda sendiri

3. Konfigurasi Awal

Mari kita mulai dengan ketergantungan Maven yang perlu kita tambahkan ke pom.xml kita :

 org.milyn milyn-smooks-all 1.7.0 

Versi terbaru dapat ditemukan di Maven Central.

4. Java Binding

Sekarang mari kita mulai dengan berfokus pada mengikat pesan ke kelas Java. Kami akan melalui konversi XML ke Java sederhana di sini.

4.1. Konsep dasar

Kami akan mulai dengan contoh sederhana. Perhatikan XML berikut ini:

 771 IN_PROGRESS 

Untuk menyelesaikan tugas ini dengan Smooks, kita harus melakukan dua hal: menyiapkan POJO dan konfigurasi Smooks.

Mari kita lihat seperti apa model kita:

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

Sekarang, mari beralih ke pemetaan Smooks.

Pada dasarnya, pemetaan adalah file XML yang berisi logika transformasi. Di artikel ini, kami akan menggunakan tiga jenis aturan yang berbeda:

  • bean - mendefinisikan pemetaan bagian terstruktur beton ke kelas Java
  • nilai - mendefinisikan pemetaan untuk properti tertentu dari kacang. Dapat berisi logika yang lebih canggih seperti decoder, yang digunakan untuk memetakan nilai ke beberapa tipe data (seperti format tanggal atau desimal)
  • w iring - memungkinkan kita untuk menyambungkan kacang ke kacang lain (misalnya kacang pemasok akan ditransfer ke kacang pesanan )

Mari kita lihat pemetaan yang akan kita gunakan dalam kasus kita di sini:

      yyyy-MM-dd   

Sekarang, dengan konfigurasi siap, mari kita coba untuk menguji apakah POJO kita dibuat dengan benar.

Pertama, kita perlu membuat objek Smooks dan meneruskan input XML sebagai aliran:

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

Dan terakhir, tegaskan jika konfigurasi dilakukan dengan benar:

@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. Pengikatan Lanjutan - Mengacu pada Kacang dan Daftar Lain

Mari kita memperluas contoh kita sebelumnya dengan tag pemasok dan item pesanan :

 771 IN_PROGRESS  Company X 1234567    1 PX1234 9.99   1 RX990 120.32   

Dan sekarang mari perbarui model kita:

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

Kita juga harus memperluas pemetaan konfigurasi dengan definisi pemasok dan kacang item .

Perhatikan bahwa kita juga telah mendefinisikan kacang item yang terpisah , yang akan menampung semua elemen item di ArrayList .

Terakhir, kami akan menggunakan atribut wiring Smooks , untuk menggabungkan semuanya.

Lihat bagaimana pemetaan akan terlihat dalam kasus ini:

      yyyy-MM-dd                 

Akhirnya, kami akan menambahkan beberapa pernyataan ke pengujian kami sebelumnya:

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. Validasi Pesan

Smooks hadir dengan mekanisme validasi berdasarkan aturan. Mari kita lihat bagaimana mereka digunakan.

Definisi aturan disimpan dalam file konfigurasi, bertumpuk di tag ruleBase , yang dapat berisi banyak elemen ruleBase .

Setiap elemen ruleBase harus memiliki properti berikut:

  • 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  

Kali ini kita hanya perlu meneruskan mesin StringResult ke Smooks:

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

Dan kami tentu saja dapat mengujinya:

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

Dalam tutorial ini, kami berfokus pada cara mengonversi pesan ke format berbeda, atau mengubahnya menjadi objek Java menggunakan Smooks. Kami juga melihat bagaimana melakukan validasi berdasarkan regex atau aturan logika bisnis.

Seperti biasa, semua kode yang digunakan di sini dapat ditemukan di GitHub.