サーチ…


前書き

JAXBまたはJAXB( Java Architecture for XML Binding )は、Java開発者がJavaクラスをXML表現にマップできるソフトウェアフレームワークです。このページでは、JAXBの読者を、主にJavaオブジェクトをXMLフォーマットにマーシャリングおよび非マーシャリングするために提供されるその機能に関する詳細な例を使用して紹介します。

構文

  • JAXB.marshall(object、fileObjOfXML);

  • オブジェクトobj = JAXB.unmarshall(fileObjOfXML、className);

パラメーター

パラメータ詳細
fileObjOfXML XMLファイルのFileオブジェクト
クラス名 .class拡張子を持つクラスの名前

備考

JDKで利用可能なXJCツールを使用すると、XMLスキーマ( .xsdファイル)で記述されたXML構造のJavaコードが自動的に生成されます( XJCトピックを参照)。

XMLファイルを作成する(オブジェクトをマーシャリングする)

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class User {

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

アノテーションXMLRootElementを使用することにより、クラスをXMLファイルのルート要素としてマークできます。

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()は、オブジェクトのコンテンツをXMLファイルに書き込むために使用されます。ここでは、 userオブジェクトと新しいFileオブジェクトが引数としてmarshal()渡されます。

実行が成功すると、class-pathに以下の内容のUserDetails.xmlという名前のXMLファイルが作成されます。

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

XMLファイルの読み込み(アンマーシャリング)

以下の内容のUserDetails.xmlという名前のXMLファイルを読み込むには

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

以下のように、 User.javaという名前のPOJOクラスが必要User.java

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class User {

    private long userID;
    private String name;

    // getters and setters
}

ここでは、XMLノードに従って変数とクラス名を作成しました。それらをマップするために、私たちはクラスの注釈XmlRootElementを使用します。

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!");
        }
    }
}

unmarshal()メソッドは、XMLファイルの解析に使用されます。 2つの引数としてXMLファイル名とクラス型を取ります。次に、オブジェクトのゲッターメソッドを使用してデータを印刷することができます。

XmlAdapterを使用して目的のxml形式を生成する

必要なXMLフォーマットがJavaオブジェクトモデルと異なる場合、XmlAdapter実装を使用してモデルオブジェクトをxmlフォーマットオブジェクトに変換することができます。この例は、フィールドの名前を持つ要素の属性にフィールドの値を配置する方法を示しています。

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);
    }
}

自動フィールド/プロパティーXMLマッピング構成(@XmlAccessorType)

注釈@XmlAccessorTypeは、フィールド/プロパティをXMLに自動的にシリアル化するかどうかを決定します。 @XmlElement@XmlAttribute @XmlElement 、または@XmlTransientフィールドとメソッド注釈は、デフォルト設定よりも優先されることに注意してください。

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

出力

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>

手動フィールド/プロパティXMLマッピング設定

注釈@XmlElement@XmlAttributeまたは@XmlTransient 、パッケージ内の他のjavax.xml.bind.annotationプログラマがシリアライズされるべきであるとどのようにマークされたフィールドまたはプロパティを指定することができます。

@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!");
        }
    }
}

既存のデータを(再)使用するためのXmlAdapterインスタンスの指定

場合によっては、データの特定のインスタンスを使用する必要があります。レクリエーションは望ましくなく、 staticデータの参照にはコードの臭いがあります。

Unmarshallerが使用する必要があるXmlAdapterインスタンスを指定することができます。これにより、ユーザーはゼロ引数のコンストラクタを持たないXmlAdapterを使用したり、アダプタにデータを渡したりすることができます。

ユーザークラス

次のクラスには、名前とユーザーの画像が含まれます。

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);
    }

}

アダプタ

メモリー内に同じイメージを2回作成するのを避けるために(そしてデータをもう一度ダウンロードするだけでなく)、アダプターはイメージをマップに保管します。

Java SE 7

有効なJava 7コードの場合は、 getImageメソッドを

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();
    }

}

XMLの例

次の2つのXMLは、 Jon SkeetとEarth 2に対応しています。どちらも同じように見えるため、同じアバターを使用します。

<?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"/>

アダプタの使用

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());

XML名前空間を直列化可能なJavaクラスにバインドする。

これは、XML名前空間を直列化可能なJavaクラスにバインドするpackage-info.javaファイルの例です。これは、ネームスペースを使用してシリアライズする必要があるJavaクラスと同じパッケージに配置する必要があります。

/**
 * 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を使用して文字列をトリミングする

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();
    }
}

そして、package-info.javaに次の宣言を追加します。

@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
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow