Table of Contents
Zapis i odczyt dokumentu
Zakładamy, że utworzony programowo dokument został zapisany w postaci pliku HTML. Co jednak, gdybyśmy chcieli mieć możliwość zapisu i późniejszego odczytu zawartości dokumentu?
Jednym z wygodnych rozwiązań jest zastosowanie JAXB (Java Architecture for XML Binding), biblioteki pozwalającej na zapis złożonej struktury obiektów w pamięci w formacie XML (ang. marshal) i późniejsze odtworzenie struktury obiektów z dokumentu XML (ang. unmarshal).
Aby zapis i odczyt był mozliwy musi być spełnionych kilka warunków:
- musimy oznaczyć elementy, które chcemy zapisać (można też wymusić użycie specyficznych tagów lub atrybutów XML). Czyli raczej oznaczamy niż programujemy, ale oszczędzamy bardzo dużo czasu!
- ponieważ przy odczycie tworzone są nowe puste obiekty na podstawie tagów, może być wymagane dodanie standardowych konstruktorów (tam gdzie są obecne konstruktory z parametrami).
Dla przypomnienia <to:jest:tag att=“a to jest atrybut”> a tag zamykający wygląda tak </to:jest:tag>.
Adnotacje
Biblioteka JAXB używa specyficznego mechanizmu języka - adnotacji (ang. annotations) [który chyba nie będzie omawiany na wykładzie ???]
Adnotacje mają postać @Identifier lub @Identifier(key=value[,otherkey=othervalue]) i są umieszczane w kodzie programu, zazwyczaj przed definicją klasy, deklaracją atrybutu lub definicją metody.
Na przykład:
<code java>
@Override
public String toString(){
return "";
}
</code>
Adnotacje nie mają bezpośredniego wpływu na wykonanie kodu, ale mogą być wykorzystywane przez zewnętrzne narzędzia przetwarzające kod (zarówno źródłowy, jak i skompilowany):
- kompilator
- biblioteki, które na podstawie adnotacji dowiadują się, w jaki sposób przetwarzać obiekty, na przykład:
- wypełniać ich atrybuty danymi zapisanymi w zewnętrznych źródłach (dokumentach, bazach danych)
- zapisywać obiekty w specyficznych formatach
- wybierać specyficzne elementy, np. funkcje służące do testowania
@org.junit.Test - wiązać wywołania metod i ich parametry z interfejsem sieciowym
Formalnie, adnotacje deklaruje się jak interfejsy i umieszcza w pakietach
Dodając adnotacje zadbaj, aby importować elementy z pakietu javax.xml.bind.annotation
Metody do zapisu i odczytu
Dodaj w klasie Document metody do zapisu i odczytu
<code java>
public void write(String fileName){
try {
JAXBContext jc = JAXBContext.newInstance(Document.class);
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
FileWriter writer= new FileWriter(fileName);;
m.marshal(this, writer);
} catch (JAXBException ex) {
ex.printStackTrace();
}
catch (IOException ex) {
ex.printStackTrace();
}
}
public static Document read(String fileName){
try {
JAXBContext jc = JAXBContext.newInstance(Document.class);
Unmarshaller m = jc.createUnmarshaller();
FileReader reader = new FileReader(fileName);
return (Document) m.unmarshal(reader);
} catch (JAXBException ex) {
ex.printStackTrace();
} catch (FileNotFoundException ex) {
ex.printStackTrace();
}
return null;
}
</code>
Dodaj także w funkcji main() kod, który zapisuje (i odczytuje) dokument
<code java>
cv.write("cv.xml");
//Document cv2 = Document.read("cv.xml");
//cv2.writeHTML(System.out);
</code>
Dla użytkowników Java 9 (zazwyczaj na laptopach)
Java SE 9 nie widzi części modułów Java EE, w tym JAXB.
1. W IntelliJ w dialogu Project Structure - ustaw Project language Level : 8 - lambdas, type annotations
2. Zalecanym obejściem (w https://blog.codefx.org/java/java-9-migration-guide/) jest dodanie opcji uruchamiania programu
<code> –add-modules java.se.ee </code>
W IntelliJ nalezy je wpisac w oknie Run → Edit Configurations → pole VM options
Dodajemy adnotacje
W następnych etapach będziemy modyfikowali kod (dodawali adnotacje) i sprawdzali, co zmienia się w pliku cv.xml
Najczęściej używane będą następujące adnotacje
@XmlRootElement - oznaczenie klasy będącej korzeniem drzewa XML@XmlElement - oznaczenie, że atrybut ma zostać zapisany jako element XML (jako nazwa znacznika XML zostanie użyta nazwa atrybutu)@XmlElement(name=“xyz”) - podana jest nazwa znacznikaxyzXmlAttribute atrybut (pole klasy) zostanie zapisany jako atrybut XML
Oznacz Document jako XMLRootElement
<code java> @XmlRootElement public class Document { … } </code>
Zobacz, co zostało zapisane do pliku cv.xml
Oznacz atrybuty klasy Document
<code java>
@XmlElement String title; @XmlElement List<Section> sections = new ArrayList<>(); @XmlElement Photo photo;
</code>
Wykonaj program i spróbuj zidentyfikować i naprawić błąd…
Photo
Pole url odwzorujemy w atrybut
<code java>
@XmlAttribute String url;
</code>
Section
Tytuł jest zapewne krótki - odwzorujemy go w atrybut, natomiast listę akapitów (paragraphs) w XmlElement
Poprawiamy nazwy znaczników XML
Zastąp w odpowiednim miejscu @XmlElement przez @XmlElement(name=“section”) i @XmlElement(name=“paragraph”).
Nie widać listy w cv.xml?
1. Uzupełnijmy więc znaczniki w ParagraphWithList, UnorderedList oraz ListItem
Prawdopodobnie dalej lista w cv.xml nie będzie widoczna…
2. Poinformuj, JAXB o klasach potomnych Paragraph
<code java> @XmlSeeAlso({ParagraphWithList.class}) public class Paragraph { </code>
… i usuń ewentualne błędy.
3. Możesz przyjrzeć się znacznikom i poprawić nazwy według uznania
