読者です 読者をやめる 読者になる 読者になる

HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

Simpleライブラリの検証(1)

Java XML

ざっくりと試してみたSimpleライブラリ。

いろいろと気になる点もあったので、ざくっと検証してみる。

XML宣言と文字エンコーディング

サンプルでは、出力されたXMLファイルにXML宣言が存在しない。そこで気になるのが、文字エンコーディングの扱いはどうなっているのかとか、XML宣言はどうやれば書けるのか、ということ。
そこで、JavaDocを参考にして書いたのが次のコード。

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
import org.simpleframework.xml.stream.Format;

public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {
        System.out.println("=== Serializer#write(T, File) ===");
        try {
            Serializer serializer = new Persister();
            HelloWorld helloWorld = newHelloWorld();

            File result = new File("data/main-1.xml");
            System.out.println("      " + result);
            serializer.write(helloWorld, result);
        } catch (Exception e) {
            e.printStackTrace(System.out);
        }
        System.out.println("=== Serializer#read(Class<? extends T>, File) ===");
        try {
            Serializer serializer = new Persister();
            File source = new File("data/main-1.xml");
            HelloWorld helloWorld = serializer.read(HelloWorld.class, source);
            System.out.println("      " + source);
            dumpHelloWorld(helloWorld);
        } catch (Exception e) {
            e.printStackTrace(System.out);
        }

        String[] encodings = {
            "UTF-8",
            "Shift_JIS",
            "EUC_JP",
            "ISO-2022-JP",
        };
        System.out.println("=== Serializer#write(T, OutputStream, String) ===");
        for (String encoding : encodings) {
            System.out.println("    === " + encoding + " ===");
            try {
                Serializer serializer = new Persister();
                HelloWorld helloWorld = newHelloWorld();
    
                File result = new File("data/main-1-" + encoding + ".xml");
                System.out.println("      " + result);
                serializer.write(helloWorld, new FileOutputStream(result), encoding);
            } catch (Exception e) {
                e.printStackTrace(System.out);
            }
        }
        System.out.println("=== Serializer#write(T, Writer) ===");
        for (String encoding : encodings) {
            System.out.println("    === " + encoding + " ===");
            try {
                Serializer serializer = new Persister();
                HelloWorld helloWorld = newHelloWorld();
    
                File result = new File("data/main-1-2-" + encoding + ".xml");
                System.out.println("      " + result);
                serializer.write(helloWorld, new OutputStreamWriter(new FileOutputStream(result), encoding));
            } catch (Exception e) {
                e.printStackTrace(System.out);
            }
        }
        System.out.println("=== Serializer#write(T, Writer):XML宣言を書いてみる ===");
        for (String encoding : encodings) {
            System.out.println("    === " + encoding + " ===");
            try {
                Serializer serializer = new Persister(new Format("<?xml version='1.0' encoding='" + encoding + "'?>"));
                HelloWorld helloWorld = newHelloWorld();
    
                File result = new File("data/main-1-3-" + encoding + ".xml");
                System.out.println("      " + result);
                serializer.write(helloWorld, new OutputStreamWriter(new FileOutputStream(result), encoding));
            } catch (Exception e) {
                e.printStackTrace(System.out);
            }
        }

        System.out.println("=== Serializer#read(Class<? extends T>, File):XML宣言なし ===");
        for (String encoding : encodings) {
            System.out.println("    === " + encoding + " ===");
            try {
                Serializer serializer = new Persister();
                File source = new File("data/main-1-" + encoding + ".xml");
                System.out.println("      " + source);
                HelloWorld helloWorld = serializer.read(HelloWorld.class, source);
                dumpHelloWorld(helloWorld);
            } catch (Exception e) {
                e.printStackTrace(System.out);
            }
        }
        System.out.println("=== Serializer#read(Class<? extends T>, InputStream, String):XML宣言なし ===");
        for (String encoding : encodings) {
            System.out.println("    === " + encoding + " ===");
            try {
                Serializer serializer = new Persister();
                File source = new File("data/main-1-" + encoding + ".xml");
                System.out.println("      " + source);
                HelloWorld helloWorld = serializer.read(HelloWorld.class, new FileInputStream(source), encoding);
                dumpHelloWorld(helloWorld);
            } catch (Exception e) {
                e.printStackTrace(System.out);
            }
        }
        System.out.println("=== Serializer#read(Class<? extends T>, Reader):XML宣言なし ===");
        for (String encoding : encodings) {
            System.out.println("    === " + encoding + " ===");
            try {
                Serializer serializer = new Persister();
                File source = new File("data/main-1-" + encoding + ".xml");
                System.out.println("      " + source);
                HelloWorld helloWorld = serializer.read(HelloWorld.class, new InputStreamReader(new FileInputStream(source), encoding));
                dumpHelloWorld(helloWorld);
            } catch (Exception e) {
                e.printStackTrace(System.out);
            }
        }
        System.out.println("=== Serializer#read(Class<? extends T>, File):XML宣言あり ===");
        for (String encoding : encodings) {
            System.out.println("    === " + encoding + " ===");
            try {
                Serializer serializer = new Persister();
                File source = new File("data/main-2-" + encoding + ".xml");
                System.out.println("      " + source);
                HelloWorld helloWorld = serializer.read(HelloWorld.class, source);
                dumpHelloWorld(helloWorld);
            } catch (Exception e) {
                e.printStackTrace(System.out);
            }
        }
    }

    private static HelloWorld newHelloWorld() {
        HelloWorld helloWorld = new HelloWorld();
        helloWorld.setJapanese("こんにちは、世界");
        helloWorld.setEnglish("Hello World");
        return helloWorld;
    }
    private static void dumpHelloWorld(HelloWorld helloWorld) {
        System.out.println("        japanese: " + helloWorld.getJapanese());
        System.out.println("        english:  " + helloWorld.getEnglish());
    }
}

HelloWorldクラスは次のようなもの。

import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;

@Root
public class HelloWorld {

    @Element
    private String japanese;

    @Element
    private String english;

    public String getJapanese() {
        return japanese;
    }

    public void setJapanese(String japanese) {
        this.japanese = japanese;
    }

    public String getEnglish() {
        return english;
    }

    public void setEnglish(String english) {
        this.english = english;
    }

}

これを実行すると、次のような出力が得られる。(スタックトレースは長いので一部省略している。)

=== Serializer#write(T, File) ===
      data\main-1.xml
=== Serializer#read(Class<? extends T>, File) ===
      data\main-1.xml
        japanese: こんにちは、世界
        english:  Hello World
=== Serializer#write(T, OutputStream, String) ===
    === UTF-8 ===
      data\main-1-UTF-8.xml
    === Shift_JIS ===
      data\main-1-Shift_JIS.xml
    === EUC_JP ===
      data\main-1-EUC_JP.xml
    === ISO-2022-JP ===
      data\main-1-ISO-2022-JP.xml
=== Serializer#write(T, Writer) ===
    === UTF-8 ===
      data\main-1-2-UTF-8.xml
    === Shift_JIS ===
      data\main-1-2-Shift_JIS.xml
    === EUC_JP ===
      data\main-1-2-EUC_JP.xml
    === ISO-2022-JP ===
      data\main-1-2-ISO-2022-JP.xml
=== Serializer#write(T, Writer):XML宣言を書いてみる ===
    === UTF-8 ===
      data\main-1-3-UTF-8.xml
    === Shift_JIS ===
      data\main-1-3-Shift_JIS.xml
    === EUC_JP ===
      data\main-1-3-EUC_JP.xml
    === ISO-2022-JP ===
      data\main-1-3-ISO-2022-JP.xml
=== Serializer#read(Class<? extends T>, File):XML宣言なし ===
    === UTF-8 ===
      data\main-1-UTF-8.xml
        japanese: こんにちは、世界
        english:  Hello World
    === Shift_JIS ===
      data\main-1-Shift_JIS.xml
javax.xml.stream.XMLStreamException
    at com.bea.xml.stream.MXParser.fillBuf(MXParser.java:3700)
    at com.bea.xml.stream.MXParser.more(MXParser.java:3715)
        :
    === EUC_JP ===
      data\main-1-EUC_JP.xml
javax.xml.stream.XMLStreamException
    at com.bea.xml.stream.MXParser.fillBuf(MXParser.java:3700)
    at com.bea.xml.stream.MXParser.more(MXParser.java:3715)
        :
    === ISO-2022-JP ===
      data\main-1-ISO-2022-JP.xml
javax.xml.stream.XMLStreamException: ParseError at [row,col]:[4,14]
Message: Unexpected end of stream
    at com.bea.xml.stream.MXParser.parseEntityRef(MXParser.java:2889)
    at com.bea.xml.stream.MXParser.nextImpl(MXParser.java:1846)
        :
=== Serializer#read(Class<? extends T>, InputStream, String):XML宣言なし ===
    === UTF-8 ===
      data\main-1-UTF-8.xml
        japanese: こんにちは、世界
        english:  Hello World
    === Shift_JIS ===
      data\main-1-Shift_JIS.xml
        japanese: こんにちは、世界
        english:  Hello World
    === EUC_JP ===
      data\main-1-EUC_JP.xml
        japanese: こんにちは、世界
        english:  Hello World
    === ISO-2022-JP ===
      data\main-1-ISO-2022-JP.xml
        japanese: こんにちは、世界
        english:  Hello World
=== Serializer#read(Class<? extends T>, Reader):XML宣言なし ===
    === UTF-8 ===
      data\main-1-UTF-8.xml
        japanese: こんにちは、世界
        english:  Hello World
    === Shift_JIS ===
      data\main-1-Shift_JIS.xml
        japanese: こんにちは、世界
        english:  Hello World
    === EUC_JP ===
      data\main-1-EUC_JP.xml
        japanese: こんにちは、世界
        english:  Hello World
    === ISO-2022-JP ===
      data\main-1-ISO-2022-JP.xml
        japanese: こんにちは、世界
        english:  Hello World
=== Serializer#read(Class<? extends T>, File):XML宣言あり ===
    === UTF-8 ===
      data\main-2-UTF-8.xml
        japanese: こんにちは、世界
        english:  Hello World
    === Shift_JIS ===
      data\main-2-Shift_JIS.xml
        japanese: こんにちは、世界
        english:  Hello World
    === EUC_JP ===
      data\main-2-EUC_JP.xml
        japanese: こんにちは、世界
        english:  Hello World
    === ISO-2022-JP ===
      data\main-2-ISO-2022-JP.xml
        japanese: こんにちは、世界
        english:  Hello World

文字エンコーディングに関しては、

  • 何も指定しない(つまり、サンプルのように)と、シリアライズもデシリアライズUTF-8を仮定するようだ。
  • Serializerインタフェースのメソッドの一覧を見てもらうとわかるが、InputStream/OutputStreamを指定するメソッドのうち、引数を3つとるメソッドの第3引数には文字エンコーディング名が指定できる。
  • 文字エンコーディングに関して適切な対処をした上でReader/Writerを渡すのもひとつの手段。
  • シリアライズする場合には、適切なXML宣言(encoding指定あり)があればFileやInputStreamを指定しても正しく読める。ただし、(試してはいないが)Readerを指定する場合には、XML宣言が嘘にならないように適切な対処が必要となる。

XML宣言に関しては、

  • Formatオブジェクトを使用してすべて自前で作るしかなさそう。

といったところだろうか。