Java und XML: Direkte Bindung mit JAXB

Veröffentlicht am 18. November 2010

Im Java-Umfeld hat sich die Datenspeicherung mit XML schon weitestgehend zum Standard durchgesetzt. Vor allem viele Konfigurationsdateien (z.B. fast alle Config-Dateien in der Java Servlet Engine „Apache Tomcat“ sind in XML gehalten) sind regelmäßig in XML notiert; aber auch viele andere Datendateien für Java-Programme werden in XML definiert, da sich für dieses Format die Validierung und das Parsing sehr einfach und generisch in Java (und anderen Tools) durchführen lässt.

Eine sehr gängige Methode für das Einlesen (und interne Verwalten) von XML-Daten liegt darin, das XML-Dokument in einen Baum zu transformieren.

Hierbei sind alle Knoten des Dokuments (Elemente, Attribute, Entitäten und CDATA) als Node-Objekt im Speicher repräsentiert, deren Eigenschaften als Membervariablen dieses Node-Objekts gelesen werden können (z.B. Tagname, Typ des Elements, Wert eines Attrubuts, …). Die einzelnen Node-Objekte sind über eine Vater-Söhne-Relation miteinander verbunden.

Das Einlesen eines XML-Dokuments in einen Baum kann mit vielen Java-Toolkits gemacht werden (z.B. mit DOM = Document Object Model)

Eine großer Nachteil bei dieser Methode ist es, dass man in seinem Java-Programm meist selbstständig den Baum durchlaufen und interpretieren muss.
Natürlich kann man mit Hilfsmitteln, wie XPath sehr gut und effektiv Anfragen auf den XML-Baum ausführen, aber den XML-Baum in seine Java-Datenstrukturen umwandeln muss man noch selbst.

Eine andere Möglichkeit, Java mit XML zu vereinen bringt JAXB (Java Architecture for XML Binding).

JAXB

Die Idee hinter JAXB ist es, eine Java-Datenstruktur direkt in ein XML-Schema umwandeln zu können, so dass sich XML-Dateien, die in diesem Schema vorliegen, direkt in die entsprechende Java-Datenstruktur überführen lassen (und umgekehrt).

Solch einen Zusammenhang bezeichnet man als „Bindung“ (engl. binding), da die Java-Struktur an ein XML-Schema gebunden wird, so dass beide zueinander kompatibel sind.

Das Interessante an JAXB ist, dass diese zugehörige XML-Schema nicht von Hand erzeugt werden muss, sondern automatisch (über die intere Reflections-API von Java) aus den Klassendefinitionen erzeugt werden kann, wenn diese mit Annotatoren versehen werden.

Natürlich kann man in JAXB auch ein Schema von Hand erzeugen und benutzen, aber ich möchte in diesem Artikel ausschließlich auf die Methode mit Annotatoren eingehen.

Annotatoren

Annotatoren (engl. „annotations“) sind zusätzliche Attribute, mit denen man Klassen, Methoden oder Variablen versehen kann, um diese näher zu kennzeichnen, indem man sie mit einem @-Zeichen vor die entsprechende Definition schreibt (z.B. @Deprecated).

Es gibt Annotatoren, die vom Compiler ausgewertet werden (z.B. erzeugt eine @Deprecated Klasse eine Warnung, wenn sie benutzt wird), aber manche Annotatoren können auch zur Laufzeit gelesen und ausgewertet werden.

Man kann Annotatoren auch zusätzliche Eigenschaften mitgeben, die den Annotator genauer beschreiben. Im Fall von JAXB kann dies beispielsweise ein XML-Tagname sein, oder ob ein Element optional ist.

Hinweis: Die hier verwendeten Annotatoren stammen alle aus dem Package javax.xml.bind.annotation. Es gibt auch noch gleichnamige Annotatoren aus anderen (internen) Packages, die nicht verwendet werden sollen, weil sie eine andere Funktion haben und mit JAXB zusammen nicht funktionieren!

Erstellen der Datenstruktur

Damit eine Datenstruktur von JAXB gut verarbeitet werden kann, sollte sie möglichst einfach konstruiert sein (keine überflüssigen, also redundanten Informationen, wenig Kreuzverweise, klare Hierarchien) und außerdem müssen (falls das Einlesen XML -> Java funktionieren soll) alle gebundenen Eigenschaften schreibbar sein.

