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

OMElementJavaオブジェクトの変換

S2Axis

Axis2 のサンプルでは、サービスの引数と戻り値にOMElementが使用されています。これによって、ドキュメント・リテラル型(XMLデータを直接やりとりする方式)の通信を実現しています。

OMElement として保持されるXMLデータは、DOMツリーに近い構造を持っていますが、特にスキーマは決まっていないようです。
でも、それって諸刃の剣!?任意のデータをやりとりできるけど、XMLデータをJavaオブジェクトに変換するときに困らないのか?

サービスを呼び出す際に、どこかで 「Javaオブジェクト→OMElement→Javaオブジェクト」という変換が必要になるんだけど、現実私は困ってます・・・
S2で管理するサービスコンポーネントはPOJOにしておきたいので、S2Axis2の内部で上記の変換を行う必要があるのです。


ということで、OMElement<-->Javaオブジェクトの変換が簡単にできないかなぁ、と思ってAxis2のクラスをあさってみました。
すると、おー、それらしきものがあるじゃないですか。

public class BeanUtil {

    public static XMLStreamReader getPullParser(Object beanObject,
                                                QName beanName);

    public static XMLStreamReader getPullParser(Object beanObject);

    public static Object deserialize(Class beanClass,
                                     OMElement beanElement) throws AxisFault;

    public static Object deserialize(Class beanClass,
                                     OMElement beanElement,
                                     MultirefHelper helper) throws AxisFault;

    public static Object deserialize(OMElement response,
                                       Object javaTypes) throws AxisFault;

    public static Object processObject(OMElement omElement,
                                       Class classType,
                                       MultirefHelper helper) throws AxisFault;

    public static OMElement getOMElement(QName opName,
                                         Object[] args,
                                         String partName);
}


このクラスを利用して、OMElement<-->Javaオブジェクトの変換サンプルを作ってみました。OMElement として保持するXMLスキーマは、値とクラスの型が分かれば良いので、勝手に決めてみました(それでいいのか?)。

public class OMElementUtilSample {

    public OMElementUtilSample() {}

    public OMElement createOMElement(Object params) {
        OMFactory fac = OMAbstractFactory.getOMFactory();

        OMNamespace omNs = fac.createOMNamespace("http://sample/services/Service", "Service");
        OMElement om;

        QName qName = new QName("method");
        om = BeanUtil.getOMElement(qName, params, null);
        om.setNamespace(omNs);

        Iterator ite = om.getChildren();
        int index = 0;
        while (ite.hasNext() == true) {
            OMElement arg = (OMElement) ite.next();
            String className = params[index].getClass().getName();
            arg.addAttribute("class", className, null);

            index++;
        }

        return om;
    }

    public Object deserializeOMElement(OMElement om)
            throws ClassNotFoundException, AxisFault {
        List list = new ArrayList();

        Iterator ite = om.getChildren();
        while (ite.hasNext() == true) {
            OMElement arg = (OMElement) ite.next();
            String className = arg.getAttribute(new QName("class")).getAttributeValue();
            Class clazz = Class.forName(className);

            Object value = BeanUtil.deserialize(clazz, arg);

            list.add(value);
        }

        return list.toArray();
    }

    public static void main(String args) {

        Object params = new Object { new String("test"),
                new Integer(1), new Long(2), new Float(0.1), new Double(0.2) };

        OMElementUtilSample sample = new OMElementUtilSample();

        // OMElement の生成
        OMElement om = sample.createOMElement(params);
        System.out.println(om);

        // OMElement のデシアライズ
        try {
            Object paramsResult = sample.deserializeOMElement(om);

            for (int index = 0; index < paramsResult.length; index++) {
                System.out.println("arg" + index + " = " + paramsResult[index]);
            }
        }
        catch (AxisFault ex) {
            ex.printStackTrace();
        }
        catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
    }

}


出力結果は、こんな感じ。


    test
    1
    2
    0.1
    0.2


arg0 = test
arg1 = 1
arg2 = 2
arg3 = 0.1
arg4 = 0.2


プリミティブ型のラッパークラスなら問題なく変換できるようです。試しにListを渡してみたら、NullPointerExceptionが発生してしまいました。