You are viewing a plain text version of this content. The canonical link for it is here.
Posted to muse-commits@ws.apache.org by da...@apache.org on 2006/06/12 18:04:01 UTC

svn commit: r413690 - in /webservices/muse/trunk/modules/muse-util-xstream: pom.xml src/org/apache/muse/core/serializer/xstream/XStreamSerializer.java

Author: danj
Date: Mon Jun 12 09:04:00 2006
New Revision: 413690

URL: http://svn.apache.org/viewvc?rev=413690&view=rev
Log:
Initial check-in of IBM-donated code for Muse 2.0 - with 
support for Axis2 (re-try after failure due to problem 
with email to muse-commits).

Currently, the modules that are not implementations of the 
WS-* specs - core, utils, WS-A/SOAP, etc. - have working 
Maven 2.0 build files. Right now they simply compile and 
write to the user's local $module/build directory. I have 
not determined how to get Maven to skip this intermediary 
copy and just put the jars in the user's local repository.

I currently use a script to build each module's POM file, 
but as I learn more about Maven I will hopefully find a way 
to aggregate POM files into one larger project. If not, I 
will provide a simple Ant script.

I'm not sure where the design doc should go, and don't 
want to mess with the web site yet, so please look at the 
design-doc.zip that was uploaded to JIRA along with the 
other IBM contributions until I determine the proper place.

Added:
    webservices/muse/trunk/modules/muse-util-xstream/pom.xml
    webservices/muse/trunk/modules/muse-util-xstream/src/org/apache/muse/core/serializer/xstream/XStreamSerializer.java

Added: webservices/muse/trunk/modules/muse-util-xstream/pom.xml
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-util-xstream/pom.xml?rev=413690&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-util-xstream/pom.xml (added)
+++ webservices/muse/trunk/modules/muse-util-xstream/pom.xml Mon Jun 12 09:04:00 2006
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>muse</groupId>
+  <artifactId>muse-util-xstream</artifactId>
+  <packaging>jar</packaging>
+  <version>2.0-SNAPSHOT</version>
+  <name>Apache Muse - XStream Serialization</name>
+  <url>http://ws.apache.org/muse</url>
+  <dependencies>
+    <dependency>
+      <groupId>muse</groupId>
+      <artifactId>muse-core</artifactId>
+      <version>2.0-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>muse</groupId>
+      <artifactId>muse-util</artifactId>
+      <version>2.0-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>muse</groupId>
+      <artifactId>muse-util-qname</artifactId>
+      <version>2.0-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>muse</groupId>
+      <artifactId>muse-util-xml</artifactId>
+      <version>2.0-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>xstream</groupId>
+      <artifactId>xstream</artifactId>
+      <version>1.1.2</version>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <sourceDirectory>src</sourceDirectory>
+    <outputDirectory>build/classes</outputDirectory>
+    <directory>build/jars</directory>
+  </build>
+</project>

Added: webservices/muse/trunk/modules/muse-util-xstream/src/org/apache/muse/core/serializer/xstream/XStreamSerializer.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-util-xstream/src/org/apache/muse/core/serializer/xstream/XStreamSerializer.java?rev=413690&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-util-xstream/src/org/apache/muse/core/serializer/xstream/XStreamSerializer.java (added)
+++ webservices/muse/trunk/modules/muse-util-xstream/src/org/apache/muse/core/serializer/xstream/XStreamSerializer.java Mon Jun 12 09:04:00 2006
@@ -0,0 +1,299 @@
+/*=============================================================================*
+ *  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);
+    }
+    
+    /**
+     * 
+     * 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);
+        }
+    }
+    
+    /**
+     * 
+     * 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.ibm.example.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);
+        }
+    }
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: muse-commits-unsubscribe@ws.apache.org
For additional commands, e-mail: muse-commits-help@ws.apache.org