Zoeken…


Invoering

JAXB of Java Architecture for XML Binding (JAXB) is een softwareframework waarmee Java-ontwikkelaars Java-klassen kunnen toewijzen aan XML-representaties. Deze pagina introduceert JAXB-lezers met gedetailleerde voorbeelden over de functies die voornamelijk worden geboden voor het in- en uitladen van Java-objecten in XML-indeling en vice versa.

Syntaxis

  • JAXB.marshall (object, fileObjOfXML);

  • Object obj = JAXB.unmarshall (fileObjOfXML, className);

parameters

Parameter Details
fileObjOfXML File van een XML-bestand
naam van de klasse Naam van een klasse met .class extensie

Opmerkingen

Met behulp van de XJC-tool die beschikbaar is in de JDK, kan java-code voor een xml-structuur die is beschreven in een xml-schema ( .xsd bestand) automatisch worden gegenereerd, zie XJC-onderwerp .

Een XML-bestand schrijven (een object opstellen)

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class User {

    private long userID;
    private String name;
    
    // getters and setters
}

Door de annotatie XMLRootElement , kunnen we een klasse als XMLRootElement van een XML-bestand markeren.

import java.io.File;
import javax.xml.bind.JAXB;

public class XMLCreator {
    public static void main(String[] args) {
        User user = new User();
        user.setName("Jon Skeet");
        user.setUserID(8884321);

        try {
            JAXB.marshal(user, new File("UserDetails.xml"));
        } catch (Exception e) {
            System.err.println("Exception occurred while writing in XML!");
        } finally {
            System.out.println("XML created");
        }
    }
}

marshal() wordt gebruikt om de inhoud van het object in een XML-bestand te schrijven. Hier worden user en een nieuw File object als argumenten doorgegeven aan de marshal() .

Na succesvolle uitvoering creëert dit een XML-bestand met de naam UserDetails.xml in het klassenpad met de onderstaande inhoud.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
    <name>Jon Skeet</name>
    <userID>8884321</userID>
</user>

Een XML-bestand lezen (unmarshalling)

Om een XML-bestand met de naam UserDetails.xml te lezen met de onderstaande inhoud

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
    <name>Jon Skeet</name>
    <userID>8884321</userID>
</user>

We hebben een POJO-klasse nodig met de naam User.java zoals hieronder

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class User {

    private long userID;
    private String name;

    // getters and setters
}

Hier hebben we de variabelen en klassenaam gemaakt op basis van de XML-knooppunten. Om ze in kaart te brengen, gebruiken we de annotatie XmlRootElement voor de klasse.

public class XMLReader {
    public static void main(String[] args) {
        try {
            User user = JAXB.unmarshal(new File("UserDetails.xml"), User.class);
            System.out.println(user.getName());   // prints Jon Skeet
            System.out.println(user.getUserID()); // prints 8884321
        } catch (Exception e) {
            System.err.println("Exception occurred while reading the XML!");
        }
    }
}

Hier unmarshal() methode unmarshal() gebruikt om het XML-bestand te parseren. Het neemt de XML-bestandsnaam en het klassetype als twee argumenten. Vervolgens kunnen we de getter-methoden van het object gebruiken om de gegevens af te drukken.

XmlAdapter gebruiken om het gewenste XML-formaat te genereren

Wanneer het gewenste XML-formaat verschilt van het Java-objectmodel, kan een XmlAdapter-implementatie worden gebruikt om het modelobject om te zetten in een XML-formaatobject en vice versa. Dit voorbeeld laat zien hoe u de waarde van een veld in een attribuut van een element met de naam van het veld plaatst.

public class XmlAdapterExample {

    @XmlAccessorType(XmlAccessType.FIELD)
    public static class NodeValueElement {
          
        @XmlAttribute(name="attrValue")
        String value;
    
        public NodeValueElement() {
        }
    
        public NodeValueElement(String value) {
            super();
            this.value = value;
        }
    
        public String getValue() {
            return value;
        }
    
        public void setValue(String value) {
            this.value = value;
        }
    }

    public static class ValueAsAttrXmlAdapter extends XmlAdapter<NodeValueElement, String> {        
        @Override
        public NodeValueElement marshal(String v) throws Exception {
            return new NodeValueElement(v);
        }
        
        @Override
        public String unmarshal(NodeValueElement v) throws Exception {
            if (v==null) return "";
            return v.getValue();
        }
    }

    @XmlRootElement(name="DataObject")
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class DataObject {
        
        String elementWithValue;

        @XmlJavaTypeAdapter(value=ValueAsAttrXmlAdapter.class)
        String elementWithAttribute;
    }

