Index: src/main/java/org/exolab/castor/xml/UnmarshalHandler.java =================================================================== --- src/main/java/org/exolab/castor/xml/UnmarshalHandler.java (Revision 7385) +++ src/main/java/org/exolab/castor/xml/UnmarshalHandler.java (Arbeitskopie) @@ -58,6 +58,8 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; import java.util.Stack; import java.util.StringTokenizer; @@ -764,7 +766,7 @@ state.buffer.setLength(0); } - if (type == String.class) { + if (type == String.class && !((XMLFieldDescriptorImpl) descriptor).isDerivedFromXSList()) { if (str != null) state.object = str; else if (state.nil) { @@ -790,6 +792,19 @@ else if (state.args != null) { state.object = createInstance(state.type, state.args); } + // TODO: !!! need to make this more explicit !!! + else if (descriptor.isMultivalued() + && descriptor.getSchemaType() != null + && descriptor.getSchemaType().equals("list") + && ((XMLFieldDescriptorImpl) descriptor).isDerivedFromXSList()) { + StringTokenizer attrValueTokenizer = new StringTokenizer(str); + List primitives = new ArrayList(); + while (attrValueTokenizer.hasMoreTokens()) { + String tokenValue = attrValueTokenizer.nextToken(); + primitives.add(toPrimitiveObject(type, tokenValue, state.fieldDesc)); + } + state.object = primitives; + } else state.object = toPrimitiveObject(type,str,state.fieldDesc); } else if (ArrayHandler.class.isAssignableFrom(state.type)) { @@ -1030,16 +1045,34 @@ if (firstOccurance && _clearCollections) { handler.resetValue(state.object); } + + if (descriptor.isMultivalued() + && descriptor.getSchemaType() != null + && descriptor.getSchemaType().equals("list") + && ((XMLFieldDescriptorImpl) descriptor).isDerivedFromXSList()) { + List values = (List) val; + for (Iterator iterator = values.iterator(); iterator.hasNext();) { + //-- finally set the value!! + Object value = iterator.next(); + handler.setValue(state.object, value); + + // If there is a parent for this object, pass along + // a notification that we've finished adding a child + if ( _unmarshalListener != null ) { + _unmarshalListener.fieldAdded(descriptor.getFieldName(), state.object, fieldState.object); + } + } + } else { - //-- finally set the value!! - handler.setValue(state.object, val); - - // If there is a parent for this object, pass along - // a notification that we've finished adding a child - if ( _unmarshalListener != null ) { - _unmarshalListener.fieldAdded(descriptor.getFieldName(), state.object, fieldState.object); - } + //-- finally set the value!! + handler.setValue(state.object, val); + // If there is a parent for this object, pass along + // a notification that we've finished adding a child + if ( _unmarshalListener != null ) { + _unmarshalListener.fieldAdded(descriptor.getFieldName(), state.object, fieldState.object); + } + } } } @@ -3010,53 +3043,70 @@ //-- if this is an multi-value attribute - StringTokenizer attrValueTokenizer = null; - if (descriptor.isMultivalued()) - { - attrValueTokenizer = new StringTokenizer(attValue); - if(attrValueTokenizer.hasMoreTokens()) - attValue = attrValueTokenizer.nextToken(); + if (descriptor.isMultivalued()) { + StringTokenizer attrValueTokenizer = new StringTokenizer(attValue); + while (attrValueTokenizer.hasMoreTokens()) { + attValue = attrValueTokenizer.nextToken(); + setAttributeValueOnObject(attValue, descriptor, parent, handler, + type, isPrimative, isQName, isByteArray); + } + } else { + setAttributeValueOnObject(attValue, descriptor, parent, handler, + type, isPrimative, isQName, isByteArray); } + + } //-- processAttribute + + /** + * Sets the value of an attribute on the target object, using the {@link FieldHandler} + * provided. + * @param attValue The attribute value. + * @param descriptor Corresponding {@link XMLFieldDescriptor} instance for the attribute processed. + * @param parent Parent object into which attribute value needs to be 'injected'. + * @param handler {@link FieldHandler} used for 'value injection'. + * @param type {@link Class} type. + * @param isPrimitive Indicates whether the attribute value represents a primitive value. + * @param isQName Indicates whether the attribute value represents a QName value. + * @param isByteArray Indicates whether the attribute value represents a byte array. + * @throws SAXException If there's a problem 'injecting' the attribute value into the target field. + */ + private void setAttributeValueOnObject(final String attValue, + final XMLFieldDescriptor descriptor, + final Object parent, + final FieldHandler handler, + final Class type, + final boolean isPrimitive, + final boolean isQName, + final boolean isByteArray) throws SAXException { + //-- value to set + Object value = attValue; + //-- special type conversion for primitives + if (isPrimitive) { + value = toPrimitiveObject(type, attValue, descriptor); + } - while(true) - { - //-- value to set - Object value = attValue; - //-- check for proper type and do type conversion - if (isPrimative) - value = toPrimitiveObject(type, attValue, descriptor); - - // special treatment for byte[]s - if (isByteArray) { - if (attValue == null) - value = new byte[0]; - else { - //-- Base64/hexbinary decoding - if (HexDecoder.DATA_TYPE.equals(descriptor.getSchemaType())) { - value = HexDecoder.decode(attValue); - } else { - value = Base64Decoder.decode(attValue); - } + //-- special byte[]s provessing, if required + if (isByteArray) { + if (attValue == null) { + value = new byte[0]; + } else { + //-- Base64/hexbinary decoding + if (HexDecoder.DATA_TYPE.equals(descriptor.getSchemaType())) { + value = HexDecoder.decode(attValue); + } else { + value = Base64Decoder.decode(attValue); } } - - //-- check if the value is a QName that needs to - //-- be resolved (ns:value -> {URI}value) - if(isQName) - value = resolveNamespace(value); - //-- set value - handler.setValue(parent, value); - //-- more values? - if(attrValueTokenizer==null) - break; - if(!attrValueTokenizer.hasMoreTokens()) - break; - //-- next value - attValue = attrValueTokenizer.nextToken(); } + + //-- QName resolution (ns:value -> {URI}value), if required + if(isQName) { + value = resolveNamespace(value); + } + //-- set value + handler.setValue(parent, value); + } - } //-- processAttribute - /** * Processes the given attribute set, and creates the * constructor arguments Index: src/main/java/org/exolab/castor/xml/schema/XMLType.java =================================================================== --- src/main/java/org/exolab/castor/xml/schema/XMLType.java (Revision 7385) +++ src/main/java/org/exolab/castor/xml/schema/XMLType.java (Arbeitskopie) @@ -164,7 +164,8 @@ **/ public final boolean isSimpleType() { return ((getStructureType() == Structure.SIMPLE_TYPE) || - (getStructureType() == Structure.UNION)); + (getStructureType() == Structure.UNION) || + (getStructureType() == Structure.LIST)); } //-- isSimpleType Index: src/main/java/org/exolab/castor/xml/schema/simpletypes/ListType.java =================================================================== --- src/main/java/org/exolab/castor/xml/schema/simpletypes/ListType.java (Revision 7385) +++ src/main/java/org/exolab/castor/xml/schema/simpletypes/ListType.java (Arbeitskopie) @@ -120,7 +120,8 @@ * @return the type of this Schema Structure */ public short getStructureType() { - return Structure.SIMPLE_TYPE; //-- should be changed to LIST + return Structure.LIST; +// return Structure.SIMPLE_TYPE; //-- should be changed to LIST } //-- getStructureType /** Index: src/main/java/org/exolab/castor/xml/util/XMLFieldDescriptorImpl.java =================================================================== --- src/main/java/org/exolab/castor/xml/util/XMLFieldDescriptorImpl.java (Revision 7385) +++ src/main/java/org/exolab/castor/xml/util/XMLFieldDescriptorImpl.java (Arbeitskopie) @@ -15,6 +15,7 @@ */ package org.exolab.castor.xml.util; +import org.exolab.castor.builder.types.XSList; import org.exolab.castor.mapping.ClassDescriptor; import org.exolab.castor.mapping.FieldDescriptor; import org.exolab.castor.mapping.FieldHandler; @@ -99,6 +100,9 @@ /** The XML Schema type of this field value. */ private String _schemaType = null; + /** The XML Schema type of the components for XML schema lists. */ + private String _componentType = null; + /** The prefix used in case the value of the field described is of type QName. */ private String _qNamePrefix = null; @@ -107,7 +111,10 @@ private FieldValidator _validator = null; - /** The XML name of the field, this is only the local name. */ + /** + * The local XML name of the field; this does not include any + * path elements. + */ private String _xmlName = null; /** The relative XML path used when wrapping in nested elements, does not @@ -116,6 +123,12 @@ private String _xmlPath = null; private List _substitutes; + + /** + * Indicates whether the field described by this {@link XMLFieldDescriptorImpl} is + * created as a result of a definition. + */ + private boolean _derivedFromXSList; //----------------/ @@ -430,6 +443,16 @@ } /** + * Sets the type of the XML Schema type of the value for the field being + * described. + * + * @param componentType The component type for <xs:list>s. + */ + public void setComponentType(final String componentType) { + _componentType = componentType; + } + + /** * @see org.exolab.castor.xml.XMLFieldDescriptor#getSchemaType() * {@inheritDoc} */ @@ -437,6 +460,10 @@ return _schemaType; } + public String getComponentType() { + return _componentType; + } + public void setValidator(final FieldValidator validator) { if (_validator != null) { _validator.setDescriptor(null); @@ -793,4 +820,24 @@ _substitutes = substitutes; } + /** + * Sets whether the field described by this {@link XMLFieldDescriptorImpl} is + * created as a result of a definition. + * @param derivedFromXSList A boolean value, true or false. + */ + public void setDerivedFromXSList(final boolean derivedFromXSList) { + _derivedFromXSList = derivedFromXSList; + } + + /** + * Indicates whether the field described by this {@link XMLFieldDescriptorImpl} is + * created as a result of a definition. + * @param derivedFromXSList Trueif the field described by this {@link XMLFieldDescriptorImpl} is + * created as a result of a definition. +. + */ + public boolean isDerivedFromXSList() { + return _derivedFromXSList; + } + } Index: codegen/src/main/java/org/exolab/castor/builder/descriptors/DescriptorSourceFactory.java =================================================================== --- codegen/src/main/java/org/exolab/castor/builder/descriptors/DescriptorSourceFactory.java (Revision 7385) +++ codegen/src/main/java/org/exolab/castor/builder/descriptors/DescriptorSourceFactory.java (Arbeitskopie) @@ -59,6 +59,7 @@ import org.exolab.castor.builder.info.CollectionInfo; import org.exolab.castor.builder.info.FieldInfo; import org.exolab.castor.builder.info.XMLInfo; +import org.exolab.castor.builder.types.XSList; import org.exolab.castor.builder.types.XSListType; import org.exolab.castor.builder.types.XSType; import org.exolab.castor.xml.XMLConstants; @@ -328,6 +329,7 @@ final JSourceCode jsc) { XSType xsType = member.getSchemaType(); + XSType xsCollectionType = null; boolean any = false; boolean isElement = (member.getNodeType() == XMLInfo.ELEMENT_TYPE); boolean isAttribute = (member.getNodeType() == XMLInfo.ATTRIBUTE_TYPE); @@ -343,6 +345,7 @@ if (xsType.isCollection()) { //Attributes can handle COLLECTION type for NMTOKENS or IDREFS for instance + xsCollectionType = xsType; xsType = ((CollectionInfo) member).getContent().getSchemaType(); } @@ -435,7 +438,15 @@ } // Add the schema type as defined in the schema - jsc.add("desc.setSchemaType(\"" + xsType.getName() + "\");"); + if (xsCollectionType == null) { + jsc.add("desc.setSchemaType(\"" + xsType.getName() + "\");"); + } else { + jsc.add("desc.setSchemaType(\"list\");"); + jsc.add("desc.setComponentType(\"" + xsType.getName() + "\");"); + if (xsCollectionType instanceof XSList && ((XSList) xsCollectionType).isDerivedFromXSList()) { + jsc.add("desc.setDerivedFromXSList(true);"); + } + } jsc.add("desc.setHandler(handler);"); //-- container Index: codegen/src/main/java/org/exolab/castor/builder/types/XSList.java =================================================================== --- codegen/src/main/java/org/exolab/castor/builder/types/XSList.java (Revision 7385) +++ codegen/src/main/java/org/exolab/castor/builder/types/XSList.java (Arbeitskopie) @@ -29,6 +29,12 @@ /** Type number of this XSType. */ public static final short TYPE = XSType.COLLECTION; + + /** + * Indicates whether this {@link XSList} instance has been created as a result + * of a definition. + */ + private boolean _derivedFromXSList; //-------------------------------------------------------------------------- @@ -61,6 +67,25 @@ final String fixedValue, final String validatorInstanceName) { getContentType().validationCode(jsc, fixedValue, validatorInstanceName); } + + /** + * Sets whether this {@link XSList} instance has been created as a result + * of a definition. + * @param derivedFromXSList A boolean value, true or false. + */ + public void setDerivedFromXSList(final boolean derivedFromXSList) { + _derivedFromXSList = derivedFromXSList; + } + + /** + * Indicates whether this {@link XSList} instance has been created as a result + * of a definition. + * @param derivedFromXSList True if this XSList instance has been created as a result + * of a definition. + */ + public boolean isDerivedFromXSList() { + return _derivedFromXSList; + } //-------------------------------------------------------------------------- } Index: codegen/src/main/java/org/exolab/castor/builder/types/XSCollectionFactory.java =================================================================== --- codegen/src/main/java/org/exolab/castor/builder/types/XSCollectionFactory.java (Revision 7385) +++ codegen/src/main/java/org/exolab/castor/builder/types/XSCollectionFactory.java (Arbeitskopie) @@ -26,7 +26,7 @@ public final class XSCollectionFactory { /** - * A private constructor as this is a factory which is never meant to be instantiacted. + * A private constructor as this is a factory which is never meant to be instantiated. */ private XSCollectionFactory() { super(); Index: codegen/src/main/java/org/exolab/castor/builder/factory/MemberFactory.java =================================================================== --- codegen/src/main/java/org/exolab/castor/builder/factory/MemberFactory.java (Revision 7385) +++ codegen/src/main/java/org/exolab/castor/builder/factory/MemberFactory.java (Arbeitskopie) @@ -63,6 +63,7 @@ import org.exolab.castor.builder.info.CollectionInfo; import org.exolab.castor.builder.info.FieldInfo; import org.exolab.castor.builder.info.XMLInfo; +import org.exolab.castor.builder.types.XSList; import org.exolab.castor.builder.types.XSListType; import org.exolab.castor.builder.types.XSClass; import org.exolab.castor.builder.types.XSString; @@ -253,7 +254,7 @@ boolean simpleTypeCollection = false; if (xmlType != null) { - if (xmlType.isSimpleType()) { + if (xmlType.isSimpleType() ) { SimpleType simpleType = (SimpleType) xmlType; SimpleType baseType = null; @@ -392,6 +393,10 @@ if (!simpleTypeCollection) { xsList.setMaximumSize(maxOccurs); xsList.setMinimumSize(minOccurs); + } else { + if (xsList instanceof XSList) { + ((XSList) xsList).setDerivedFromXSList(true); + } } fieldInfo = cInfo; } else {