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
) :
- Cell.java
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
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
<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
<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
oznacza że typy podstawowe będą przedstawione w XML`u jako elementy a nie atrybuty tagów, ten fragment :
<element name=‘cell’ property=‘cells’ updater=‘addCell’ class=‘org.holewa.betwixt.beans.Cell’/>
</element>
Oznacza że kolekcja obiektów będących instancją klasy
będzie zapisana w XML`u między tagami
oraz jeden element tej kolekcji będzie zapisany między tagami
.
Dodatkowo mamy atrybut
który zawiera nazwę metody (
) 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
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
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 :
<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
.











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?
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.
Dzięki za posty - zrobię zestawienie/porównanie zalecanych przez Was rozwiązań.
Pozdrawiam,
Radek
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.
mhm właśnie o tym mówię: “kownertującą < , >”
@Wooki: Poprawione! Dzięki!