    public static void main(String[] args) {
        DataObject data = new DataObject();
        data.elementWithValue="value1";
        data.elementWithAttribute ="value2";
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        JAXB.marshal(data, baos);

        String xmlString = new String(baos.toByteArray(), StandardCharsets.UTF_8);
        
        System.out.println(xmlString);
    }
}

Automatische configuratie van veld / eigenschap XML-toewijzing (@XmlAccessorType)

Annotatie @XmlAccessorType bepaalt of velden / eigenschappen automatisch worden geserialiseerd naar XML. Merk op dat veld- en methode-annotaties @XmlElement , @XmlAttribute of @XmlTransient voorrang hebben op de standaardinstellingen.

public class XmlAccessTypeExample {

@XmlAccessorType(XmlAccessType.FIELD)
static class AccessorExampleField {
    public String field="value1";
    
    public String getGetter() {
        return "getter";
    }
    
    public void setGetter(String value) {}
}

@XmlAccessorType(XmlAccessType.NONE)
static class AccessorExampleNone {
    public String field="value1";
    
    public String getGetter() {
        return "getter";
    }
    
    public void setGetter(String value) {}
}

@XmlAccessorType(XmlAccessType.PROPERTY)
static class AccessorExampleProperty {
    public String field="value1";
    
    public String getGetter() {
        return "getter";
    }
    
    public void setGetter(String value) {}
}

@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
static class AccessorExamplePublic {
    public String field="value1";
    
    public String getGetter() {
        return "getter";
    }
    
    public void setGetter(String value) {}
}

public static void main(String[] args) {
    try {
        System.out.println("\nField:");
        JAXB.marshal(new AccessorExampleField(), System.out);
        System.out.println("\nNone:");
        JAXB.marshal(new AccessorExampleNone(), System.out);
        System.out.println("\nProperty:");
        JAXB.marshal(new AccessorExampleProperty(), System.out);
        System.out.println("\nPublic:");
        JAXB.marshal(new AccessorExamplePublic(), System.out);
    } catch (Exception e) {
        System.err.println("Exception occurred while writing in XML!");
    }
}

} // outer class end

uitgang

Field:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleField>
    <field>value1</field>
</accessorExampleField>

None:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleNone/>

Property:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleProperty>
    <getter>getter</getter>
</accessorExampleProperty>

Public:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExamplePublic>
    <field>value1</field>
    <getter>getter</getter>
</accessorExamplePublic>

Handmatige veld / eigenschap XML mapping configuratie

Met annotaties @XmlElement , @XmlAttribute of @XmlTransient en andere in pakket javax.xml.bind.annotation kan de programmeur opgeven welke en hoe gemarkeerde velden of eigenschappen moeten worden geserialiseerd.

@XmlAccessorType(XmlAccessType.NONE) // we want no automatic field/property marshalling
public class ManualXmlElementsExample {
    
    @XmlElement
    private String field="field value";

    @XmlAttribute
    private String attribute="attr value";
    
    @XmlAttribute(name="differentAttribute")
    private String oneAttribute="other attr value";
    
    @XmlElement(name="different name")
    private String oneName="different name value";
    
    @XmlTransient
    private String transientField = "will not get serialized ever";
    
    
    @XmlElement
    public String getModifiedTransientValue() {
        return transientField.replace(" ever", ", unless in a getter");
    }
    
    public void setModifiedTransientValue(String val) {} // empty on purpose


    public static void main(String[] args) {
        try {
            JAXB.marshal(new ManualXmlElementsExample(), System.out);
        } catch (Exception e) {
            System.err.println("Exception occurred while writing in XML!");
        }
    }
}

Een XmlAdapter-instantie opgeven om bestaande gegevens te (her) gebruiken

Soms moeten specifieke instanties van gegevens worden gebruikt. Recreatie is niet gewenst en het verwijzen naar static gegevens zou een codegeur hebben.

Het is mogelijk om een XmlAdapter instantie te specificeren die de Unmarshaller moet gebruiken, waarmee de gebruiker XmlAdapter s kan gebruiken zonder nul-arg constructor en / of gegevens doorgeeft aan de adapter.

Voorbeeld

Gebruikersklasse

De volgende klasse bevat een naam en een gebruikersafbeelding.

import java.awt.image.BufferedImage;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
public class User {
    
    private String name;
    private BufferedImage image;

    @XmlAttribute
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @XmlJavaTypeAdapter(value=ImageCacheAdapter.class)
    @XmlAttribute
    public BufferedImage getImage() {
        return image;
    }

    public void setImage(BufferedImage image) {
        this.image = image;
    }

    public User(String name, BufferedImage image) {
        this.name = name;
        this.image = image;
    }

    public User() {
        this("", null);
    }

}

Adapter

