自作DI①

SpringやCDIで提供されるDIの仕組だが、いろいろ原理主義的で扱いにくいところがあるため、やりやすいようにDIを自作してみる。
最終形として
アノテーションベース
XMLの設定ファイルでインジェクションするクラスを指定
を想定して作っていこうと思っている。

DIの仕組を考える前に、今日は設定ファイルに使おうと思っているXMLJavaからの扱い方を復習してみたい。
有名どころのDOMのライブラリにて、かつてハマったところも鑑みて使い方をみていく。

test.xml

<?xml version="1.0" encoding="UTF-8"?>
<factor1>
  <factor2>
    <factor3>value3</factor3>
    <factor4>value4</factor4>
  </factor2>
</factor1>

このxmlファイルをパースしてDocumentクラスのインスタンスに展開。

package xmltest;

import java.io.File;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;

public class XmlTest {
    public static void main(String args[]){
        try{
            Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().
                parse(new File("C:\\test.xml"));
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

XMLドキュメントの根幹であるDocumentのインスタンスは、内部でDOMツリーの構造を成している。
ドキュメント内の各要素をNodeとして取り出すことが出来、子要素は各NodeからNodeとして取り出すことが出来る。
複数Nodeを取り出す際にはNodeList型というのもある。ちなみにIterableではない。
Nodeを辿って目的の子ノードを探すことも出来るが、getElementsByTagNameで特定のtag名を持つNodeを再帰的に取ってくることも出来る。

ちょっとハマるのが、タグだけでなくタグ外のテキストもNodeとして扱われることだ。test.xmlの例で言えば、factor2からgetChildNodes()でNodeListを取得した場合、中のNodeは
・factor2の後ろの改行コード+インデント
・factor3
・factor3の後ろの改行コード+インデント
・factor4
・factor4の後ろの改行コード+インデント
の5つになる。なので無考慮にgetFirstChild()で最初のタグを処理しようとすると失敗する。かと言ってtext上タグを完全に隣接させれば最初のNodeがタグになるため、2番目のNodeを最初のタグとすることも出来ない。
NodeNameを確認して処理するなど、きちんとチェックを行うことが必要になる。

package xmltest;

import java.io.File;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XmlTest {
    public static void main(String args[]){
        try{
            Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().
                parse(new File("C:\\test.xml"));
            Node nodeTest1 = doc.getFirstChild();
            System.out.println("--test1---");
            System.out.print("name:" + nodeTest1.getNodeName());
            System.out.print(",type:" + nodeTest1.getNodeType());
            System.out.println(",value:" + nodeTest1.getNodeValue());
            System.out.println("----------");

            Node nodeTest2 = doc.getFirstChild().getChildNodes().item(0);
            System.out.println("--test2---");
            System.out.print("name:" + nodeTest2.getNodeName());
            System.out.print(",type:" + nodeTest2.getNodeType());
            System.out.println(",value:" + nodeTest2.getNodeValue());
            System.out.println("----------");

            NodeList parentNl = doc.getElementsByTagName("factor2");
            NodeList childNl = parentNl.item(0).getChildNodes();
            System.out.println("--test3---");
            for(int i = 0;i < childNl.getLength();i++){
            	Node nodeTest3 = childNl.item(i);
            	System.out.print("name:" + nodeTest3.getNodeName());
            	System.out.print(",type:" + nodeTest3.getNodeType());
            	System.out.println(",value:" + nodeTest3.getNodeValue());
            }
            System.out.println("----------");
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

実行結果

--test1---
name:factor1,type:1,value:null
----------
--test2---
name:#text,type:3,value:
  
----------
--test3---
name:#text,type:3,value:
    
name:factor3,type:1,value:null
name:#text,type:3,value:
    
name:factor4,type:1,value:null
name:#text,type:3,value:
  
----------