XStream-Benutzerhandbuch: Konvertieren von Objekten in XML
1. Überblick
In diesem Tutorial erfahren Sie, wie Sie mit der BibliothekXStreamJava-Objekte in XML serialisieren.
2. Eigenschaften
Die Verwendung von XStream zum Serialisieren und Deserialisieren von XML bietet einige interessante Vorteile:
-
Richtig konfiguriert erzeugt es sehrclean XML
-
Bietet signifikante Möglichkeiten fürcustomization der XML-Ausgabe
-
Unterstützung fürobject graphs, einschließlich Zirkelverweisen
-
In den meisten Anwendungsfällen ist die XStream-Instanzthread-safe, once configured (bei der Verwendung von Anmerkungen gibt es Einschränkungen).
-
Währendexception handling werden eindeutige Meldungen bereitgestellt, um die Diagnose von Problemen zu erleichtern
-
Ab Version 1.4.7 stehensecurity featureszur Verfügung, um die Serialisierung bestimmter Typen zu verbieten
3. Projektaufbau
Um XStream in unserem Projekt zu verwenden, werden wir die folgende Maven-Abhängigkeit hinzufügen:
com.thoughtworks.xstream
xstream
1.4.9
4. Grundsätzliche Verwendung
Die KlasseXStream ist eine Fassade für die API. Beim Erstellen einer Instanz vonXStream müssen wir uns auch um Thread-Sicherheitsprobleme kümmern:
XStream xstream = new XStream();
Sobald eine Instanz erstellt und konfiguriert wurde, kann sie für das Marshalling / Unmarshalling von mehreren Threads gemeinsam genutzt werden, es sei denn, Sie aktivieren die Anmerkungsverarbeitung.
4.1. Treiber
Es werden mehrere Treiber unterstützt, z. B.DomDriver,StaxDriver,XppDriver und mehr. Diese Treiber weisen unterschiedliche Leistungs- und Ressourcennutzungsmerkmale auf.
Der XPP3-Treiber wird standardmäßig verwendet, aber natürlich können wir den Treiber leicht ändern:
XStream xstream = new XStream(new StaxDriver());
4.2. XML generieren
Beginnen wir mit der Definition eines einfachen POJO für -Customer:
public class Customer {
private String firstName;
private String lastName;
private Date dob;
// standard constructor, setters, and getters
}
Lassen Sie uns nun eine XML-Darstellung des Objekts generieren:
Customer customer = new Customer("John", "Doe", new Date());
String dataXml = xstream.toXML(customer);
Mit den Standardeinstellungen wird die folgende Ausgabe erzeugt:
John
Doe
1986-02-14 03:46:16.381 UTC
An dieser Ausgabe können wir deutlich erkennen, dass das enthaltende Tag standardmäßig den vollständig qualifizierten KlassennamenCustomer. verwendet
Es gibt viele Gründe, warum wir möglicherweise entscheiden, dass das Standardverhalten nicht unseren Anforderungen entspricht. Zum Beispiel ist es möglicherweise nicht einfach, die Paketstruktur unserer Anwendung offenzulegen. Außerdem ist das generierte XML erheblich länger.
5. Aliase
Einalias ist ein Name, den wir für Elemente verwenden möchten, anstatt Standardnamen zu verwenden.
Zum Beispiel können wircom.example.pojo.Customer durchcustomer ersetzen, indem wir einen Alias für die KlasseCustomer registrieren. Wir können auch Aliase für Eigenschaften einer Klasse hinzufügen. Durch die Verwendung von Aliasen können wir unsere XML-Ausgabe viel besser lesbar und weniger Java-spezifisch machen.
5.1. Klasse Aliase
Aliase können entweder programmgesteuert oder mithilfe von Anmerkungen registriert werden.
Kommentieren wir jetzt unsereCustomer-Klasse mit@XStreamAlias:
@XStreamAlias("customer")
Jetzt müssen wir unsere Instanz konfigurieren, um diese Annotation zu verwenden:
xstream.processAnnotations(Customer.class);
Wenn wir einen Alias programmgesteuert konfigurieren möchten, können wir alternativ den folgenden Code verwenden:
xstream.alias("customer", Customer.class);
Unabhängig davon, ob der Alias oder die programmatische Konfiguration verwendet wird, ist die Ausgabe für einCustomer-Objekt viel sauberer:
John
Doe
1986-02-14 03:46:16.381 UTC
5.2. Feld Aliase
Wir können auch Aliase für Felder hinzufügen, die dieselbe Annotation verwenden, die für Aliasing-Klassen verwendet wird. Wenn wir beispielsweise möchten, dass das FeldfirstName in der XML-Darstellung durchfn ersetzt wird, können wir die folgende Anmerkung verwenden:
@XStreamAlias("fn")
private String firstName;
Alternativ können wir das gleiche Ziel programmatisch erreichen:
xstream.aliasField("fn", Customer.class, "firstName");
Die MethodealiasFieldakzeptiert drei Argumente: den Alias, den wir verwenden möchten, die Klasse, in der die Eigenschaft definiert ist, und den Eigenschaftsnamen, den wir als Alias verwenden möchten.
Unabhängig von der verwendeten Methode ist die Ausgabe dieselbe:
John
Doe
1986-02-14 03:46:16.381 UTC
5.3. Standard-Aliase
Es gibt mehrere Aliase, die für Klassen vorregistriert sind - hier einige davon:
alias("float", Float.class);
alias("date", Date.class);
alias("gregorian-calendar", Calendar.class);
alias("url", URL.class);
alias("list", List.class);
alias("locale", Locale.class);
alias("currency", Currency.class);
6. Sammlungen
Jetzt fügen wir eine Liste vonContactDetails innerhalb derCustomer-Klasse hinzu.
private List contactDetailsList;
Mit den Standardeinstellungen für das Sammlungshandling ist dies die Ausgabe:
John
Doe
1986-02-14 04:14:05.874 UTC
6673543265
0124-2460311
4676543565
0120-223312
Nehmen wir an, wir müssen die übergeordneten Tags, voncontactDetailsListweglassen und möchten nur, dass jedesContactDetails-Element ein untergeordnetes Element descustomer-Elements ist. Lassen Sie uns unser Beispiel noch einmal modifizieren:
xstream.addImplicitCollection(Customer.class, "contactDetailsList");
Wenn das XML generiert wird, werden die Root-Tags weggelassen, was zu dem folgenden XML führt:
John
Doe
1986-02-14 04:14:20.541 UTC
6673543265
0124-2460311
4676543565
0120-223312
Dasselbe kann auch mit Anmerkungen erreicht werden:
@XStreamImplicit
private List contactDetailsList;
7. Konverter
XStream verwendet eine Karte der Instanzen vonConvertermit jeweils eigener Konvertierungsstrategie. Diese konvertieren gelieferte Daten in ein bestimmtes Format in XML und wieder zurück.
Zusätzlich zur Verwendung der Standardkonverter können wir die Standardeinstellungen ändern oder benutzerdefinierte Konverter registrieren.
7.1. Ändern eines vorhandenen Konverters
Angenommen, wir waren nicht zufrieden mit der Art und Weise, wie diedob-Tags von XStream (DateConverter) als_ using the default settings. We can modify the custom converter for _Date generiert wurden:
xstream.registerConverter(new DateConverter("dd-MM-yyyy", null));
Das Obige erzeugt die Ausgabe im Format "dd-MM-yyyy":
John
Doe
14-02-1986
7.2. Benutzerdefinierte Konverter
Wir können auch einen benutzerdefinierten Konverter erstellen, um die gleiche Ausgabe wie im vorherigen Abschnitt zu erzielen:
public class MyDateConverter implements Converter {
private SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
@Override
public boolean canConvert(Class clazz) {
return Date.class.isAssignableFrom(clazz);
}
@Override
public void marshal(
Object value, HierarchicalStreamWriter writer, MarshallingContext arg2) {
Date date = (Date)value;
writer.setValue(formatter.format(date));
}
// other methods
}
Schließlich registrieren wir unsereMyDateConverter-Klasse wie folgt:
xstream.registerConverter(new MyDateConverter());
Wir können auch Konverter erstellen, die dieSingleValueConverter-Schnittstelle implementieren, mit der ein Objekt in eine Zeichenfolge konvertiert werden soll.
public class MySingleValueConverter implements SingleValueConverter {
@Override
public boolean canConvert(Class clazz) {
return Customer.class.isAssignableFrom(clazz);
}
@Override
public String toString(Object obj) {
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
Date date = ((Customer) obj).getDob();
return ((Customer) obj).getFirstName() + ","
+ ((Customer) obj).getLastName() + ","
+ formatter.format(date);
}
// other methods
}
Schließlich registrieren wirMySingleValueConverter:
xstream.registerConverter(new MySingleValueConverter());
Unter Verwendung vonMySingleValueConverter lautet die XML-Ausgabe fürCustomer wie folgt:
John,Doe,14-02-1986
7.3. Konverterpriorität
Bei der Registrierung vonConverter Objekten kann auch deren Prioritätsstufe festgelegt werden.
Aus denXStream javadocs:
Die Konverter können mit einer expliziten Priorität registriert werden. Standardmäßig sind sie bei XStream.PRIORITY_NORMAL registriert. Konverter gleicher Priorität werden in der umgekehrten Reihenfolge verwendet, in der sie registriert wurden. Der Standardkonverter, d.h. Der Konverter, der verwendet wird, wenn kein anderer registrierter Konverter geeignet ist, kann mit der Priorität XStream.PRIORITY_VERY_LOW registriert werden. XStream verwendet standardmäßig den ReflectionConverter als Fallback-Konverter.
Die API bietet mehrere benannte Prioritätswerte: **
private static final int PRIORITY_NORMAL = 0;
private static final int PRIORITY_LOW = -10;
private static final int PRIORITY_VERY_LOW = -20;
8. Felder weglassen
Wir können Felder in unserem generierten XML entweder mit Anmerkungen oder programmgesteuerter Konfiguration weglassen. Um ein Feld mit einer Annotation wegzulassen, wenden wir einfach die Annotation@XStreamOmitFieldauf das betreffende Feld an:
@XStreamOmitField
private String firstName;
Um das Feld programmgesteuert auszulassen, verwenden wir die folgende Methode:
xstream.omitField(Customer.class, "firstName");
Unabhängig von der gewählten Methode ist die Ausgabe dieselbe:
Doe
14-02-1986
9. Attributfelder
Manchmal möchten wir ein Feld vielleicht eher als Attribut eines Elements als als Element selbst serialisieren. Angenommen, wir fügen eincontactType-Feld hinzu:
private String contactType;
Wenn wircontactType als XML-Attribut festlegen möchten, können wir die Annotation@XStreamAsAttribute verwenden:
@XStreamAsAttribute
private String contactType;
Alternativ können wir das gleiche Ziel programmatisch erreichen:
xstream.useAttributeFor(ContactDetails.class, "contactType");
Die Ausgabe einer der obigen Methoden ist dieselbe:
6673543265
0124-2460311
10. Parallelität
Das Verarbeitungsmodell von XStream birgt einige Herausforderungen. Sobald die Instanz konfiguriert ist, ist sie threadsicher.
Es ist wichtig zu beachten, dass die Verarbeitung von Anmerkungen die Konfiguration unmittelbar vor dem Zuordnen / Aufheben der Zuordnung ändert. Wenn die Instanz mithilfe von Anmerkungen im laufenden Betrieb konfiguriert werden muss, empfiehlt es sich im Allgemeinen, für jeden Thread eine separateXStream-Instanz zu verwenden.
11. Fazit
In diesem Artikel wurden die Grundlagen der Verwendung von XStream zum Konvertieren von Objekten in XML behandelt. Wir haben auch Informationen zu Anpassungen erhalten, mit denen sichergestellt werden kann, dass die XML-Ausgabe unseren Anforderungen entspricht. Schließlich haben wir uns mit Thread-Sicherheitsproblemen bei Anmerkungen befasst.
Im nächsten Artikel dieser Reihe erfahren Sie, wie Sie XML zurück in Java-Objekte konvertieren.
Der vollständige Quellcode für diesen Artikel kann von den verknüpftenGitHub repository heruntergeladen werden.