XStream-Benutzerhandbuch: Objekte in XML konvertieren

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.

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.