Falls man in seinem Programm lieber mit immutablen, also unveränderlichen Objekten zur Threadsicherheit arbeitet, kann man entweder eine zusätzliche Datenstruktur für JAXB erstellen, die dann leicht auf eine immutable Version des Objekts umgewandelt werden kann, oder man verwendet das Facade-Entwurfsmuster, um dem eigentlichen Programm die Schreibzugriffe vorzuenthalten.

Außerdem muss man sich überlegen, ob man lieber mit Attributen (öffentliche Member-Variablen) oder Properties (private Member-Variablen und öffentliche Setter und Getter) arbeitet.
Beides kann von JAXB verarbeitet werden, und sowohl Attribute als auch Properties werden per Default mit in das XML-Schema übernommen.
Eine Klasse darf aber nicht gleichzeitig ein Attribut und eine Property mit dem selben Namen im Schema haben (eins von beiden muss dann deaktiviert werden).

Zusätzlich muss ein leerer Konstruktor für alle gebundenen Klassen vorhanden sein, da JAXB nach dem „Datenbean“-Schema arbeitet: Zuerst wird ein neues Objekt mit leerem Konstruktor erstellt und dann werden mit den Settern (oder Attributzugriffen) alle relevanten Properties (bzw. Attribute) gesetzt.

In diesem Beispiel möchte ich eine Datenstruktur für eine einfache Bibliotheksverwaltung (Bücher, Zeitschriften, Autoren und Daten usw.) in XML abbilden.
Ich werde hier zur Veranschaulichung sowohl Attribute, als auch Properties benutzen, um das System zu erklären.

Dazu sind erst einmal die Datenklassen zu schaffen:

Date.java
package jaxbdemo;

public class Date {

	// Diese Klasse nutzt öffentliche Attribute
	
	public int year;
	public int month;
	public int day;
	
	/**
	 * Leerer Konstruktor (für JAXB)
	 */
	public Date() {	}
	
	/**
	 * Daten-Konstruktor
	 */
	public Date(int day, int month, int year) {
		this.year = year;
		this.month = month;
		this.day = day;
	}
	
}
Author.java
package jaxbdemo;

public class Author {

	// Diese Klasse verwendet Properties
	
	private String firstname;
	private String name;
	private Date birthday;
	
	/**
	 * Leerer Konstruktor (für JAXB)
	 */
	public Author() {
		this.firstname = "";
		this.name = "";
		this.birthday = null;
	}
	
	/**
	 * Daten-Konstruktor
	 */
	public Author(String firstname, String name, Date birthday) {
		this.firstname = firstname;
		this.name = name;
		this.birthday = birthday;
	}
	
	/* Setter und Getter */
	
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	
	public Date getBirthday() {
		return birthday;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}
	
	public String getFirstname() {
		return firstname;
	}
	
}
Book.java
package jaxbdemo;

public class Book {
	
	private String title;
	private String publisher;
	private String abstractText;
	private Author author;
	private Author coauthor;
	private Date published;
	
	/**
	 * Leerer Konstruktor (für JAXB)
	 */
	public Book() {
		this.title = "";
		this.publisher = "";
		this.abstractText = null;
		this.author = null;
		this.coauthor = null;
		this.published = null;
	}

	/**
	 * Datenkonstruktor
	 */
	public Book(String title, String publisher, String abstractText,
			Author author, Author coauthor, Date published) {
		this.title = title;
		this.publisher = publisher;
		this.abstractText = abstractText;
		this.author = author;
		this.coauthor = coauthor;
		this.published = published;
	}
	
	/* Setter und Getter */
	
	public void setTitle(String title) {
		this.title = title;
	}
	
	public String getTitle() {
		return title;
	}
	
	public void setPublisher(String publisher) {
		this.publisher = publisher;
	}
	
	public String getPublisher() {
		return publisher;
	}
	
	public void setAbstractText(String abstractText) {
		this.abstractText = abstractText;
	}
	
	public String getAbstractText() {
		return abstractText;
	}
	
	public void setAuthor(Author author) {
		this.author = author;
	}
	
	public Author getAuthor() {
		return author;
	}
	
	public void setCoauthor(Author coauthor) {
		this.coauthor = coauthor;
	}
	
	public Author getCoauthor() {
		return coauthor;
	}
	
	public void setPublished(Date published) {
		this.published = published;
	}
	
	public Date getPublished() {
		return published;
	}

}
Journal.java
package jaxbdemo;

public class Journal {

	private String title;
	private String publisher;
	private Date published;
	
	/**
	 * Leerer Konstruktor (für JAXB)
	 */
	public Journal() {
		this.title = "";
		this.publisher = "";
		this.published = null;
	}
	
	/**
	 * Datenkonstruktor
	 */
	public Journal(String title, String publisher, Date published) {
		this.title = title;
		this.publisher = publisher;
		this.published = published;
	}
	
	/* Setter und Getter */
	
	public void setTitle(String title) {
		this.title = title;
	}
	
	public String getTitle() {
		return title;
	}
	
	public void setPublisher(String publisher) {
		this.publisher = publisher;
	}
	
	public String getPublisher() {
		return publisher;
	}
	
	public void setPublished(Date published) {
		this.published = published;
	}
	
	public Date getPublished() {
		return published;
	}
	
}
Library.java
package jaxbdemo;

import java.util.LinkedList;
import java.util.List;

public class Library {
	
	private List<Book> books;
	
	private List<Journal> journals;
	
	private List<Author> featured;
	
	/**
	 * Leerer Konstruktor (für JAXB)
	 */
	public Library() {
		this.books = new LinkedList<Book>();
		this.journals = new LinkedList<Journal>();
		this.featured = new LinkedList<Author>();
	}
	
	/* 
	 * Setter und Getter 
	 */

	public void setBooks(List<Book> books) {
		this.books = books;
	}
	
	public List<Book> getBooks() {
		return books;
	}
	
	public void setJournals(List<Journal> journals) {
		this.journals = journals;
	}
	
	public List<Journal> getJournals() {
		return journals;
	}
	
	public void setFeatured(List<Author> featured) {
		this.featured = featured;
	}
	
	public List<Author> getFeatured() {
		return featured;
	}
	
	// --- Hilfsmethoden ---
	
	public void addBook(Book book) {
		this.books.add(book);
	}
	
	public void addJournal(Journal journal) {
		this.journals.add(journal);
	}
	
	public void addFeatured(Author featured) {
		this.featured.add(featured);
	}
	
}

Um ein wenig Content für die Demo zu haben, sollte noch eine Klasse für Main() und zum erstellen des Demo-Contents erstellt werden:

DemoMain.java
package jaxbdemo;

public class DemoMain {
	
	/**
	 * Erstelle Demo Daten
	 */
	public static Library makeDemoLibrary() {
		Library library = new Library();
		
		Author johnSmith = new Author("John", "Smith", new Date(27, 4, 1965));
		Author joeMiller = new Author("Joe F.", "Miller", new Date(16, 1, 1943));
		Author jimMeyers = new Author("Jim", "Meyers", new Date(20, 11, 1973));
		Author hubertCameron = new Author("Hubert", "Cameron", null);
		
		Book book1 = new Book("The Art of Programming", "Springer Verlag",
				"Es war einmal ...", johnSmith, null, new Date(11, 10, 2003));
		
		Book book2 = new Book("Buch der Sinnlosigkeit", "Ravensburger", null,
				joeMiller, johnSmith, new Date(3, 5, 1999));
		
		Book book3 = new Book("Termodynamik von kristallinem Wasser",
				"Springer Verlag", "Eine toole Einleitung ...",
				jimMeyers, null, new Date(6, 12, 2005));
		
		Journal journal1 = new Journal("Spektrum der Wissenschaft",
				"Spektrum Verlag", new Date(1, 6, 2010));
		
		Journal journal2 = new Journal("Spektrum der Wissenschaft",
				"Spektrum Verlag", new Date(1, 8, 2010));
	
		Journal journal3 = new Journal("Der Spiegel", "Spiegel Verlag",
				new Date(15, 3, 2005));
		
		library.addBook(book1);
		library.addBook(book2);
		library.addBook(book3);
		
		library.addJournal(journal1);
		library.addJournal(journal2);
		library.addJournal(journal3);
		
		library.addFeatured(johnSmith);
		library.addFeatured(hubertCameron);
		
		return library;
	}

}

Binden der Datenklassen mit JAXB-Annotatoren

Als nächstes müssen die Datenklassen mit Annotatoren so gekennzeichnet werden, dass sie von JAXB verarbeitet werden können. Hierbei gelten folgende Regeln:

  • Die Basisklasse (hier: Library) muss mit dem Annotator @XmlRootElement gekennzeichnet werden.
  • Um ein Property zu annotieren, kann entweder der Setter oder Getter annotiert werden
  • Um Attribute oder Properties mit in die XML-Struktur aufzunehmen kann der Annotator @XmlElement oder @XmlAttribute verwendet werden (per Default werden Properties und öffentliche Attribute als XML-Element benutzt)
  • Der Tagnamen/Attributnamen eines Attributes oder einer Property wird automatisch vom Java-Namen übernommen
  • Um einen eigenen Namen für Elemente/Attribute festzulegen, kann dem Annotator das Attribut „name“ mit übergeben werden (z.B. @XmlElement(name = "MeinTagName"))
  • Um ein Element/Attribut als optional zu kennzeichnen, kann dem Annotator das Attribut required = false mitgegeben werden.
  • Um eine Property/ein öffentliches Attribut nicht mit in das XML-Schema aufzunehmen, muss es mit dem Annotator @XmlTransient versehen werden
  • Listen werden normalerweise als eine Reihe von Elementen gebunden, wobei für jeden Listeneintrag ein Element des Propertynamens erzeugt wird. Um eine Liste noch in ein Unterelement zu kapseln, kann der Annotator @XmlElementWrapper vorgeschaltet werden (Ein Beispiel für die Anwendung dieses Annotators findet sich für die Listen in der Klasse Library.java.

Da die meisten Strukturen automatisch erkannt werden, ist in diesem beispiel nicht viel zu tun. Das Einzige, was annotiert werden muss, ist das Root-Element, die Wrapper für die Listen und Elemente, die in XML einen anderen Namen haben sollen, als in Java (z.B. ist in Java “abstract” kein gültiger Bezeichner, in XML ist es allerdings ein gültige Elementname).

Fügt man die entsprechenden Annotatoren zu den Beispiel-Klassen hinzu, so ergibt sich:

Date.java (unverändert)
package jaxbdemo;

public class Date {

	// Diese Klasse nutzt öffentliche Attribute
	
	public int year;
	public int month;
	public int day;
	
	/**
	 * Leerer Konstruktor (für JAXB)
	 */
	public Date() {	}
	
	/**
	 * Daten-Konstruktor
	 */
	public Date(int day, int month, int year) {
		this.year = year;
		this.month = month;
		this.day = day;
	}
	
}
Author.java (unverändert)
package jaxbdemo;

public class Author {

	// Diese Klasse verwendet Properties
	
	private String firstname;
	private String name;
	private Date birthday;
	
	/**
	 * Leerer Konstruktor (für JAXB)
	 */
	public Author() {
		this.firstname = "";
		this.name = "";
		this.birthday = null;
	}
	
	/**
	 * Daten-Konstruktor
	 */
	public Author(String firstname, String name, Date birthday) {
		this.firstname = firstname;
		this.name = name;
		this.birthday = birthday;
	}
	
	/* Setter und Getter */
	
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	
	public Date getBirthday() {
		return birthday;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}
	
	public String getFirstname() {
		return firstname;
	}
	
}
Journal.java (unverändert)
package jaxbdemo;

public class Journal {

	private String title;
	private String publisher;
	private Date published;
	
	/**
	 * Leerer Konstruktor (für JAXB)
	 */
	public Journal() {
		this.title = "";
		this.publisher = "";
		this.published = null;
	}
	
	/**
	 * Datenkonstruktor
	 */
	public Journal(String title, String publisher, Date published) {
		this.title = title;
		this.publisher = publisher;
		this.published = published;
	}
	
	/* Setter und Getter */
	
	public void setTitle(String title) {
		this.title = title;
	}
	
	public String getTitle() {
		return title;
	}
	
	public void setPublisher(String publisher) {
		this.publisher = publisher;
	}
	
	public String getPublisher() {
		return publisher;
	}
	
	public void setPublished(Date published) {
		this.published = published;
	}
	
	public Date getPublished() {
		return published;
	}
	
}
Book.java
package jaxbdemo;

import javax.xml.bind.annotation.XmlElement;

public class Book {
	
	private String title;
	private String publisher;
	private String abstractText;
	private Author author;
	private Author coauthor;
	private Date published;
	
	/**
	 * Leerer Konstruktor (für JAXB)
	 */
	public Book() {
		this.title = "";
		this.publisher = "";
		this.abstractText = null;
		this.author = null;
		this.coauthor = null;
		this.published = null;
	}

	/**
	 * Datenkonstruktor
	 */
	public Book(String title, String publisher, String abstractText,
			Author author, Author coauthor, Date published) {
		this.title = title;
		this.publisher = publisher;
		this.abstractText = abstractText;
		this.author = author;
		this.coauthor = coauthor;
		this.published = published;
	}
	
	/* Setter und Getter */
	
	public void setTitle(String title) {
		this.title = title;
	}
	
	public String getTitle() {
		return title;
	}
	
	public void setPublisher(String publisher) {
		this.publisher = publisher;
	}
	
	public String getPublisher() {
		return publisher;
	}
	
	@XmlElement (name = "abstract")
	public void setAbstractText(String abstractText) {
		this.abstractText = abstractText;
	}
	
	public String getAbstractText() {
		return abstractText;
	}
	
	public void setAuthor(Author author) {
		this.author = author;
	}
	
	public Author getAuthor() {
		return author;
	}
	
	public void setCoauthor(Author coauthor) {
		this.coauthor = coauthor;
	}
	
	public Author getCoauthor() {
		return coauthor;
	}
	
	public void setPublished(Date published) {
		this.published = published;
	}
	
	public Date getPublished() {
		return published;
	}

}
Library.java
package jaxbdemo;

import java.util.LinkedList;
import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Library {
	
	private List<Book> books;
	
	private List<Journal> journals;
	
	private List<Author> featured;
	
	/**
	 * Leerer Konstruktor (für JAXB)
	 */
	public Library() {
		this.books = new LinkedList<Book>();
		this.journals = new LinkedList<Journal>();
		this.featured = new LinkedList<Author>();
	}
	
	/* 
	 * Setter und Getter 
	 */

	@XmlElementWrapper (name = "books")
	@XmlElement (name = "book")
	public void setBooks(List<Book> books) {
		this.books = books;
	}
	
	public List<Book> getBooks() {
		return books;
	}
	
	@XmlElementWrapper (name = "journals")
	@XmlElement (name = "journal")
	public void setJournals(List<Journal> journals) {
		this.journals = journals;
	}
	
	public List<Journal> getJournals() {
		return journals;
	}
	
	@XmlElementWrapper (name = "featuredAuthors")
	@XmlElement (name = "author")
	public void setFeatured(List<Author> featured) {
		this.featured = featured;
	}
	
	public List<Author> getFeatured() {
		return featured;
	}
	
	// --- Hilfsmethoden ---
	
	public void addBook(Book book) {
		this.books.add(book);
	}
	
	public void addJournal(Journal journal) {
		this.journals.add(journal);
	}
	
	public void addFeatured(Author featured) {
		this.featured.add(featured);
	}
	
}

Marshalling

Das Umwandeln eines gebundenen Java-Objekts in XML heißt im JAXB-Kontext “marshalling”.
Um nun aus unseren erzeugten Demo-Objekt eine XML-Datei zu erzeugen, muss folgendes getan werden:

  1. Erstellen eines JAXB-Kontextes aus der gebundenen Klassenstruktur (Library)
  2. Erstellen eines Marshallers aus dem Kontext
  3. Verarbeiten des Objekts durch den Marshaller
try {
		
	JAXBContext context = JAXBContext.newInstance(Library.class);
	Marshaller marshaller = context.createMarshaller();
	marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
	
	Library demoLib = makeDemoLibrary();
	
	marshaller.marshal(demoLib, new File("demoLib.xml"));

} catch (JAXBException e) {
	e.printStackTrace();
}

Der Marshaller kann die erzeugten XML-Daten entweder in einen Stream schreiben oder - wie hier - in eine Datei.

Unmarshalling

Der umgekehrte Vorgang wir Unmarshalling genannt: aus einer kompatiblen XML-Datei wir mittels JAXB ein Java-Objekt erzeugt.

Der Aufruf erfolgt fast analog:

try {
	
	// Der context ist der selbe wie beim marshalling ...
	Unmarshaller unmarshaller = context.createUnmarshaller();
	
	Object obj = unmarshaller.unmarshal(new File("demoLib.xml"));
	if (obj instanceof Library) {
		Library anotherLib = (Library) obj;
		System.out.println("Library erfolgreich wiederhergestellt: " + anotherLib);
	} else {
		System.out.println("Unmarshalling nicht erfolgreich...");
	}

} catch (JAXBException e) {
	e.printStackTrace();
}

Zusammenfassung

Wir haben gesehen, dass mit wenig Aufwand ein XML-Schema für Java-Klassen erzeugt werden und damit das Einlesen und Ausgeben von XML-Dokumenten mit fester Struktur stark vereinfacht werden kann.
Ich hab JAXB als mächtiges Werkzeug kennen gelernt und setze es (trotz anfänglicher Bedenken) doch gerne ein.

Zum Abschluss noch die fertige Main-Klasse:

DemoMain.java
package jaxbdemo;

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class DemoMain {
	
	/**
	 * Main Methode.
	 */
	public static void main(String[] args) {
		
		try {
		
			// Marshal
			
			JAXBContext context = JAXBContext.newInstance(Library.class);
			Marshaller marshaller = context.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
			
			Library demoLib = makeDemoLibrary();
			
			marshaller.marshal(demoLib, new File("demoLib.xml"));
			
			// Unmarshal
			
			// Der context ist der selbe wie beim marshalling ...
			Unmarshaller unmarshaller = context.createUnmarshaller();
			
			Object obj = unmarshaller.unmarshal(new File("demoLib.xml"));
			if (obj instanceof Library) {
				Library anotherLib = (Library) obj;
				System.out.println("Library erfolgreich wiederhergestellt: " + anotherLib);
			} else {
				System.out.println("Unmarshalling nicht erfolgreich...");
			}
		
		} catch (JAXBException e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * Erstelle Demo Daten
	 */
	public static Library makeDemoLibrary() {
		Library library = new Library();
		
		Author johnSmith = new Author("John", "Smith", new Date(27, 4, 1965));
		Author joeMiller = new Author("Joe F.", "Miller", new Date(16, 1, 1943));
		Author jimMeyers = new Author("Jim", "Meyers", new Date(20, 11, 1973));
		Author hubertCameron = new Author("Hubert", "Cameron", null);
		
		Book book1 = new Book("The Art of Programming", "Springer Verlag",
				"Es war einmal ...", johnSmith, null, new Date(11, 10, 2003));
		
		Book book2 = new Book("Buch der Sinnlosigkeit", "Ravensburger", null,
				joeMiller, johnSmith, new Date(3, 5, 1999));
		
		Book book3 = new Book("Termodynamik von kristallinem Wasser",
				"Springer Verlag", "Eine toole Einleitung ...",
				jimMeyers, null, new Date(6, 12, 2005));
		
		Journal journal1 = new Journal("Spektrum der Wissenschaft",
				"Spektrum Verlag", new Date(1, 6, 2010));
		
		Journal journal2 = new Journal("Spektrum der Wissenschaft",
				"Spektrum Verlag", new Date(1, 8, 2010));
	
		Journal journal3 = new Journal("Der Spiegel", "Spiegel Verlag",
				new Date(15, 3, 2005));
		
		library.addBook(book1);
		library.addBook(book2);
		library.addBook(book3);
		
		library.addJournal(journal1);
		library.addJournal(journal2);
		library.addJournal(journal3);
		
		library.addFeatured(johnSmith);
		library.addFeatured(hubertCameron);
		
		return library;
	}

}

Programmierbeispiele zum Download

Download auf Github

Kategorie: Java