Some of posts from this blog has been moved to dywicki.pl. You will be automatically redirected to new blog if you would submit comment.
New posts are published on dywicki.pl, this blog contains old content and it is not continued.

Niektóre posty z tego bloga zostały przeniesione do dywicki.pl. Zostaniesz automatycznie przekierowany jeśli bedzięsz chciał dodać komentarz.
Nowe posty sa publikowane na dywicki.pl, ten blog zawiera stare treści i nie jest kontynuowany.

JAXB 2, zabawy z datą i konwersją typów

Filed under Java,JAXB by

Jedną z bolączek JAXB jest problematyczna obsługa dat i czasów. Przypomnijmy sobie schemat użyty w jednej z wcześniejszych not.


	<!-- Definicja książki -->
	<complextype name="Book">
		<sequence>
			<element name="title" type="string" minOccurs="1" />
			<element name="isbn" type="string" />
			<element name="releaseDate" type="date" />
			<element name="author" type="tns:Author" maxOccurs="unbounded" />
		</sequence>
	</complextype>

Jak widać, każda książka ma określoną datę wydania. Jakkolwiek typ date z XML Schema nie jest bezpośrednio odwzorowany do java.util.Date czy też java.util.Calendar. W przypadku implementacji dostarczonej przez Sun mamy do czynienia z obiektami klasy XMLGregorianCalendarImpl. Rozwiązaniem problemu jest dodanie odpowiedniego adaptera. Możemy robić to ręcznie ale najwygodniejszym rozwiązaniem będzie skorzystanie z gotowca – klasy javax.xml.bind.DatatypeConverter. Jej użycie wygląda następująco:

< ?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://dywicki.pl/court"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"
    xmlns:tns="http://dywicki.pl/court" elementFormDefault="qualified">
    <annotation>
        <appinfo>
            <jaxb :globalBindings>
                <jaxb :javaType name="java.util.Calendar" xmlType="date"
                    parseMethod="javax.xml.bind.DatatypeConverter.parseDate"
                    printMethod="javax.xml.bind.DatatypeConverter.printDate" />
            </jaxb:globalBindings>
        </appinfo>
    </annotation>

    <!-- tutaj deklaracje typów -->
</schema>

Podobne rozwiązanie można wykorzystać na poziomie pojedyńczego elementu aby zmapować konkretny element do obiektu. Element annotation można również dodać do deklaracji simpleType (powiedzmy reprezentacja numeru pesel + proste restrykcje).

    <complextype name="File">
        <sequence>
            <element name="category" type="string">
                <annotation>
                    <appinfo>
                        <jaxb :javaType
                            name="pl.dywicki.court.Category"
                            parseMethod="pl.dywicki.court.Category.parse"
                            printMethod="pl.dywicki.court.Category.print"
                        />
                    </appinfo>
                </annotation>
            </element>
        </sequence>
    </complextype>

JAXB wygeneruje wówczas odpowiednie adnotacje dla tworzonych klas oraz adaptery, które odwołują się do metod wskazanych w atrybutach elementu javaType.

W moim przypadku kod klasy Category wygląda następująco:

package pl.dywicki.court;

/**
 * Reprezentacja kategorii sprawy.
 *
 * @author Lukasz Dywicki <a href="mailto:luke@code-house.net">luke@code-house.net</a>
 **/
public class Category {

    private String name;

    public Category(String value) {
        this.name = value;
    }

    public static Category parse(String value) {
        return new Category(value);
    }
    
    public static String print(Category value) {
        return value.name;
    }
}

Jest to oczywiście maksymalnie uproszczony przykład. W konstruktorze bądź metodach, które konwertują string do obiektu możemy podpiąć walidację i bronić się wyjątkami przed nieprawidłowymi wartościami by uniemożliwić deserializację dokumentu.

4 responses so far

4 Responses to “JAXB 2, zabawy z datą i konwersją typów”

  1. wojtosz says:

    Widzę że wszystkie rzeczy do zdefiniowania upakowujesz do XML, a może tak chodź raz YAML ? :)

  2. Hej wojtosz!
    Kiedyś rozwodziłem się nad tym dlaczego nie yaml. Yaml to tylko konfiguracja, xml to znacznie więcej. :)

  3. tt says:

    Drugi listing jest zwalony – nie kompiluje się, bo:

    1.
    Jest tag “<jaxb :globalBindings>” , a powinno być “<jaxb:globalBindings>” .

    2.
    Tag “<jaxb:globalBindings>” , powinien być zamknięty przez “</jaxb:globalBindings>” , a nie przez “</jaxb>”

  4. Hej, tt. Poprawiłem drugi błąd w listingu. Pierwszy wynika z wad w skrypcie do kolorowania składni.

Leave a Reply