Om te voorkomen dat twee keer dezelfde afbeelding in het geheugen wordt gemaakt (en de gegevens opnieuw worden gedownload), slaat de adapter de afbeeldingen op in een kaart.

Java SE 7

Voor geldige Java 7-code vervangt u de methode getImage door

public BufferedImage getImage(URL url) {
    BufferedImage image = imageCache.get(url);
    if (image == null) {
        try {
            image = ImageIO.read(url);
        } catch (IOException ex) {
            Logger.getLogger(ImageCacheAdapter.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
        imageCache.put(url, image);
        reverseIndex.put(image, url);
    }
    return image;
}
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class ImageCacheAdapter extends XmlAdapter<String, BufferedImage> {

    private final Map<URL, BufferedImage> imageCache = new HashMap<>();
    private final Map<BufferedImage, URL> reverseIndex = new HashMap<>();

    public BufferedImage getImage(URL url) {
        // using a single lookup using Java 8 methods
        return imageCache.computeIfAbsent(url, s -> {
            try {
                BufferedImage img = ImageIO.read(s);
                reverseIndex.put(img, s);
                return img;
            } catch (IOException ex) {
                Logger.getLogger(ImageCacheAdapter.class.getName()).log(Level.SEVERE, null, ex);
                return null;
            }
        });
    }

    @Override
    public BufferedImage unmarshal(String v) throws Exception {
        return getImage(new URL(v));
    }

    @Override
    public String marshal(BufferedImage v) throws Exception {
        return reverseIndex.get(v).toExternalForm();
    }

}

Voorbeeld XML's

De volgende 2 xmls zijn voor Jon Skeet en zijn earth 2-tegenhanger, die beide er precies hetzelfde uitzien en daarom dezelfde avatar gebruiken.

<?xml version="1.0" encoding="UTF-8"?>

<user name="Jon Skeet" image="https://www.gravatar.com/avatar/6d8ebb117e8d83d74ea95fbdd0f87e13?s=328&amp;d=identicon&amp;r=PG"/>
<?xml version="1.0" encoding="UTF-8"?>

<user name="Jon Skeet (Earth 2)" image="https://www.gravatar.com/avatar/6d8ebb117e8d83d74ea95fbdd0f87e13?s=328&amp;d=identicon&amp;r=PG"/>

De adapter gebruiken

ImageCacheAdapter adapter = new ImageCacheAdapter();

JAXBContext context = JAXBContext.newInstance(User.class);

Unmarshaller unmarshaller = context.createUnmarshaller();

// specifiy the adapter instance to use for every
// @XmlJavaTypeAdapter(value=ImageCacheAdapter.class)
unmarshaller.setAdapter(ImageCacheAdapter.class, adapter);

User result1 = (User) unmarshaller.unmarshal(Main.class.getResource("user.xml"));

// unmarshal second xml using the same adapter instance
Unmarshaller unmarshaller2 = context.createUnmarshaller();
unmarshaller2.setAdapter(ImageCacheAdapter.class, adapter);
User result2 = (User) unmarshaller2.unmarshal(Main.class.getResource("user2.xml"));

System.out.println(result1.getName());
System.out.println(result2.getName());

// yields true, since image is reused
System.out.println(result1.getImage() == result2.getImage());

Een XML-naamruimte binden aan een serialiseerbare Java-klasse.

Dit is een voorbeeld van een package-info.java bestand dat een XML-naamruimte bindt aan een serialiseerbare Java-klasse. Dit moet in hetzelfde pakket worden geplaatst als de Java-klassen die moeten worden geserialiseerd met behulp van de naamruimte.

/**
 * A package containing serializable classes.
 */
@XmlSchema
(
    xmlns =
    {
        @XmlNs(prefix = MySerializableClass.NAMESPACE_PREFIX, namespaceURI = MySerializableClass.NAMESPACE)
    },
    namespace = MySerializableClass.NAMESPACE,
    elementFormDefault = XmlNsForm.QUALIFIED
)
package com.test.jaxb;

import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

XmlAdapter gebruiken om tekenreeks bij te knippen.

package com.example.xml.adapters;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class StringTrimAdapter extends XmlAdapter<String, String> {
    @Override
    public String unmarshal(String v) throws Exception {
        if (v == null)
            return null;
        return v.trim();
    }

    @Override
    public String marshal(String v) throws Exception {
        if (v == null)
            return null;
        return v.trim();
    }
}

En voeg in pakket-info.java de volgende verklaring toe.

@XmlJavaTypeAdapter(value = com.example.xml.adapters.StringTrimAdapter.class, type = String.class)
package com.example.xml.jaxb.bindings;// Packge where you intend to apply trimming filter

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow