Package org.apache.muse.core.serializer.xstream

Source Code of org.apache.muse.core.serializer.xstream.XStreamSerializer$MuseSerializerXStream

/*=============================================================================*
*  Copyright 2006 The Apache Software Foundation
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*=============================================================================*/

package org.apache.muse.core.serializer.xstream;

import javax.xml.namespace.QName;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import org.apache.muse.core.serializer.Serializer;
import org.apache.muse.util.ReflectUtils;
import org.apache.muse.util.xml.XmlUtils;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.alias.ClassMapper;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.DomReader;
import com.thoughtworks.xstream.io.xml.DomWriter;
import com.thoughtworks.xstream.mapper.MapperWrapper;

/**
*
* XStreamSerializer is a generic Serializer that relies on the XStream
* library to serialize and deserialize objects to/from XML without any
* configuration files or schemas. To use this class within Muse
* applications, simply sub-class it an override the getSerializableType()
* method to return the class or interface that is being serialized. That's it!
* <br><br>
* This serializer has some additional code that helps XStream create "pure"
* XML by adding better support for XML namespaces and prefixes, as well as
* being more flexible in the Java field name conventions that can be read
* and converted into proper XML element names.
* <br><br>
* For more information about how XStream serializes your objects, and to get
* the JAR file needed to execute this code, please visit XStream's web site:
* <br><br>
* <a href="http://xstream.codehaus.org">http://xstream.codehaus.org</a>
*
* @author Dan Jemiolo (danj)
*
* @see org.apache.muse.core.serializer.Serializer
*
*/

public abstract class XStreamSerializer implements Serializer
{    
    //
    // The XStream facade that aggregates all of the core XStream features.
    // Note we initialize XStream with the DOM driver so that sub-classes
    // that use the XStream.toXML and XStream.fromXML convenience methods
    // will not have to configure this themselves (the default driver is
    // XML Pull Parser, which we do not wish to include for legal reasons).
    //
    // This version of the XStream facade is an extension that calls
    // on this Serializer class to get the name/type that is being
    // serialized. This, in combination with some prefix/namespace support
    // code, allows us to generate "pure" XML that has no Java connotations.
    //
    private XStream _xstream = new MuseSerializerXStream();
   
    /**
     *
     * This method takes the non-namespace-aware DOM (DOM Level 1) that
     * is generated by XStream and converts it into an equivalent DOM
     * tree with the proper namespaces and prefixes. The namespace and
     * prefix values should be taken from the QName that is provided to
     * the Serializer.toXML() method.
     *
     */
    protected Element copySubTree(Element[] children,
                                  Element root,
                                  String namespace,
                                  String prefix)
    {
        Document doc = root.getOwnerDocument();
       
        for (int n = 0; n < children.length; ++n)
        {
            //
            // create a QName using the user's URI/prefix and the
            // local name created by XStream
            //
            QName qname = new QName(namespace, children[n].getLocalName(), prefix);
           
            //
            // now copy over the text and sub-child elements
            //
           
            Element childCopy = XmlUtils.createElement(doc, qname);
            root.appendChild(childCopy);
           
            String text = XmlUtils.extractText(children[n]);
           
            if (text != null)
                XmlUtils.setElementText(childCopy, text);
           
            Element[] subChildren = XmlUtils.getAllElements(children[n]);
            copySubTree(subChildren, childCopy, namespace, prefix);
        }
       
        return root;
    }
   
    /**
     *
     * @return A POJO representation of the given XML fragment.
     *
     */
    public Object fromXML(Element xml)
    {
        return getXStream().unmarshal(new DomReader(xml));
    }
   
    /**
     *
     * @return The XStream API, initialized with the DOM parser/driver.
     *
     */
    public final XStream getXStream()
    {
        return _xstream;
    }
   
