Betwixt

Miałem ostatnio potrzebę w prosty sposób zapisać i odczytać moje beany do/z pliku XML. Zastanawiając się jak to szybko i przyjemnie zrobić, przypomniałem sobie o czymś takim jak Betwixt ;) .
Betwixt to biblioteka wchodząca w skład Apache Jakarta - Commons i służąca do zapisu/odczytu beanów do/z plików XML. Jest to bardzo elastyczna i przydatna biblioteka, pokażę na przykładzie jak przy jej pomocy możemy szybko przedstawić nasze beany w postaci XML.

Tak oto będą wyglądały nasze beany (będą 2 ponieważ wtedy przykład będzie bardziej interesujący :P ) :

  • Cell.java
package org.holewa.betwixt.beans;

import java.util.ArrayList;
import java.util.List;

/**
 * Betwixt example
 *
 * @author Radoslaw Holewa
 */

public class Cell {
 
  private int id;
  private boolean readOnly;
  private String key;
  private List<String> topCells = new ArrayList<String>();
 
  public boolean isReadOnly() {
    return readOnly;
  }
 
  public void setReadOnly(boolean readOnly) {
    this.readOnly = readOnly;
  }
 
  public List<String> getTopCells() {
    return topCells;
  }
 
  public void setTopCells(List<String> topCells) {
    this.topCells = topCells;
  }
 
  public void addTopCell(String cellName) {
    topCells.add(cellName);
  }

  public String getKey() {
    return key;
  }

  public void setKey(String key) {
    this.key = key;
  }

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }
 
}

  • Model.java
package org.holewa.betwixt.beans;

import java.util.ArrayList;
import java.util.List;

/**
 * Betwixt example
 *
 * @author Radoslaw Holewa
 */

public class Model {
 
  private int id;
  private List<Cell> cells = new ArrayList<Cell>();
 
  public int getId() {
    return id;
  }
 
  public void setId(int id) {
    this.id = id;
  }
 
  public List<Cell> getCells() {
    return cells;
  }
 
  public void setCells(List<Cell> cells) {
    this.cells = cells;
  }
 
  public void addCell(Cell cell) {
    cells.add(cell);
  }
 
}

Do klas tych musimy stworzyć pliki opisujące sposób mapowania pól beana na pola w XML`u, są to pliki z rozszerzeniem betwixt i znajdujące się w tym samym katalogu co klasy im odpowiadające :

  • Cell.betwixt
<?xml version=‘1.0′ encoding=‘UTF-8′ ?>
<info primitiveTypes=‘element’>
    <element name=‘cell’>
        <element name=‘key’ property=‘key’/>
        <element name=‘row’ property=‘id’/>
        <element name=‘readonly’ property=‘readOnly’/>
        <element name=‘topcells’>
            <element name=‘topcell’ property=‘topCells’ updater=‘addTopCell’ class=‘java.lang.String’/>
        </element>
        <addDefaults/>
    </element>
</info>
  • Model.betwixt
<?xml version=‘1.0′ encoding=‘UTF-8′ ?>
<info primitiveTypes=‘element’>
    <element name=‘model’>
        <element name=‘id’ property=‘id’/>
        <element name=‘cells’>
            <element name=‘cell’ property=‘cells’ updater=‘addCell’ class=‘org.holewa.betwixt.beans.Cell’/>
        </element>
        <addDefaults/>
    </element>
</info>

Tak jak napisałem wyżej, pliki te opisują sposób mapowania pól. Atrybut

primitiveTypes=’element’

oznacza że typy podstawowe będą przedstawione w XML`u jako elementy a nie atrybuty tagów, ten fragment :

<element name=‘cells’>
    <element name=‘cell’ property=‘cells’ updater=‘addCell’ class=‘org.holewa.betwixt.beans.Cell’/>
</element>

Oznacza że kolekcja obiektów będących instancją klasy

org.holewa.betwixt.beans.Cell

będzie zapisana w XML`u między tagami

<cells></cells>

oraz jeden element tej kolekcji będzie zapisany między tagami

<cell></cell>

.
Dodatkowo mamy atrybut

updater=’addCell’

który zawiera nazwę metody (

addCell(Cell cell)

) odpowiedzialnej za dodanie elementu do kolekcji (jest to potrzebne do prawidłowego wczytania XML`a zawierającego kolekcję). Ostatnią rzeczą którą warto wymienić jest tag

<addDefaults/>

