Zaimplementujemy kilka klas, które pozwolą na utworzenie strukturalnego dokumentu - i wypełnimy przykładowymi danymi tak, aby powstało CV.
Dokument będzie miał:
Klasa Photo
jest raczej prosta
public class Photo { Photo(String url){ this.url =url; } String url; void writeHTML(PrintStream out){ out.printf("<img src=\"%s\" alt=\"Smiley face\" height=\"42\" width=\"42\"/>\n",url) } }
Klasa powinna mieć następujące atrybuty:
String title; Photo photo; List<Section> sections = new ArrayList<>();
oraz metody:
Document setTitle(String title){ this.title = title; return this; } Document setPhoto(String photoUrl){ // ??? return this; } Section addSection(String sectionTitle){ // utwórz sekcję o danym tytule i dodaj do sections return ???; } Document addSection(Section s){ return this; } void writeHTML(PrintStream out){ // zapisz niezbędne znaczniki HTML // dodaj tytuł i obrazek // dla każdej sekcji wywołaj section.writeHTML(out) }
Możesz dodać konstruktor ustalający tytuł dokumentu.
Sekcja powinna mieć następujące atrybuty:
String title; List<Paragraph> paragraps = new ArrayList<>() ;
oraz metody
Section setTitle(String title){} Section addParagraph(String paragraphText){} Section addParagraph(Paragraph p){} void writeHTML(PrintStream out){}
Możesz dodać konstruktor ustalający tytuł sekcji.
Atrybut content
to treść akapitu.
setContent()
zmienia treśćwriteHTML()
powinna umieszczać treść pomiędzy znacznikam <p>…</p>
Dodaj na podstawie diagramu
ParagraphWithList
ma dodatkowy atrybut - listę typu UnorederedList
; można ją wypisać wewnątrz znaczników <p>…</p>
lub po znaczniku zamykającym. UnorederedList
przechowuje na liście elementy ListItem
ListItem
zawiera wyłącznie tekst
Klasa UnorederedList
została wprowadzona, ponieważ będzie odpowiedzialna za wypisywanie
<ul> ... ... </ul>
Podobnie ListItem
ma wypisywać tekst pomiędzy znacznikami <li>…</li>
Spróbuj dobrać funkcje tak, aby budowało się w miarę wygodnie. Na przykład tak:
Document cv = new Document("Jana Kowalski - CV"); cv.setPhoto("https://upload.wikimedia.org/wikipedia/commons/thumb/7/71/Calico_tabby_cat_-_Savannah.jpg/1200px-Calico_tabby_cat_-_Savannah.jpg"); cv.addSection("Wykształcenie") .addParagraph("2000-2005 Przedszkole im. Królewny Snieżki w ...") .addParagraph("2006-2012 SP7 im Ronalda Regana w ...") .addParagraph( new ParagraphWithList().setContent("Kursy") .addListItem("Języka Angielskiego") .addListItem("Języka Hiszpańskiego") .addListItem("Szydełkowania") ); cv.addSection("Umiejętności") .addParagraph( new ParagraphWithList().setContent("Znane technologie") .addListItem("C") .addListItem("C++") .addListItem("Java") );
Możesz wygenerować swoje CV lub wyimaginowanej osoby, ale zadbaj, aby znalazło się w nim wystarczająco dużo informacji.
Powinno to być jedno wywołanie, jak (wypisujące na konsoli)
cv.writeHTML(System.out);
lub (wpisujące do pliku)
cv.writeHTML(new PrintStream("cv.html","ISO-8859-2")); // lub cv.writeHTML(new PrintStream("cv.html","UTF-8"));
Wygeneruj poprawny składniowo dokumenty HTML. Możesz zastosować zdefiniowane w nagłówku style CSS, aby zapewnić ładne formatowanie.
Więcej informacji na temat języka HTML: https://www.w3schools.com/html/
Głównym celem klas jest generacja kodu w HTML. Testy powinny więc sprawdzać głównie poprawność generacji: obecność znaczników i danych w wygenerowanym kodzie…
Co może być sprawdzone dla wyjścia typu <img src=“jan-kowalski.png” alt=“Smiley face” height=“42” width=“42”/>
?
Przykład implementacji
public class PhotoTest { @org.junit.Test public void writeHTML() throws Exception { String imageUrl = "jan-kowalski.png"; // Utwórz strumień zapisujący w pamięci ByteArrayOutputStream os = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(os); // Utwórz obiekt i zapisz do strumienia new Photo(imageUrl).writeHTML(ps); String result = null; // Pobierz jako String try { result = os.toString("ISO-8859-2"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } //System.out.println(result); // Sprawdź, czy result zawiera wybrane elementy assertTrue(result.contains("<img")); assertTrue(result.contains("/>")); assertTrue(result.contains("src=")); assertTrue(result.contains(imageUrl)); } }
Napisz testy sprawdzające poprawność generacji kodu dla trzech wybranych klas.
W poprzedniej wersji lab4_old częścią zadania był zapis i odczyt danych dokumentu w formacie XML. Obsługa XML za pomocą biblioteki JAXB została wycofana z dystrybucji Java SE. Jest częścią Java EE (Enterprise Edition), gdzie wykorzystywana jest do obsługi protokołu SOAP służącego do zdalnego wywołania procedur. Zamiast XML użyjemy więc formatu JSON.
Spośród dostępnych bibliotek do obsługi formatu JSON https://www.baeldung.com/java-json użyjemy Gson
com.google.code.gson
. Następnie aktywuj lupę (wyszukiwanie) i wybierz wersję, np. 2.10.1Generalnie, InteliJ ma (może miewał?) czasem problemy ze znajdywaniem bibliotek. Warto sprawdzić wersje w Maven Repository. Z nieznanych powodów InteliJ nie jest w stanie ich znaleźć, ale jest w stanie pobrać i zainstalować.
Serializacja to proces zamiany obiektów na format służący do przechowywania lub transferu danych. Często też w języku angielskim jest określana terminem marshaling, zwłaszcza w kontekście serializacji obiektów w celu przesłania ich przez sieć, patrz Wikipedia
Dodaj kod w klasie Dokument
String toJson(){ Gson gson = new GsonBuilder().setPrettyPrinting().create(); return gson.toJson(this); }
Wypisz zwrócony tekst. Efekt powinien być podobny do poniższego:
{ "title": "Jana Kowalski - CV", "photo": { "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/71/Calico_tabby_cat_-_Savannah.jpg/1200px-Calico_tabby_cat_-_Savannah.jpg" }, "sections": [ { "title": "Wykształcenie", "paragraphs": [ { "content": "2000-2005 Przedszkole im. Królewny Snieżki w ..." }, { "content": "2006-2012 SP7 im Ronalda Regana w ..." }, { "list": { "items": [ { "content": "Języka Angielskiego" }, { "content": "Języka Hiszpańskiego" }, { "content": "Szydełkowania" } ] }, "content": "Kursy" } ] }, { "title": "Umiejętności", "paragraphs": [ { "list": { "items": [ { "content": "C" }, { "content": "C++" }, { "content": "Java" } ] }, "content": "Znane technologie" } ] } ] }
Dodaj w klasie Dokument statyczną funkcję zamieniająca tekst na obiekt dokument
Document fromJson(String jsonString){ Gson gson = new GsonBuilder().create(); return gson.fromJson(jsonString, Document.class); }
Wywołaj tę funkcje i przeanalizuj zawartość odtworzonego dokumentu. Na przykład zapisz w formacie HTML lub JSON.
Wniosek: obiekty klasy ParagraphWithList
nie zostały poprawnie wczytane.
Hierarchie klas są na ogół problemem podczas deserializacji. Jeżeli w klasie Section
lista akapitów jest zdefiniowana jako List<Paragraph> paragraphs = new ArrayList<>();
biblioteka spodziewa się obiektów klasy bazowej, a nie potomnej. Tworzy więc obiekty klasy bazowej i ignoruje listę będącą atrybutem ParagraphWithList
Jednym z rozwiązań jest jawne przekazanie informacji o typie.
danilopianini.gson.extras
. Dla gson 2.10.1 gson-extras w wersji 0.2.1 zadziałało poprawnie.String toJson(){ RuntimeTypeAdapterFactory<Paragraph> adapter = RuntimeTypeAdapterFactory .of(Paragraph.class) .registerSubtype(Paragraph.class) .registerSubtype(ParagraphWithList.class); Gson gson = new GsonBuilder().registerTypeAdapterFactory(adapter).setPrettyPrinting().create(); return gson.toJson(this);
W tym przypadku wynik powinien być następujący:
{ "title": "Jana Kowalski - CV", "photo": { "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/71/Calico_tabby_cat_-_Savannah.jpg/1200px-Calico_tabby_cat_-_Savannah.jpg" }, "sections": [ { "title": "Wykształcenie", "paragraphs": [ { "type": "Paragraph", "content": "2000-2005 Przedszkole im. Królewny Snieżki w ..." }, { "type": "Paragraph", "content": "2006-2012 SP7 im Ronalda Regana w ..." }, { "type": "ParagraphWithList", "list": { "items": [ { "content": "Języka Angielskiego" }, { "content": "Języka Hiszpańskiego" }, { "content": "Szydełkowania" } ] }, "content": "Kursy" } ] }, { "title": "Umiejętności", "paragraphs": [ { "type": "ParagraphWithList", "list": { "items": [ { "content": "C" }, { "content": "C++" }, { "content": "Java" } ] }, "content": "Znane technologie" } ] } ] }
ParagraphWithList
.