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.