który sprawi, że w naszym XML`u pojawią się wszystkie pola nie wymienione w pliku opisującym mapowanie obiektu na pola w XML`u (jeśli go pominiemy to pola te nie będą mapowane przy odczycie z/zapisie do pliku XML).

Teraz czas na aplikacje która przekształci nasze beany do postaci XML :

  • Main.java
package org.holewa.betwixt;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.betwixt.io.BeanWriter;
import org.holewa.betwixt.beans.Cell;
import org.holewa.betwixt.beans.Model;

/**
 * Betwixt example
 *
 * @author Radoslaw Holewa
 */

public class Main {
 
  public static void main(String[] args) {
    StringWriter outputWriter = new StringWriter();
    outputWriter.write(“<?xml version=’1.0′ ?>\n);
    BeanWriter beanWriter = new BeanWriter(outputWriter);
    beanWriter.getXMLIntrospector().getConfiguration().setAttributesForPrimitives(false);
    beanWriter.getBindingConfiguration().setMapIDs(false);
    beanWriter.enablePrettyPrint();
    beanWriter.setInitialIndentLevel(0);
    try {
      beanWriter.write(prepare());
      System.out.println(outputWriter.toString());
    } catch (Exception e) {
      System.out.println(“Could not write.”);
    }
  }
 
  private static Model prepare() {
    Model model = new Model();        //Model zawiera swoje pola plus 2 beany 
    model.setId(1);
    Cell cell = new Cell();           //Pierwszy bean
    cell.setId(1);
    cell.setReadOnly(true);
    cell.setKey(“KEY_1″);
    List<String> topCells = new ArrayList<String>();
    topCells.add(“CELL_1″);
    topCells.add(“CELL_2″);
    cell.setTopCells(topCells);       //Do pierwszego beana dodajemy kolekcje
    model.addCell(cell);
    cell = new Cell();                //Drugi bean
    cell.setId(1);
    cell.setReadOnly(true);
    cell.setKey(“KEY_2″);
    model.addCell(cell);
    return  model;
  }
 
}

Wynik wykonania tego programu powinien być następujący :

<?xml version=‘1.0′ ?>
<model>
  <cells>
    <cell>
      <id>1</id>
      <key>KEY_1</key>
      <readonly>true</readonly>
      <topcells>
        <topcell>CELL_1</topcell>
        <topcell>CELL_2</topcell>
      </topcells>
    </cell>
    <cell>
      <id>1</id>
      <key>KEY_2</key>
      <readonly>true</readonly>
      <topcells/>
    </cell>
  </cells>
  <id>1</id>
</model>

No dobra, pewnie teraz pojawi się pytanie jak odczytać naszego beana z pliku ?
Jest to bardzo proste ale żeby nie iść tak całkiem na łatwiznę i zachęcić do głębszego poznania Betwixt odsyłam do tego fragmentu dokumentacji :P .

  • Digg
  • del.icio.us
  • Google
  • description
  • Technorati
  • Wykop
May 1, 2007 | |

COMMENTS

 

Trackback URI | Comments RSS

6 Responses to “Betwixt”

  1. Piotr Maj on May 21st, 2007 8:02 am

    hej, nie wgryzałem się dokładnie w tą bibliotekę, ale wydaje mi się, że zapis i odczyt bean HTML łatwiej zrobić np. klasami XMLDecoder oraz XMLEncoder, albo XStreamem. Betwixt wygląda na ich tle dość skomplikowanie,ale może ma jakieś ukryte właściwości?

  2. Bartosz Leper on June 14th, 2007 1:42 pm

    Wydaje mi się, że użycie Castora jest znacznie łatwiejsze. Ciekawe, jak wyglądałoby porównanie tych dwóch bibliotek pod kątem elastyczności.

  3. radoslaw.holewa on June 16th, 2007 1:43 am

    Dzięki za posty - zrobię zestawienie/porównanie zalecanych przez Was rozwiązań.

    Pozdrawiam,
    Radek

  4. Wooki on December 7th, 2009 10:53 pm

    Chyba zepsuła Ci się metoda konwertująca itp. na encje w każdym razie połowa kodu jest przez to całkowicie nieosiągalna z poziomu strony.

  5. Wooki on December 7th, 2009 10:54 pm

    mhm właśnie o tym mówię: “kownertującą < , >”

  6. radoslaw.holewa on December 8th, 2009 9:58 am

    @Wooki: Poprawione! Dzięki!

Leave a Reply