Thanks Scott. Here's my contribution:

I made these changes to Apache SOAP 2.3.1 in response to a TestMaker user that hit an interoperability problem when working with java.util.Calendar types in a complex object. When the BeanSerializer operated on the complex object it emits an XML element:

<memoCalendar xlmns:ns3="http://java.util"; xmi:type="ns3:Calendar">2004-03-16T-06:12:23:218Z</memoCalendar>

If this were .NET or Apache Axis the marshalled request element would look like this:

<memoCalendar xsi:type="xsd:dateTime">2004-03-16T-06:12:23:218Z</memoCalendar>

The customer's Web Service application responded with a SOAP exception saying it could not deserialize a java.util.Calendar type. The customer is not in control of the complex object (it came in a prepackaged signed jar file.)

Attached are three modified files:

DateSerializer.java - I modified this to accept java.util.Date and java.util.Calendar objects. Previously it only accepted java.util.Calendar.

CalendarSerializer.java - I modified this to accept java.util.Calendar and java.util.GregorianCalendar objects. Previously it only accepted java.util.GregorianCalendar.

SoapEngUtils.java - I modified this to look for java.util.Calendar types and if so it forces the use of a QName object with "http://www.w3.org/2001/XMLSchema"; and a value of "dateTime".

These changes are a hack to get my customer's application to work. I would prefer to work with someone on the Apace SOAP team to design a better solution.

I don't like the idea of having branches so perhaps there is a way to work together to get this improvement redesigned and part of Apache SOAP. I'm open to your ideas.

-Frank


/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000 The Apache Software Foundation.  All rights 
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:  
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "SOAP" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written 
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 2000, International
 * Business Machines, Inc., http://www.apache.org.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

package org.apache.soap.encoding.soapenc;

import org.apache.soap.util.xml.*;
import org.apache.soap.util.*;
import org.apache.soap.rpc.SOAPContext;
import java.io.*;
import org.w3c.dom.*;
import java.io.*;
import java.util.*;
import java.text.*;

/**
*
* This class de/serializes instances of java.util.Date from/to
* the XML-Schema type 'timeInstant'. For details see the
* <A HREF="http://www.w3.org/TR/xmlschema-2/#timeInstant";>XML-Schema specification</A>
*
* @author Phil Mork
* @author Glen Daniels ([EMAIL PROTECTED])
* @author Matthew J. Duftler ([EMAIL PROTECTED])
* @author Sam Ruby ([EMAIL PROTECTED])
* @see Serializer
* @see Deserializer
*/
public class DateSerializer implements Serializer, Deserializer
{
  SimpleDateFormat sdf;

  public DateSerializer()
  {
    sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                            //  0123456789 0 123456789
    sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
  }

  public void marshall(String inScopeEncStyle, Class javaType, Object src,
                       Object context, Writer sink, NSStack nsStack,
                       XMLJavaMappingRegistry xjmr, SOAPContext ctx)
                        throws IllegalArgumentException, IOException
  {
    
    /* [EMAIL PROTECTED] March 15, 2004: Changed to allow this serializer to
       marshal java.util.Calendar object types too. 
    */
    Date calDate = null;
      
    if( javaType.equals(java.util.Date.class))
    {
        calDate = new Date( ((Date)src).getTime() );
    }

    if( javaType.equals(java.util.Calendar.class))
    {
        calDate = ((Calendar)src).getTime();
    }
      
    if ( calDate == null )
      throw new IllegalArgumentException("Can only serialize java.util.Date or 
java.util.Calendar instances");
    
    nsStack.pushScope();
    if(src!=null)
    {
        
      /* [EMAIL PROTECTED] March 16,2004: Change the 2nd param below to use dateTime 
always. This
         is to force interoperability for Cricket Communications' Web Service 
application. I do not
         recommend this for anyone else.
      */
        
      SoapEncUtils.generateStructureHeader(inScopeEncStyle,
                                           javaType,
                                           context,
                                           sink,
                                           nsStack,
                                           xjmr,
                                           ctx);

      String fdate=null;

      synchronized(sdf)
      {
        fdate=sdf.format( calDate );
      }

      sink.write(fdate);
      sink.write("</" + context + '>');
    }
    else
    {
      SoapEncUtils.generateNullStructure(inScopeEncStyle,
                                           javaType,
                                           context,
                                           sink,
                                           nsStack,
                                           xjmr,
                                           ctx);
    }
    nsStack.popScope();
  }

  public Bean unmarshall(String inScopeEncStyle, QName elementType, Node src,
                         XMLJavaMappingRegistry xjmr, SOAPContext ctx)
                          throws IllegalArgumentException
  {
    Date date=null;
    Element root = (Element)src;
    String value = DOMUtils.getChildCharacterData(root);
    if(value!=null && !((value=value.trim()).equals("")))
    {
      try
      {
        synchronized(sdf)
        {
          date=sdf.parse(value);
        }
      }
      catch (ParseException pe)
      {
        try
        {
          // validate fixed portion of format
          if (value.length() < 19) 
            throw new ParseException("",0);

          if (value.charAt(4) != '-' || value.charAt(7) != '-' ||
              value.charAt(10) != 'T')
            throw new ParseException("",0);

          if (value.charAt(13) != ':' || value.charAt(16) != ':')
            throw new ParseException("",0);

          // convert what we have validated so far
          try
          {
            synchronized(sdf)
            {
              date=sdf.parse(value.substring(0,19)+".000Z"); 
            }
          }
          catch (Exception e)
          {
            throw new ParseException("",0);
          }

          int pos = 19;

          // parse optional milliseconds
          if (pos < value.length() && value.charAt(pos)=='.') {
            int milliseconds = 0;
            int start = ++pos;
            while (pos<value.length() && Character.isDigit(value.charAt(pos)))
              pos++;

            String decimal=value.substring(start,pos);
            if (decimal.length()==3) {
              milliseconds=Integer.parseInt(decimal);
            } else if (decimal.length() < 3) {
              milliseconds=Integer.parseInt((decimal+"000").substring(0,3));
            } else {
              milliseconds=Integer.parseInt(decimal.substring(0,3));
              if (decimal.charAt(3)>='5') ++milliseconds;
            }

            // add milliseconds to the current result
            date.setTime(date.getTime()+milliseconds);
          }

          // parse optional timezone
          if (pos+5 < value.length() &&
               (value.charAt(pos)=='+' || (value.charAt(pos)=='-')))
          {
            if (!Character.isDigit(value.charAt(pos+1)) || 
                !Character.isDigit(value.charAt(pos+2)) || 
                value.charAt(pos+3) != ':'              || 
                !Character.isDigit(value.charAt(pos+4)) || 
                !Character.isDigit(value.charAt(pos+5)))
               throw new ParseException("",0);

            int hours = (value.charAt(pos+1)-'0')*10+value.charAt(pos+2)-'0';
            int mins  = (value.charAt(pos+4)-'0')*10+value.charAt(pos+5)-'0';
            int milliseconds = (hours*60+mins)*60*1000;

            // subtract milliseconds from the current date to obtain GMT
            if (value.charAt(pos)=='+') milliseconds=-milliseconds;
            date.setTime(date.getTime()+milliseconds);
            pos+=6;  
          }

          if (pos < value.length() && value.charAt(pos)=='Z') pos++;

          if (pos < value.length())
            throw new ParseException("",0);
        }
        catch (ParseException pe2)
        {
          synchronized(sdf)
          {
            throw new IllegalArgumentException("String represents no valid " +
                                             "Date for this Deserializer; " +
                                             "try " + sdf.toPattern() + ".");
          }
        }
      }
    }
    return new Bean(java.util.Date.class,date);
  }
}
/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000 The Apache Software Foundation.  All rights 
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:  
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "SOAP" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written 
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 2000, International
 * Business Machines, Inc., http://www.apache.org.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
* Initial revision - based on code from Apache serializer classes
*/

package org.apache.soap.encoding.soapenc;

import org.apache.soap.util.xml.*;
import org.apache.soap.util.*;
import org.apache.soap.encoding.soapenc.SoapEncUtils;
import org.apache.soap.rpc.SOAPContext;
import java.io.*;
import org.w3c.dom.*;
import java.io.*;
import java.util.*;
import java.text.*;

/**
*
* This class de/serializes instances of java.util.GregorianCalendar from/to
* the XML-Schema type 'date'. For details see the
* <A HREF="http://www.w3.org/TR/xmlschema-2/#date";>XML-Schema specification</A>
*
* @author Phil Mork
* @author Glen Daniels ([EMAIL PROTECTED])
* @see Serializer
* @see Deserializer
*/
public class CalendarSerializer implements Serializer, Deserializer
{
  SimpleDateFormat sdf;  

  public CalendarSerializer()
  {    
    sdf=new SimpleDateFormat("yyyy-MM-dd");
    //For now just use the default locale timezone  - could set to GMT if needed
    //sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
  }

  public void marshall(String inScopeEncStyle, Class javaType, Object src,
                       Object context, Writer sink, NSStack nsStack,
                       XMLJavaMappingRegistry xjmr, SOAPContext ctx)
                        throws IllegalArgumentException, IOException
  {    
      /* [EMAIL PROTECTED], March 12, 2003: Changed to be able to handle 
java.util.Calendar objects */
    Date calDate = null;
      
    if( javaType.equals(java.util.GregorianCalendar.class))
    {
        calDate = ((GregorianCalendar)src).getTime();
    }

    if( javaType.equals(java.util.Calendar.class))
    {
        calDate = ((Calendar)src).getTime();
    }
      
    if ( calDate == null )
      throw new IllegalArgumentException("Can only serialize GregorianCalendar or 
Calendar instances");

    nsStack.pushScope();
    if(src!=null)
    {
      SoapEncUtils.generateStructureHeader(inScopeEncStyle,
                                           javaType,
                                           context,
                                           sink,
                                           nsStack,
                                           xjmr,
                                           ctx);
      
      String fdate = null;

      synchronized(sdf)
      {
        fdate=sdf.format(calDate);
      }

      sink.write(fdate);
      sink.write("</" + context + '>');
    }
    else
    {
      SoapEncUtils.generateNullStructure(inScopeEncStyle,
                                           javaType,
                                           context,
                                           sink,
                                           nsStack,
                                           xjmr,
                                           ctx);
    }
    nsStack.popScope();
  }

  public Bean unmarshall(String inScopeEncStyle, QName elementType, Node src,
                         XMLJavaMappingRegistry xjmr, SOAPContext ctx)
                          throws IllegalArgumentException
  {
    Date date=null;
    Calendar calDate = new GregorianCalendar();
    Element root = (Element)src;
    String value = DOMUtils.getChildCharacterData(root);
    if(value!=null && !((value=value.trim()).equals("")))
    {
      try
      {
        synchronized(sdf)
        {
          date=sdf.parse(value);
        }
        calDate.setTime(date);
      }
      catch (ParseException pe)
      {
        throw new IllegalArgumentException("String represents no valid Date for this 
Deserializer");
      }
    }
    return new Bean(java.util.GregorianCalendar.class, calDate);
  }
}
/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "SOAP" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 2000, International
 * Business Machines, Inc., http://www.apache.org.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

package org.apache.soap.encoding.soapenc;

import java.io.*;
import org.w3c.dom.*;
import org.apache.soap.util.xml.*;
import org.apache.soap.*;
import org.apache.soap.encoding.SOAPMappingRegistry;
import org.apache.soap.rpc.SOAPContext;

/**
 * These static methods can be used to do much of the repetitive and
 * mechanical work that is required when generating structures using
 * the <code>SOAP-ENC</code> encoding style.
 *
 * @author Matthew J. Duftler ([EMAIL PROTECTED])
 * @author Scott Nichol ([EMAIL PROTECTED])
 */
public class SoapEncUtils
{
  public static void generateNullStructure(String inScopeEncStyle,
                                           Class javaType, Object context,
                                           Writer sink, NSStack nsStack,
                                           XMLJavaMappingRegistry xjmr,
                                           SOAPContext ctx)
    throws IllegalArgumentException, IOException
  {
    generateStructureHeader(inScopeEncStyle, javaType, context, sink,
                            nsStack, xjmr, ctx, null, null, true);
  }

  public static void generateNullArray(String inScopeEncStyle,
                                       Class javaType, Object context,
                                       Writer sink, NSStack nsStack,
                                       XMLJavaMappingRegistry xjmr,
                                       SOAPContext ctx,
                                       QName arrayElementType,
                                       String arrayLengthStr)
    throws IllegalArgumentException, IOException
  {
    generateStructureHeader(inScopeEncStyle, javaType, context, sink,
                            nsStack, xjmr, ctx, arrayElementType, arrayLengthStr,
                            true);
  }

  public static void generateArrayHeader(String inScopeEncStyle,
                                         Class javaType, Object context,
                                         Writer sink, NSStack nsStack,
                                         XMLJavaMappingRegistry xjmr,
                                         SOAPContext ctx,
                                         QName arrayElementType,
                                         String arrayLengthStr)
    throws IllegalArgumentException, IOException
  {
    generateStructureHeader(inScopeEncStyle, javaType, context, sink,
                            nsStack, xjmr, ctx, arrayElementType, arrayLengthStr,
                            false);
  }

  public static void generateStructureHeader(String inScopeEncStyle,
                                             Class javaType, Object context,
                                             Writer sink, NSStack nsStack,
                                             XMLJavaMappingRegistry xjmr,
                                             SOAPContext ctx)
    throws IllegalArgumentException, IOException
  {
    generateStructureHeader(inScopeEncStyle, javaType, context, sink,
                            nsStack, xjmr, ctx, null, null, false);
  }

  private static void generateStructureHeader(String inScopeEncStyle,
                                              Class javaType, Object context,
                                              Writer sink, NSStack nsStack,
                                              XMLJavaMappingRegistry xjmr,
                                              SOAPContext ctx,
                                              QName arrayElementType,
                                              String arrayLengthStr,
                                              boolean isNull)
    throws IllegalArgumentException, IOException
  {
      
    /* [EMAIL PROTECTED] March 16, 2004: Hacking the QName for java.util.Calendar
     to make it interoperate with a Web Service that requires dateTime. I would
     not recommend this approach to anyone. */
    
    QName elementType = null;

    if ( javaType.equals(java.util.Calendar.class) )
    {
        elementType = new QName( "http://www.w3.org/2001/XMLSchema";, "dateTime" );
    }
    else
    {
        elementType = xjmr.queryElementType(javaType, Constants.NS_URI_SOAP_ENC);
    }
    
    String namespaceDecl = "";

    if (context instanceof PrefixedName)
    {
      PrefixedName pname = (PrefixedName)context;
      QName qname = pname.getQName();

      if (qname != null)
      {
        String namespaceURI = qname.getNamespaceURI();

        if (namespaceURI != null && !namespaceURI.equals(""))
        {
          if (pname.getPrefix() == null)
          {
            String prefix = nsStack.getPrefixFromURI(namespaceURI);

            if (prefix == null)
            {
              prefix = nsStack.addNSDeclaration(namespaceURI);
              namespaceDecl = " xmlns:" + prefix + "=\"" + namespaceURI + '\"';
            }

            pname.setPrefix(prefix);
          }
        }
      }
    }

    sink.write('<');
    sink.write(context.toString());
    sink.write(namespaceDecl);

    // Write the id for a multiRef element
    if (context instanceof MultiRefContext) {
      sink.write(' '+ Constants.ATTR_ID + "=\"" +
                 Constants.ATTRVAL_MULTIREF_ID_PREFIX);
      sink.write(((MultiRefContext) context).getId() + "");
      sink.write( '\"');
    }

    // Get prefixes for the needed namespaces.
    String elementTypeNS = elementType.getNamespaceURI();
    String xsiNamespaceURI;

    if (elementTypeNS.startsWith("http://www.w3.org/";)
        && elementTypeNS.endsWith("/XMLSchema")) {
      xsiNamespaceURI = elementTypeNS + "-instance";
    } else if (xjmr instanceof SOAPMappingRegistry) {
      xsiNamespaceURI = ((SOAPMappingRegistry) xjmr).getSchemaURI() + "-instance";
    } else {
      xsiNamespaceURI = Constants.NS_URI_CURRENT_SCHEMA_XSI;
    }

    String xsiNSPrefix = nsStack.getPrefixFromURI(xsiNamespaceURI, sink);
    String elementTypeNSPrefix = nsStack.getPrefixFromURI(elementTypeNS, sink);

    if (ctx == null || !ctx.getDocLitSerialization()) {
      sink.write(' ');
      sink.write(xsiNSPrefix);
      sink.write(':' + Constants.ATTR_TYPE + "=\"");
      sink.write(elementTypeNSPrefix);
      sink.write(':');
      sink.write(elementType.getLocalPart());
      sink.write('\"');
    }

    if (inScopeEncStyle == null
        || !inScopeEncStyle.equals(Constants.NS_URI_SOAP_ENC))
    {
      // Determine the prefix associated with the NS_URI_SOAP_ENV
      // namespace URI.
      String soapEnvNSPrefix = nsStack.getPrefixFromURI(
        Constants.NS_URI_SOAP_ENV, sink);

      sink.write(' ');
      sink.write(soapEnvNSPrefix);
      sink.write(':' +Constants.ATTR_ENCODING_STYLE + "=\"" +
                 Constants.NS_URI_SOAP_ENC + '\"');
    }

    if (arrayElementType != null)
    {
      String arrayElementTypeNSPrefix = nsStack.getPrefixFromURI(
        arrayElementType.getNamespaceURI(), sink);
      String arrayTypeValue = arrayElementTypeNSPrefix + ':' +
                              arrayElementType.getLocalPart() +
                              '[' + arrayLengthStr + ']';
      String soapEncNSPrefix = nsStack.getPrefixFromURI(
        Constants.NS_URI_SOAP_ENC, sink);

      sink.write(' ');
      sink.write(soapEncNSPrefix);
      sink.write(':' + Constants.ATTR_ARRAY_TYPE +"=\"");
      sink.write(arrayTypeValue);
      sink.write('\"');
    }

    if (isNull)
    {
      sink.write(' ');
      sink.write(xsiNSPrefix);
      sink.write(':');
      sink.write(nilName(xsiNamespaceURI));
      sink.write("=\"" + Constants.ATTRVAL_TRUE + "\"/");
    }

    sink.write('>');
  }

  public static void generateNullStructure(String inScopeEncStyle,
                                           Class javaType, Object context,
                                           Writer sink, NSStack nsStack,
                                           XMLJavaMappingRegistry xjmr)
    throws IllegalArgumentException, IOException
  {
    generateStructureHeader(inScopeEncStyle, javaType, context, sink,
                            nsStack, xjmr, null, null, null, true);
  }

  public static void generateNullArray(String inScopeEncStyle,
                                       Class javaType, Object context,
                                       Writer sink, NSStack nsStack,
                                       XMLJavaMappingRegistry xjmr,
                                       QName arrayElementType,
                                       String arrayLengthStr)
    throws IllegalArgumentException, IOException
  {
    generateStructureHeader(inScopeEncStyle, javaType, context, sink,
                            nsStack, xjmr, null, arrayElementType, arrayLengthStr,
                            true);
  }

  public static void generateArrayHeader(String inScopeEncStyle,
                                         Class javaType, Object context,
                                         Writer sink, NSStack nsStack,
                                         XMLJavaMappingRegistry xjmr,
                                         QName arrayElementType,
                                         String arrayLengthStr)
    throws IllegalArgumentException, IOException
  {
    generateStructureHeader(inScopeEncStyle, javaType, context, sink,
                            nsStack, xjmr, null, arrayElementType, arrayLengthStr,
                            false);
  }

  public static void generateStructureHeader(String inScopeEncStyle,
                                             Class javaType, Object context,
                                             Writer sink, NSStack nsStack,
                                             XMLJavaMappingRegistry xjmr)
    throws IllegalArgumentException, IOException
  {
    generateStructureHeader(inScopeEncStyle, javaType, context, sink,
                            nsStack, xjmr, null, null, null, false);
  }

  private static String nilName(String currentSchemaXSI)
  {
    return (currentSchemaXSI.equals(Constants.NS_URI_2001_SCHEMA_XSI))
           ? Constants.ATTR_NIL
           : Constants.ATTR_NULL;
  }

  public static boolean isNull(Element element)
  {
    String nullValue = DOMUtils.getAttributeNS(element,
                                               Constants.NS_URI_2001_SCHEMA_XSI,
                                               Constants.ATTR_NIL);

    if (nullValue == null)
    {
      nullValue = DOMUtils.getAttributeNS(element,
                                          Constants.NS_URI_2000_SCHEMA_XSI,
                                          Constants.ATTR_NULL);
    }

    if (nullValue == null)
    {
      nullValue = DOMUtils.getAttributeNS(element,
                                          Constants.NS_URI_1999_SCHEMA_XSI,
                                          Constants.ATTR_NULL);
    }

        // This case accepts the buggy output from Apache SOAP prior to 2.3.1,
        // specifically a xsi:null for 2001 schema (should be xsi:nil).
    if (nullValue == null)
    {
      nullValue = DOMUtils.getAttributeNS(element,
                                          Constants.NS_URI_2001_SCHEMA_XSI,
                                          Constants.ATTR_NULL);
    }

    return nullValue != null && decodeBooleanValue(nullValue);
  }

  public static boolean decodeBooleanValue(String value)
  {
    switch (value.charAt(0))
    {
      case '0': case 'f': case 'F':
        return false;

      case '1': case 't': case 'T':
        return true;

      default:
        throw new IllegalArgumentException("Invalid boolean value: " + value);
    }
  }

  public static QName getAttributeValue(Element el,
                                        String attrNameNamespaceURI,
                                        String attrNameLocalPart,
                                        String elDesc,
                                        boolean isRequired)
    throws IllegalArgumentException
  {
    String attrValue = DOMUtils.getAttributeNS(el,
                                               attrNameNamespaceURI,
                                               attrNameLocalPart);

    if (attrValue != null)
    {
      int index = attrValue.indexOf(':');

      if (index != -1)
      {
        String attrValuePrefix       = attrValue.substring(0, index);
        String attrValueLocalPart    = attrValue.substring(index + 1);
        String attrValueNamespaceURI =
          DOMUtils.getNamespaceURIFromPrefix(el, attrValuePrefix);

        if (attrValueNamespaceURI != null)
        {
          return new QName(attrValueNamespaceURI, attrValueLocalPart);
        }
        else
        {
          throw new IllegalArgumentException("Unable to resolve namespace " +
                                             "URI for '" + attrValuePrefix +
                                             "'.");
        }
      }
      else
      {
        throw new IllegalArgumentException("The value of the '" +
                                           attrNameNamespaceURI + ':' +
                                           attrNameLocalPart +
                                           "' attribute must be " +
                                           "namespace-qualified.");
      }
    }
    else if (isRequired)
    {
      throw new IllegalArgumentException("The '" +
                                         attrNameNamespaceURI + ':' +
                                         attrNameLocalPart +
                                         "' attribute must be " +
                                         "specified for every " +
                                         elDesc + '.');
    }
    else
    {
      return null;
    }
  }

  /**
   * Get the value of the xsi:type attribute, for varying values of
   * the xsi namespace.  In the absence of an xsi:type attribute,
   * determine whether the element QName implies a type, e.g. if it
   * has the SOAP-ENC namespaceURI.  For now, this is limited to
   * checking for SOAP-ENC:Array.
   */
  public static QName getTypeQName(Element el)
    throws IllegalArgumentException
  {
    // Try 2001
    QName typeQName = getAttributeValue(el, Constants.NS_URI_2001_SCHEMA_XSI,
                                        Constants.ATTR_TYPE, null, false);

    if (typeQName != null)
      return typeQName;

    // Try 2000
    typeQName = getAttributeValue(el, Constants.NS_URI_2000_SCHEMA_XSI,
                                  Constants.ATTR_TYPE, null, false);

    if (typeQName != null)
      return typeQName;

    // Try 1999
    typeQName = getAttributeValue(el, Constants.NS_URI_1999_SCHEMA_XSI,
                                  Constants.ATTR_TYPE, null, false);

    if (typeQName != null)
      return typeQName;

    // Check for SOAP-ENC namespace for element name
    String nsURI = el.getNamespaceURI();
    if (nsURI != null && nsURI.equals(Constants.NS_URI_SOAP_ENC)) {
      // For now, just check for Array
      String localName = el.getLocalName();
      if (localName.equals("Array"))
        typeQName = new QName(nsURI, localName);
    }

    return typeQName;
  }
}


On Mar 12, 2004, at 6:36 PM, Scott Nichol wrote:

We are always open to contributions.

Scott Nichol

Do not send e-mail directly to this e-mail address,
because it is filtered to accept only mail from
specific mail lists.
----- Original Message -----
From: "Frank Cohen" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Friday, March 12, 2004 8:35 PM
Subject: java.util.Calendar serializer patch contribution


My open-source framework and utility TestMaker bundles Apache SOAP. A user pointed out a problem where he was trying to serialized a java.util.Calendar object in a complex data type. The Apache SOAP code serializes GregorianCalendar but not Calendar. So, I modified the Calendar serializer class. I'm wondering if this is worthwhile to submit to the Apache SOAP project as a contribution? I intend to ship the modified library with TestMaker 4.0.9 and later.

Please let me know if you want the patch and how to send it. Thanks.

-Frank



--
Frank Cohen, PushToTest, http://www.PushToTest.com, phone: 408 374 7426
Enterprise test automation solutions to check and monitor Web-enabled
applications for functionality, scalability and reliability.



--
Frank Cohen, PushToTest, http://www.PushToTest.com, phone: 408 374 7426
Enterprise test automation solutions to check and monitor Web-enabled
applications for functionality, scalability and reliability.

Reply via email to