niedziela, 13 kwietnia 2008

Serializacja XML - zapis java.util.Date oraz wartości enumeracji

Niniejszy artykuł jest kontynuacją wątku z artykułu TestNG - dane testowe z plików XML o wykorzystaniu standardowej (J2SE) schemy serializacji XML objektów do preparowania danych testowych. Ten artykuł będzie traktował o zapisie danych typu java.util.Date oraz typu wyliczeniowego - enumeracji.
Gwoli przypomnienia w tym przypadku nie chodzi o serializację obiektów z poziomu javy, tylko o ręczne preparowania plików XML zawierających zserializowane obiekty, które zostaną zdeserializowane z użyciem standardowego mechanizmu - java.beans.XMLDecoder, a następnie zostaną użyte jako dane wejściowe dla testów jednostkowych.

Niemniej przy serializacji obiektu z poziomy javy, który ma jedno pole o typie java.util.Date a drugie o typie wyliczeniowym, uzyskamy efekt dalece niezadowalający, którego na pewno nie będziemy chcieli naśladować.
Pole o typie wyliczeniowym w ogóle nie zostanie zapisane. Z kolei pole z datom zostanie zapisane, ale w formie liczby milisekund od 1 stycznia 1970r. Na pewno nie jest to wygodna postać dla człowieka, anie do odczytu, a tym bardziej do zapisu. W każdym razie java.beans.XMLEncoder zserializuje java.util.Date w następujący sposób:
<void property="birthDate"> 
 <object class="java.util.Date"> 
  <long>439254000000</long> 
 </object> 
</void>
Not tak... to przecież całkiem logiczne, bo jest to jedyny nie "potępiony" sposób ustawiania daty jaki oferuje interfejs java.util.Date.
Normalnie (w javie) jakbym miał uzyskać datę ze stringa, to bym skorzystał z java.text.SimpleDateFormat. No ale jak go użyć w tym XML'u... już podaję:
<void id="sdf" class="java.text.SimpleDateFormat">
 <string>yyyy-MM-dd</string>
 <void id="date0" method="parse">
  <string>1983-12-03</string>
 </void>
</void>
...
<object class="pl.dwalczak.Osoba">
 ...
 <void property="dataUrodzin">
  <object idref="date0"/>
 </void>
 ...
</object>
Pierwsza część konstrukcji (znacznik void z id="sdf"), to deklaracja, której w javie odpowiada:
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
java.util.Date date0 = sdf.parse("1983-12-03");
Nie definiuje ona żadnego zserializowanego obiektu, a jedynie zmienne, które mogą być wykorzystane przy definiowaniu zserializowanych obietków. Może być umieszczona w elemencie głównym, lub też bezpośrednio w zserializowanym obiekcie.
Druga część konstrukcji (znacznik object) definiuje obiekt typu pl.dwalczak.Osoba, w którym ustawia pole dataUrodzin wcześniej zdefiniowaną zmienną date0.

Wracając do typu wyliczeniowego.
Załóżmy, że klasa pl.dwalczak.Osoba posiada pole typOsoby o typie pl.dwalczak.TypOsoby, który jest enumeracjom:
package pl.dwalczak;
public enum TypOsoby {
 OsobaFizyczna,
 OsobaPrawna;
}
Wówczas ustawienie pola typOsoby dla obiektu pl.dwalczak.Osoba może wyglądać następująco:
<void property="type"> 
 <object class="com.dwalczak.TypOsoby" field="OsobaFizyczna"/> 
</void>
Lub tak:
<void property="type"> 
 <object class="com.dwalczak.TypOsoby" method="valueOf">
  <string>OsobaPrawna</string>
 </object> 
</void>

Podsumowanie

O ile problem z serializowaniem wartości typu wyliczeniowego, nie specjalnie zmniejsza atrakcyjność formatu standardowej serializacji obiektów XML w J2SE, jako ogólnego formatu zapisywania danych testowych, gdyż manualnie można to zapisać w całkiem przyzwoitej formie. To problem z datą faktycznie obniża tą atrakcyjność, gdyż formuła zapisu jej w "ludzkiej" postaci jest trochę za długa i skomplikowana. Mimo to, myślę że stosowanie tego formatu może być mniej pracochłonne niż projektowanie własnego i pisanie kodu deserializującego z niego obiekty.

Zasoby

Long Term Persistence of JavaBeans Components: XML Schema
Sergey Malenkov's Blog - How to encode Type-Safe Enums?

Brak komentarzy: