Hi Jean-François, Bug 15724 was fixed today -- check the latest CVS (or the January 4th "interim" source tarball, which does not yet exist).
Regards, Eric -----Original Message----- From: Jean-François Cloutier [mailto:[EMAIL PROTECTED]] Sent: Friday, January 03, 2003 2:56 PM To: [EMAIL PROTECTED] Subject: Improvements to Axis (among others, performance issues with These modifications are based on the v1 release done on October 7, 2002 (since this is the only "official" release). --------------------------------------------------------------------- IMPROVEMENT #1 : probably the most important one (already reported in Bug 15724) --------------------------------------------------------------------- I made this modification after I found out wsdl2java to be extremely slow with large WSDL files. In my case, the WSDL file had about 150 schema types. On a Pentium III 700Mhz and 512Mhz, it was taking 15 minutes to generate the Java stubs. After my code change, it was taking... 10 seconds. My investigation revealed that 98% of the time was spent figuring out what are the derived types of a schema type. When you have a somewhat large object model, this computation was done multiple for a given type. The trick is obviously to cache this computation for each type. Class: org.apache.axis.wsdl.symbolTable.Utils /** * This method returns a set of all types that are derived * from this type via an extension of a complexType */ public static HashSet getDerivedTypes(TypeEntry type, SymbolTable symbolTable) { HashSet types = (HashSet) symbolTable.derivedSets.get(type); if (types != null) return types; types = new HashSet(); symbolTable.derivedSets.put(type, types); if (type != null && type.getNode() != null) { getDerivedTypes(type, types, symbolTable); } else if (Constants.isSchemaXSD(type.getQName().getNamespaceURI()) && (type.getQName().getLocalPart().equals("anyType")|| type.getQName().getLocalPart().equals("any"))) { // All types are derived from anyType types.addAll(symbolTable.getTypes()); } return types; } // getNestedTypes private static void getDerivedTypes( TypeEntry type, HashSet types, SymbolTable symbolTable) { // If all types are in the set, return if (types.size() == symbolTable.getTypes().size()) { return; } // Search the dictionary for derived types of type Vector allTypes = symbolTable.getTypes(); Iterator it = allTypes.iterator(); while(it.hasNext()) { TypeEntry derivedType = (TypeEntry) it.next(); if (derivedType instanceof DefinedType && derivedType.getNode() != null && !types.contains(derivedType) && SchemaUtils.getComplexElementExtensionBase( derivedType.getNode(), symbolTable) == type) { types.add(derivedType); HashSet derivedTypes = getDerivedTypes(derivedType, symbolTable); types.addAll(derivedTypes); } } } // getDerivedTypes Class: org.apache.axis.wsdl.symbolTable.SymbolTable public HashMap derivedSets = new HashMap(); --------------------------------------------------------------------- IMPROVEMENT #2 : BeanDeserializerFactory should respect the class set in deserClass such that Bean deserializer can be subclassed. Likewise for BeanSerializerFactory with serClass. --------------------------------------------------------------------- Class: org.apache.axis.encoding.ser.BeanDeserializerFactory static final Class[] ctorArgTypes = { Class.class, QName.class, TypeDesc.class, java.util.Map.class }; protected Deserializer getGeneralPurpose(String mechanismType) { if ((javaType == null) || (xmlType == null)) return super.getGeneralPurpose(mechanismType); if (deserClass == EnumDeserializer.class) return super.getGeneralPurpose(mechanismType); try { Constructor ctor = deserClass.getConstructor(ctorArgTypes); Object[] args = new Object[] { javaType, xmlType, typeDesc, propertyMap }; return (Deserializer) ctor.newInstance(args); } catch (Exception e) { return new BeanDeserializer(javaType, xmlType, typeDesc, propertyMap); } } Class: org.apache.axis.encoding.ser.BeanSerializerFactory static final Class[] ctorArgTypes = { Class.class, QName.class, TypeDesc.class, BeanPropertyDescriptor[].class }; protected Serializer getGeneralPurpose(String mechanismType) { if ((javaType == null) || (xmlType == null)) return super.getGeneralPurpose(mechanismType); if (serClass == EnumSerializer.class) return super.getGeneralPurpose(mechanismType); try { Constructor ctor = serClass.getConstructor(ctorArgTypes); Object[] args = new Object[] { javaType, xmlType, typeDesc, propertyDescriptor }; return (Serializer) ctor.newInstance(args); } catch (Exception e) { return new BeanSerializer(javaType, xmlType, typeDesc, propertyDescriptor); } } --------------------------------------------------------------------- IMPROVEMENT #3 : allow a subclass of Bean serializer to hook his own BeanPropertyTarget --------------------------------------------------------------------- Title says it all. Class: org.apache.axis.encoding.ser.BeanDeserializer /** * Deserializer interface called on each child element encountered in * the XML stream. * @param namespace is the namespace of the child element * @param localName is the local name of the child element * @param prefix is the prefix used on the name of the child element * @param attributes are the attributes of the child element * @param context is the deserialization context. * @return is a Deserializer to use to deserialize a child (must be * a derived class of SOAPHandler) or null if no deserialization should * be performed. */ public SOAPHandler onStartChild(String namespace, String localName, String prefix, Attributes attributes, DeserializationContext context) throws SAXException { BeanPropertyDescriptor propDesc = null; FieldDesc fieldDesc = null; String encodingStyle = context.getMessageContext().getEncodingStyle(); boolean isEncoded = Constants.isSOAP_ENC(encodingStyle); QName elemQName = new QName(namespace, localName); // The collectionIndex needs to be reset for Beans with multiple arrays if ((prevQName == null) || (!prevQName.equals(elemQName))) { collectionIndex = -1; } prevQName = elemQName; if (typeDesc != null) { // Lookup the name appropriately (assuming an unqualified // name for SOAP encoding, using the namespace otherwise) String fieldName = typeDesc.getFieldNameForElement(elemQName, isEncoded); propDesc = (BeanPropertyDescriptor)propertyMap.get(fieldName); fieldDesc = typeDesc.getFieldByName(fieldName); } if (propDesc == null) { // look for a field by this name. propDesc = (BeanPropertyDescriptor) propertyMap.get(localName); } // try and see if this is an xsd:any namespace="##any" element before // reporting a problem if (propDesc == null) { // try to put unknown elements into a SOAPElement property, if // appropriate propDesc = getAnyPropertyDesc(); if (propDesc != null) { try { MessageElement [] curElements = (MessageElement[])propDesc.get(value); int length = 0; if (curElements != null) { length = curElements.length; } MessageElement [] newElements = new MessageElement[length + 1]; if (curElements != null) { System.arraycopy(curElements, 0, newElements, 0, length); } MessageElement thisEl = context.getCurElement(); newElements[length] = thisEl; propDesc.set(value, newElements); return new SOAPHandler(); } catch (Exception e) { throw new SAXException(e); } } } if (propDesc == null) { // No such field throw new SAXException( Messages.getMessage("badElem00", javaType.getName(), localName)); } // Get the child's xsi:type if available QName childXMLType = context.getTypeFromXSITypeAttr(namespace, localName, attributes); String href = attributes.getValue("href"); // If no xsi:type or href, check the meta-data for the field if (childXMLType == null && fieldDesc != null && href == null) { childXMLType = fieldDesc.getXmlType(); } // Get Deserializer for child, default to using DeserializerImpl Deserializer dSer = getDeserializer(childXMLType, propDesc.getType(), href, context); // It is an error if the dSer is not found, the base // deserializer impl is returned so that it can generate the correct message. if (dSer == null) { dSer = new DeserializerImpl(); return (SOAPHandler)dSer; } // Register value target if (propDesc.isWriteable()) { // If this is an indexed property, and the deserializer we found // was NOT the ArrayDeserializer, this is a non-SOAP array: // <bean> // <field>value1</field> // <field>value2</field> // ... // In this case, we want to use the collectionIndex and make sure // the deserialized value for the child element goes into the // right place in the collection. if (propDesc.isIndexed() && !(dSer instanceof ArrayDeserializer)) { collectionIndex++; dSer.registerValueTarget(createValueTarget(value, propDesc, collectionIndex)); } else { // If we're here, the element maps to a single field value, // whether that be a "basic" type or an array, so use the // normal (non-indexed) BeanPropertyTarget form. collectionIndex = -1; dSer.registerValueTarget(createValueTarget(value, propDesc, -1)); } } return (SOAPHandler)dSer; } protected Target createValueTarget(Object value, BeanPropertyDescriptor propDesc, int collectionIndex) { return new BeanPropertyTarget(value, propDesc, collectionIndex); } _________________________________________________________________ MSN Messenger : discutez en direct avec vos amis ! http://www.msn.fr/msger/default.asp