    /**
     *
     * @return The XML representation of the object, with the root element
     *         having the given QName.
     *
     */
    public Element toXML(Object result, QName qname)
    {
        Document doc = XmlUtils.createDocument();
       
        //
        // use marshal rather than toXML so we can serialize the object
        // directly to DOM (toXML returns a string of XML)
        //
        getXStream().marshal(result, new DomWriter(doc));
       
        //
        // XStream creates DOM Level 1 - argh! we need qualified names
        // to be schema-compliant, so we have to copy the whole DOM tree
        // in a Level 2 way. DOM (both levels) does not permit the
        // changing of the name(space) of nodes after their creation.
        //
        Element root = XmlUtils.getFirstElement(doc);
        Element[] children = XmlUtils.getAllElements(root);

        String namespace = qname.getNamespaceURI();
        String prefix = qname.getPrefix();
        Element qualifiedRoot = XmlUtils.createElement(doc, qname);
       
        return copySubTree(children, qualifiedRoot, namespace, prefix);
    }
   
    /**
     *
     * JavaFieldConverter is a pluggable XStream component that allows us
     * more control over the naming conventions XStream uses/accepts when
     * serializing and deserializing XML. We use this component to achieve
     * two goals:
     * <ol>
     * <li>Tolerate namespaces and prefixes in XML elements when XStream
     * is deserializing XML into POJOs. Normally, it would balk at the
     * prefixed-name of the element because it doesn't match the field
     * name or any of its aliases.
     * </li>
     * <br>
     * <li>Tolerate Java field naming conventions - camel casing (first
     * letter lowercase) and underscore prefixes. We drop underscore prefixes
     * from the name and convert the first letter to uppercase before using
     * the name to create an XML element. This makes it impossible to tell
     * that the XML came from a Java class.
     * </li>
     * <br>
     * </ol>
     *
     * @author Dan Jemiolo (danj)
     *
     */
    private class JavaFieldConverter extends MapperWrapper
    {
        public JavaFieldConverter(ClassMapper wrapper)
        {
            super(wrapper);
        }
       
        /**
         *
         * This method returns Serializer.getSerializableType(). Because
         * each XStreamSerializer-based serializer will have its own
         * instance of XStream, we can assume it is serializing this type.
         *
         */
        public Class realClass(String className)
        {
            return getSerializableType();
        }
       
        /**
         *
         * This method converts the XML element name to the Java field name.
         *
         */
        public String realMember(Class theClass, String elementName)
        {
            //
            // strip prefix from DOM element name
            //
            int colonIndex = elementName.indexOf(':');
           
            if (colonIndex >= 0)
                elementName = elementName.substring(colonIndex + 1);
           
            //
            // make two options - just camel case, or camel case with an
            // underscore prefix. try 'em both
            //
            String withLowerCase = Character.toLowerCase(elementName.charAt(0)) + elementName.substring(1);
            String withPrefix = '_' + withLowerCase;
           
            try
            {
                theClass.getDeclaredField(withPrefix);
                return withPrefix; // has the underscore - return it!
            }
           
            catch (NoSuchFieldException error)
            {
                //
                // no underscore - return regular name
                //
                return withLowerCase;
            }
        }
       
        /**
         *
         * This method returns the unqualified (no package) name of the
         * Java class (com.example.myapp.MyClass becomes "MyClass").
         *
         */
        public String serializedClass(Class theClass)
        {
            return ReflectUtils.getShortName(theClass);
        }
       
        /**
         *
         * This method strips an camel casing or underscore prefix from
         * the given field name so it can be used as an XML element name.
         *
         */
        public String serializedMember(Class theClass, String fieldName)
        {
            if (fieldName.charAt(0) == '_')
                fieldName = fieldName.substring(1);
           
            fieldName = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
           
            return super.serializedMember(theClass, fieldName);
        }
    }
   
    /**
     *
     * MuseSerializerXStream is a version of XStream that uses our
     * JavaFieldConverter class to map Java field names to XML elements.
     *
     * @author Dan Jemiolo (danj)
     *
     */
    private class MuseSerializerXStream extends XStream
    {
        public MuseSerializerXStream()
        {
            super(new DomDriver());
        }
       
        protected MapperWrapper wrapMapper(MapperWrapper next)
        {
            return new JavaFieldConverter(next);
        }
    }
}
TOP

Related Classes of org.apache.muse.core.serializer.xstream.XStreamSerializer$MuseSerializerXStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.