Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/AbstractTypeCreator.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/AbstractTypeCreator.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/AbstractTypeCreator.java (working copy) @@ -18,15 +18,23 @@ import org.codehaus.xfire.util.ServiceUtils; /** - * @author Hani Suleiman - * Date: Jun 14, 2005 - * Time: 11:59:57 PM + * @author Hani Suleiman Date: Jun 14, 2005 Time: 11:59:57 PM */ -public abstract class AbstractTypeCreator implements TypeCreator +public abstract class AbstractTypeCreator + implements TypeCreator { protected TypeMapping tm; + protected AbstractTypeCreator nextCreator; + private boolean defaultExtensibleElements = true; + + private boolean defaultExtensibleAttributes = true; + + private boolean defaultNillable = false; + + private int defaultMinOccurs = 1; + public TypeMapping getTypeMapping() { return tm; @@ -35,8 +43,9 @@ public void setTypeMapping(TypeMapping typeMapping) { this.tm = typeMapping; - - if (nextCreator != null) nextCreator.setTypeMapping(tm); + + if (nextCreator != null) + nextCreator.setTypeMapping(tm); } public void setNextCreator(AbstractTypeCreator creator) @@ -63,30 +72,31 @@ protected Type createTypeForClass(TypeClassInfo info) { Class javaType = info.getTypeClass(); + Type result = null; if (info.getType() != null) { - return createUserType(info); + result = createUserType(info); } - else if(isHolder(javaType)) + else if (isHolder(javaType)) { - return createHolderType(info); + result = createHolderType(info); } - else if(isArray(javaType)) + else if (isArray(javaType)) { - return createArrayType(info); + result = createArrayType(info); } - else if(isMap(javaType)) + else if (isMap(javaType)) { - return createMapType(info); + result = createMapType(info); } - else if(isCollection(javaType)) + else if (isCollection(javaType)) { - return createCollectionType(info); + result = createCollectionType(info); } - else if(isEnum(javaType)) + else if (isEnum(javaType)) { - return createEnumType(info); + result = createEnumType(info); } else { @@ -95,9 +105,10 @@ { type = createDefaultType(info); } - - return type; + result = type; } + setDefaults( result ); + return result; } protected boolean isHolder(Class javaType) @@ -109,10 +120,10 @@ { if (info.getGenericType() == null) { - throw new UnsupportedOperationException("To use holder types " + - "you must have an XML descriptor declaring the component type."); + throw new UnsupportedOperationException("To use holder types " + + "you must have an XML descriptor declaring the component type."); } - + Class heldCls = (Class) info.getGenericType(); info.setTypeClass(heldCls); @@ -131,28 +142,29 @@ try { Type type = (Type) info.getType().newInstance(); - + QName name = info.getTypeName(); - if (name == null) name = createQName(info.getTypeClass()); - + if (name == null) + name = createQName(info.getTypeClass()); + type.setSchemaType(name); type.setTypeClass(info.getTypeClass()); type.setTypeMapping(getTypeMapping()); - + return type; } catch (InstantiationException e) { - throw new XFireRuntimeException("Couldn't instantiate type classs " + - info.getType().getName(), e); + throw new XFireRuntimeException("Couldn't instantiate type classs " + + info.getType().getName(), e); } catch (IllegalAccessException e) { - throw new XFireRuntimeException("Couldn't access type classs " + - info.getType().getName(), e); + throw new XFireRuntimeException("Couldn't access type classs " + + info.getType().getName(), e); } } - + protected QName createArrayQName(TypeClassInfo info) { Class javaType = info.getTypeClass(); @@ -164,9 +176,14 @@ ArrayType type = new ArrayType(); type.setSchemaType(createArrayQName(info)); type.setTypeClass(info.getTypeClass()); - return type; } + + protected void setDefaults ( Type type ) + { + type.setNillable(isDefaultNillable()); + type.setMinOccurs(getDefaultMinOccurs()); + } protected QName createQName(Class javaType) { @@ -187,11 +204,12 @@ { CollectionType type = new CollectionType(component); type.setTypeMapping(getTypeMapping()); - + QName name = info.getTypeName(); - if (name == null) name = createCollectionQName(info, component); + if (name == null) + name = createCollectionQName(info, component); type.setSchemaType(name); - + type.setTypeClass(info.getTypeClass()); return type; @@ -200,9 +218,7 @@ protected Type createMapType(TypeClassInfo info, Class keyType, Class valueType) { QName schemaType = createMapQName(info, keyType, valueType); - MapType type = new MapType(schemaType, - keyType, - valueType); + MapType type = new MapType(schemaType, keyType, valueType); type.setTypeMapping(getTypeMapping()); type.setTypeClass(info.getTypeClass()); @@ -211,51 +227,49 @@ protected Type createMapType(TypeClassInfo info) { - return createMapType(info, (Class) info.getKeyType(), (Class) info.getGenericType()); + return createMapType(info, (Class) info.getKeyType(), (Class) info.getGenericType()); } protected QName createMapQName(TypeClassInfo info, Class keyClass, Class valueClass) { - if(keyClass == null) + if (keyClass == null) { - throw new XFireRuntimeException("Cannot create mapping for map, unspecified key type" - + (info.getDescription() != null ? " for " + info.getDescription() : "")); + throw new XFireRuntimeException("Cannot create mapping for map, unspecified key type" + + (info.getDescription() != null ? " for " + info.getDescription() : "")); } - - if(valueClass == null) + + if (valueClass == null) { throw new XFireRuntimeException("Cannot create mapping for map, unspecified value type" - + (info.getDescription() != null ? " for " + info.getDescription() : "")); + + (info.getDescription() != null ? " for " + info.getDescription() : "")); } - + Type keyType = tm.getType(keyClass); - if(keyType == null) + if (keyType == null) { keyType = createType(keyClass); getTypeMapping().register(keyType); } - + Type valueType = tm.getType(valueClass); - if(valueType == null) + if (valueType == null) { - valueType = createType(valueClass); + valueType = createType(valueClass); getTypeMapping().register(valueType); } - - String name = keyType.getSchemaType().getLocalPart() - + '2' - + valueType.getSchemaType().getLocalPart() - + "Map"; - + + String name = keyType.getSchemaType().getLocalPart() + '2' + + valueType.getSchemaType().getLocalPart() + "Map"; + // TODO: Get namespace from XML? return new QName(tm.getEncodingStyleURI(), name); } - + protected boolean isMap(Class javaType) { return Map.class.isAssignableFrom(javaType); } - + public abstract TypeClassInfo createClassInfo(PropertyDescriptor pd); protected boolean isEnum(Class javaType) @@ -275,20 +289,21 @@ protected QName createCollectionQName(TypeClassInfo info, Class componentType) { Class javaType = info.getTypeClass(); - if(componentType == null) + if (componentType == null) { - throw new XFireRuntimeException("Cannot create mapping for " + javaType.getName() + ", unspecified component type" - + (info.getDescription() != null ? " for " + info.getDescription() : "")); + throw new XFireRuntimeException("Cannot create mapping for " + javaType.getName() + + ", unspecified component type" + + (info.getDescription() != null ? " for " + info.getDescription() : "")); } Type type = tm.getType(componentType); - if(type == null) + if (type == null) { type = createType(componentType); getTypeMapping().register(type); } String ns; - if(type.isComplex()) + if (type.isComplex()) { ns = type.getSchemaType().getNamespaceURI(); } @@ -308,21 +323,26 @@ /** * Create a Type for a Method parameter. - * - * @param m the method to create a type for - * @param index The parameter index. If the index is less than zero, the return type is used. + * + * @param m + * the method to create a type for + * @param index + * The parameter index. If the index is less than zero, the + * return type is used. */ public Type createType(Method m, int index) { TypeClassInfo info = createClassInfo(m, index); - info.setDescription((index == -1 ? "return type" : "parameter " + index) + " of method " + m.getName() + " in " + m.getDeclaringClass()); + info.setDescription((index == -1 ? "return type" : "parameter " + index) + " of method " + + m.getName() + " in " + m.getDeclaringClass()); return createTypeForClass(info); } /** * Create type information for a PropertyDescriptor. - * - * @param pd the propertydescriptor + * + * @param pd + * the propertydescriptor */ public Type createType(PropertyDescriptor pd) { @@ -333,8 +353,9 @@ /** * Create type information for a Field. - * - * @param f the field to create a type from + * + * @param f + * the field to create a type from */ public Type createType(Field f) { @@ -353,12 +374,19 @@ public static class TypeClassInfo { Class typeClass; + Object[] annotations; + Object genericType; + Object keyType; + String mappedName; + QName typeName; + Class type; + String description; public String getDescription() @@ -431,4 +459,45 @@ this.type = type; } } + + public boolean isDefaultExtensibleAttributes() + { + return defaultExtensibleAttributes; + } + + public void setDefaultExtensibleAttributes(boolean defaultExtensibleAttributes) + { + this.defaultExtensibleAttributes = defaultExtensibleAttributes; + } + + public boolean isDefaultExtensibleElements() + { + return defaultExtensibleElements; + } + + public void setDefaultExtensibleElements(boolean defaultExtensibleElements) + { + this.defaultExtensibleElements = defaultExtensibleElements; + } + + public int getDefaultMinOccurs() + { + return defaultMinOccurs; + } + + public void setDefaultMinOccurs(int defaultMinOccurs) + { + this.defaultMinOccurs = defaultMinOccurs; + } + + public boolean isDefaultNillable() + { + return defaultNillable; + } + + public void setDefaultNillable(boolean defaultNillable) + { + this.defaultNillable = defaultNillable; + } + } Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/ArrayType.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/ArrayType.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/ArrayType.java (working copy) @@ -34,7 +34,6 @@ public ArrayType() { - setNillable(true); } public Object readObject(MessageReader reader, MessageContext context) Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/Base64Type.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/Base64Type.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/Base64Type.java (working copy) @@ -24,7 +24,6 @@ public Base64Type() { super(); - setNillable(true); } public Object readObject(MessageReader mreader, MessageContext context) Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BeanType.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BeanType.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BeanType.java (working copy) @@ -37,14 +37,11 @@ public BeanType() { - setNillable(true); } public BeanType(BeanTypeInfo info) { - this._info = info; - setNillable(true); - + this._info = info; this.setTypeClass(info.getTypeClass()); } @@ -370,6 +367,19 @@ writeTypeReference(name, nameWithPrefix, element, type, prefix); } + /** + * if future proof then add element + */ + if ( info.isExtensibleElements() ) + { + if (seq == null) + { + seq = new Element("sequence", SoapConstants.XSD_PREFIX, SoapConstants.XSD); + complex.addContent(seq); + } + seq.addContent( createAnyElement () ); + } + // Write out schema for attributes for (Iterator itr = info.getAttributes(); itr.hasNext();) { @@ -390,6 +400,14 @@ element.setAttribute(new Attribute("name", nameWithPrefix)); element.setAttribute(new Attribute("type", prefix + ':' + type.getSchemaType().getLocalPart())); } + + /** + * If extensible attributes then add + */ + if ( info.isExtensibleAttributes() ) + { + complex.addContent( createAnyAttribute() ); + } } private String getNameWithPrefix(Element root, String nameNS, String localName) @@ -422,8 +440,12 @@ { element.setAttribute(new Attribute("name", nameWithPrefix)); element.setAttribute(new Attribute("type", prefix + ':' + type.getSchemaType().getLocalPart())); - element.setAttribute(new Attribute("minOccurs", "0")); + if ( getTypeInfo().getMinOccurs( name ) == 0 ) + { + element.setAttribute(new Attribute("minOccurs", "0")); + } + if (getTypeInfo().isNillable(name)) { element.setAttribute(new Attribute("nillable", "true")); @@ -501,4 +523,35 @@ return info; } + + /** + * Create an element to represent any future elements + * that might get added to the schema + * + * @return + */ + private Element createAnyElement() + { + Element result = new Element("any", + SoapConstants.XSD_PREFIX, + SoapConstants.XSD); + result.setAttribute(new Attribute("minOccurs", "0")); + result.setAttribute(new Attribute("maxOccurs", "unbounded")); + return result; + } + + /** + * Create an element to represent any future attributes + * that might get added to the schema + * + * @return + */ + private Element createAnyAttribute() + { + Element result = new Element("anyAttribute", + SoapConstants.XSD_PREFIX, + SoapConstants.XSD); + return result; + } + } Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BeanTypeInfo.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BeanTypeInfo.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BeanTypeInfo.java (working copy) @@ -19,22 +19,41 @@ public class BeanTypeInfo { private Map mappedName2typeName = new HashMap(); + private Map mappedName2pdName = new HashMap(); + private Map mappedName2type = new HashMap(); private Class beanClass; + private List attributes = new ArrayList(); + private List elements = new ArrayList(); + private PropertyDescriptor[] descriptors; + private TypeMapping typeMapping; + private boolean initialized; + private String defaultNamespace; - + + /** + * extensibleElements means adding xs:any to WSDL Complex Type Definition + */ + private boolean extensibleElements = true; + + /** + * extensibleAttributes means adding xs:anyAttribute to WSDL Complex Type + * Definition + */ + private boolean extensibleAttributes = true; + public BeanTypeInfo(Class typeClass, String defaultNamespace) { this.beanClass = typeClass; this.defaultNamespace = defaultNamespace; - + initializeProperties(); } @@ -43,13 +62,14 @@ * * @param typeClass * @param defaultNamespace - * @param initiallize If true attempt default property/xml mappings. + * @param initiallize + * If true attempt default property/xml mappings. */ public BeanTypeInfo(Class typeClass, String defaultNamespace, boolean initialize) { this.beanClass = typeClass; this.defaultNamespace = defaultNamespace; - + initializeProperties(); setInitialized(!initialize); } @@ -74,20 +94,22 @@ } catch (Exception e) { - if(e instanceof XFireRuntimeException) throw (XFireRuntimeException)e; + if (e instanceof XFireRuntimeException) + throw (XFireRuntimeException) e; throw new XFireRuntimeException("Couldn't create TypeInfo.", e); } - + setInitialized(true); } public boolean isMapped(PropertyDescriptor pd) { - if (pd.getReadMethod() == null) return false; + if (pd.getReadMethod() == null) + return false; return true; } - + public boolean isInitialized() { return initialized; @@ -101,7 +123,7 @@ protected void mapProperty(PropertyDescriptor pd) { String name = pd.getName(); - + if (isAttribute(pd)) { mapAttribute(name, createMappedName(pd)); @@ -111,7 +133,7 @@ mapElement(name, createMappedName(pd)); } } - + protected PropertyDescriptor[] getPropertyDescriptors() { return descriptors; @@ -124,14 +146,14 @@ if (descriptors[i].getName().equals(name)) return descriptors[i]; } - + return null; } /** * Get the type class for the field with the specified QName. */ - public Type getType(QName name) + public Type getType(QName name) { // 1. Try a prexisting mapped type Type type = (Type) mappedName2type.get(name); @@ -143,11 +165,12 @@ if (typeName != null) { type = getTypeMapping().getType(typeName); - - if (type != null) mapType(name, type); + + if (type != null) + mapType(name, type); } } - + // 3. Create the type from the property descriptor and map it if (type == null) { @@ -158,10 +181,11 @@ } catch (Exception e) { - if(e instanceof XFireRuntimeException) throw (XFireRuntimeException)e; + if (e instanceof XFireRuntimeException) + throw (XFireRuntimeException) e; throw new XFireRuntimeException("Couldn't get properties.", e); } - + if (desc == null) { return null; @@ -171,22 +195,23 @@ { type = getTypeMapping().getTypeCreator().createType(desc); } - catch(XFireRuntimeException e) + catch (XFireRuntimeException e) { - e.prepend("Couldn't create type for property " + desc.getName() - + " on " + getTypeClass()); - + e.prepend("Couldn't create type for property " + desc.getName() + " on " + + getTypeClass()); + throw e; } - - if (registerType(desc)) getTypeMapping().register(type); - + + if (registerType(desc)) + getTypeMapping().register(type); + mapType(name, type); } - - if ( type == null ) - throw new XFireRuntimeException( "Couldn't find type for property " + name ); - + + if (type == null) + throw new XFireRuntimeException("Couldn't find type for property " + name); + return type; } @@ -216,8 +241,9 @@ } /** - * Specifies the name of the property as it shows up in the xml schema. - * This method just returns propertyDescriptor.getName(); + * Specifies the name of the property as it shows up in the xml schema. This + * method just returns propertyDescriptor.getName(); + * * @param desc * @return */ @@ -237,9 +263,10 @@ mappedName2pdName.put(mappedName, property); elements.add(mappedName); } - + /** * Specifies the SchemaType for a particular class. + * * @param mappedName * @param type */ @@ -247,7 +274,7 @@ { mappedName2typeName.put(mappedName, type); } - + private void initializeProperties() { BeanInfo beanInfo = null; @@ -260,7 +287,7 @@ else if (beanClass == Object.class || beanClass == Throwable.class) { } - else if(beanClass == Throwable.class) + else if (beanClass == Throwable.class) { } else if (Throwable.class.isAssignableFrom(beanClass)) @@ -284,10 +311,10 @@ { throw new XFireRuntimeException("Couldn't introspect interface.", e); } - + if (beanInfo != null) descriptors = beanInfo.getPropertyDescriptors(); - + if (descriptors == null) { descriptors = new PropertyDescriptor[0]; @@ -330,14 +357,14 @@ public PropertyDescriptor getPropertyDescriptorFromMappedName(QName name) { - return getPropertyDescriptor( getPropertyNameFromMappedName(name) ); + return getPropertyDescriptor(getPropertyNameFromMappedName(name)); } - + protected boolean isAttribute(PropertyDescriptor desc) { return false; } - + protected boolean isElement(PropertyDescriptor desc) { return true; @@ -353,16 +380,29 @@ return beanClass; } + /** + * Nillable is only allowed if the actual property is Nullable + * @param name + * @return + */ public boolean isNillable(QName name) { - return getType(name).isNillable(); + Type type = getType(name); + if (!type.isNullable()) + return false; + return type.isNillable(); } - + + public int getMinOccurs(QName name) + { + return getType(name).getMinOccurs(); + } + private String getPropertyNameFromMappedName(QName name) { return (String) mappedName2pdName.get(name); } - + public Iterator getAttributes() { return attributes.iterator(); @@ -372,4 +412,25 @@ { return elements.iterator(); } + + public boolean isExtensibleElements() + { + return extensibleElements; + } + + public void setExtensibleElements(boolean futureProof) + { + this.extensibleElements = futureProof; + } + + public boolean isExtensibleAttributes() + { + return extensibleAttributes; + } + + public void setExtensibleAttributes(boolean extensibleAttributes) + { + this.extensibleAttributes = extensibleAttributes; + } + } \ No newline at end of file Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BeanTypePropertyInfo.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BeanTypePropertyInfo.java (revision 0) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BeanTypePropertyInfo.java (revision 0) @@ -0,0 +1,36 @@ +package org.codehaus.xfire.aegis.type.basic; + +/** + * BeanTypePropertyInfo defines attributes of each Property of a Bean + * for use in constructing the Complex Type Schema definition of the Bean + * + * @author Adamn Chesney + * + */ +public class BeanTypePropertyInfo +{ + + private boolean nillable = false; + private int minOccurs = 1; + + public int getMinOccurs() + { + return minOccurs; + } + public void setMinOccurs(int minOccurs) + { + this.minOccurs = minOccurs; + } + public boolean isNillable() + { + return nillable; + } + public void setNillable(boolean nillable) + { + this.nillable = nillable; + } + + + + +} Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BigDecimalType.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BigDecimalType.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BigDecimalType.java (working copy) @@ -17,7 +17,6 @@ public BigDecimalType() { super(); - setNillable(true); } public Object readObject( final MessageReader reader, final MessageContext context ) Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BooleanType.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BooleanType.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/BooleanType.java (working copy) @@ -12,17 +12,7 @@ */ public class BooleanType extends Type -{ - public void setTypeClass(Class typeClass) - { - super.setTypeClass(typeClass); - - if (typeClass.equals(Boolean.class)) - { - setNillable(true); - } - } - +{ public Object readObject(MessageReader reader, MessageContext context) { return new Boolean( reader.getValueAsBoolean() ); Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/DoubleType.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/DoubleType.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/DoubleType.java (working copy) @@ -12,17 +12,7 @@ */ public class DoubleType extends Type -{ - public void setTypeClass(Class typeClass) - { - super.setTypeClass(typeClass); - - if (typeClass.equals(Double.class)) - { - setNillable(true); - } - } - +{ public Object readObject(MessageReader reader, MessageContext context) { return new Double( reader.getValueAsDouble() ); Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/FloatType.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/FloatType.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/FloatType.java (working copy) @@ -13,16 +13,7 @@ public class FloatType extends Type { - public void setTypeClass(Class typeClass) - { - super.setTypeClass(typeClass); - - if (typeClass.equals(Float.class)) - { - setNillable(true); - } - } - + public Object readObject(MessageReader reader, MessageContext context) { return new Float( reader.getValueAsFloat() ); Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/IntType.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/IntType.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/IntType.java (working copy) @@ -13,16 +13,6 @@ public class IntType extends Type { - public void setTypeClass(Class typeClass) - { - super.setTypeClass(typeClass); - - if (typeClass.equals(Integer.class)) - { - setNillable(true); - } - } - public Object readObject(MessageReader reader, MessageContext context) { return new Integer( reader.getValueAsInt() ); Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/LongType.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/LongType.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/LongType.java (working copy) @@ -13,16 +13,7 @@ public class LongType extends Type { - public void setTypeClass(Class typeClass) - { - super.setTypeClass(typeClass); - - if (typeClass.equals(Long.class)) - { - setNillable(true); - } - } - + public Object readObject(MessageReader reader, MessageContext context) { return new Long( reader.getValueAsLong() ); Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/ShortType.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/ShortType.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/ShortType.java (working copy) @@ -13,16 +13,6 @@ public class ShortType extends Type { - public void setTypeClass(Class typeClass) - { - super.setTypeClass(typeClass); - - if (typeClass.equals(Short.class)) - { - setNillable(true); - } - } - public Object readObject(MessageReader reader, MessageContext context) { return new Short( reader.getValue() ); Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/StringType.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/StringType.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/StringType.java (working copy) @@ -13,9 +13,9 @@ public class StringType extends Type { + public StringType() - { - setNillable(true); + { } public Object readObject(MessageReader reader, MessageContext context) Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/XMLBeanTypeInfo.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/XMLBeanTypeInfo.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/basic/XMLBeanTypeInfo.java (working copy) @@ -19,7 +19,11 @@ { private static final Log logger = LogFactory.getLog(XMLBeanTypeInfo.class); private List mappings; - private Map name2Nillable = new HashMap(); + + /** + * Map used for storing meta data about each property + */ + private Map name2PropertyInfo = new HashMap(); public XMLBeanTypeInfo(Class typeClass, List mappings, @@ -67,8 +71,14 @@ String nillableVal = e.getAttributeValue("nillable"); if (nillableVal != null && nillableVal.length() > 0) { - name2Nillable.put(mappedName, Boolean.valueOf(nillableVal)); + ensurePropertyInfo( mappedName ).setNillable( Boolean.valueOf(nillableVal).booleanValue() ); } + + String minOccurs = e.getAttributeValue("minOccurs"); + if ( minOccurs != null && minOccurs.length() > 0 ) + { + ensurePropertyInfo( mappedName).setMinOccurs( Integer.parseInt( minOccurs ) ); + } } try @@ -110,13 +120,54 @@ return null; } - + + /** + * Grab Nillable by looking in PropertyInfo map + * if no entry found, revert to parent class + */ public boolean isNillable(QName name) { - Boolean nillable = (Boolean) name2Nillable.get(name); - - if (nillable != null) return nillable.booleanValue(); - + BeanTypePropertyInfo info = getPropertyInfo( name ); + if ( info != null ) return info.isNillable(); return super.isNillable(name); - } + } + + /** + * Grab Min Occurs by looking in PropertyInfo map + * if no entry found, revert to parent class + */ + public int getMinOccurs (QName name) + { + BeanTypePropertyInfo info = getPropertyInfo( name ); + if ( info != null ) return info.getMinOccurs(); + return super.getMinOccurs( name ); + } + + + /** + * Grab the Property Info for the given property + * @param name + * @return the BeanTypePropertyInfo for the property or NULL if none found + */ + private BeanTypePropertyInfo getPropertyInfo (QName name) + { + return (BeanTypePropertyInfo) name2PropertyInfo.get( name ); + } + + /** + * Grab the Property Info for the given property but if not found + * create one and add it to the map + * @param name + * @return the BeanTypePropertyInfo for the property + */ + private BeanTypePropertyInfo ensurePropertyInfo (QName name) + { + BeanTypePropertyInfo result = getPropertyInfo( name ); + if ( result == null ) + { + result = new BeanTypePropertyInfo(); + name2PropertyInfo.put( name, result ); + } + return result; + } } Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/DefaultTypeCreator.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/DefaultTypeCreator.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/DefaultTypeCreator.java (working copy) @@ -6,14 +6,17 @@ import org.codehaus.xfire.XFireRuntimeException; import org.codehaus.xfire.aegis.type.basic.BeanType; -public class DefaultTypeCreator extends AbstractTypeCreator +public class DefaultTypeCreator + extends AbstractTypeCreator { public TypeClassInfo createClassInfo(Method m, int index) { TypeClassInfo info = new TypeClassInfo(); - if(index >= 0) info.setTypeClass(m.getParameterTypes()[index]); - else info.setTypeClass(m.getReturnType()); + if (index >= 0) + info.setTypeClass(m.getParameterTypes()[index]); + else + info.setTypeClass(m.getReturnType()); return info; } @@ -25,14 +28,14 @@ public Type createCollectionType(TypeClassInfo info) { - if(info.getGenericType() == null) + if (info.getGenericType() == null) { - throw new XFireRuntimeException("Cannot create mapping for " + - info.getTypeClass().getName() + - ", unspecified component type for " + info.getDescription()); + throw new XFireRuntimeException("Cannot create mapping for " + + info.getTypeClass().getName() + ", unspecified component type for " + + info.getDescription()); } - return createCollectionType(info, (Class)info.getGenericType()); + return createCollectionType(info, (Class) info.getGenericType()); } public Type createDefaultType(TypeClassInfo info) @@ -41,7 +44,7 @@ type.setSchemaType(createQName(info.getTypeClass())); type.setTypeClass(info.getTypeClass()); type.setTypeMapping(getTypeMapping()); - + setDefaults( type ); return type; } } Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/DefaultTypeMappingRegistry.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/DefaultTypeMappingRegistry.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/DefaultTypeMappingRegistry.java (working copy) @@ -43,40 +43,74 @@ /** * The default implementation of TypeMappingRegistry. - * + * * @author Dan Diephouse * @since Feb 22, 2004 */ public class DefaultTypeMappingRegistry - implements TypeMappingRegistry + implements TypeMappingRegistry { private static final Log logger = LogFactory.getLog(DefaultTypeMappingRegistry.class); - - protected static final QName XSD_STRING = new QName(SoapConstants.XSD, "string", SoapConstants.XSD_PREFIX); - protected static final QName XSD_LONG = new QName(SoapConstants.XSD, "long", SoapConstants.XSD_PREFIX); - protected static final QName XSD_FLOAT = new QName(SoapConstants.XSD, "float", SoapConstants.XSD_PREFIX); - protected static final QName XSD_DOUBLE = new QName(SoapConstants.XSD, "double", SoapConstants.XSD_PREFIX); - protected static final QName XSD_INT = new QName(SoapConstants.XSD, "int", SoapConstants.XSD_PREFIX); - protected static final QName XSD_SHORT = new QName(SoapConstants.XSD, "short", SoapConstants.XSD_PREFIX); - protected static final QName XSD_BOOLEAN = new QName(SoapConstants.XSD, "boolean", SoapConstants.XSD_PREFIX); - protected static final QName XSD_DATETIME = new QName(SoapConstants.XSD, "dateTime", SoapConstants.XSD_PREFIX); - protected static final QName XSD_TIME = new QName(SoapConstants.XSD, "dateTime", SoapConstants.XSD_PREFIX); - protected static final QName XSD_BASE64 = new QName(SoapConstants.XSD, "base64Binary", SoapConstants.XSD_PREFIX); - protected static final QName XSD_DECIMAL = new QName(SoapConstants.XSD, "decimal", SoapConstants.XSD_PREFIX); - protected static final QName XSD_URI = new QName(SoapConstants.XSD, "anyURI", SoapConstants.XSD_PREFIX); - protected static final QName XSD_ANY = new QName(SoapConstants.XSD, "anyType", SoapConstants.XSD_PREFIX); + protected static final QName XSD_STRING = new QName(SoapConstants.XSD, "string", + SoapConstants.XSD_PREFIX); + protected static final QName XSD_LONG = new QName(SoapConstants.XSD, "long", + SoapConstants.XSD_PREFIX); + + protected static final QName XSD_FLOAT = new QName(SoapConstants.XSD, "float", + SoapConstants.XSD_PREFIX); + + protected static final QName XSD_DOUBLE = new QName(SoapConstants.XSD, "double", + SoapConstants.XSD_PREFIX); + + protected static final QName XSD_INT = new QName(SoapConstants.XSD, "int", + SoapConstants.XSD_PREFIX); + + protected static final QName XSD_SHORT = new QName(SoapConstants.XSD, "short", + SoapConstants.XSD_PREFIX); + + protected static final QName XSD_BOOLEAN = new QName(SoapConstants.XSD, "boolean", + SoapConstants.XSD_PREFIX); + + protected static final QName XSD_DATETIME = new QName(SoapConstants.XSD, "dateTime", + SoapConstants.XSD_PREFIX); + + protected static final QName XSD_TIME = new QName(SoapConstants.XSD, "dateTime", + SoapConstants.XSD_PREFIX); + + protected static final QName XSD_BASE64 = new QName(SoapConstants.XSD, "base64Binary", + SoapConstants.XSD_PREFIX); + + protected static final QName XSD_DECIMAL = new QName(SoapConstants.XSD, "decimal", + SoapConstants.XSD_PREFIX); + + protected static final QName XSD_URI = new QName(SoapConstants.XSD, "anyURI", + SoapConstants.XSD_PREFIX); + + protected static final QName XSD_ANY = new QName(SoapConstants.XSD, "anyType", + SoapConstants.XSD_PREFIX); + protected static final String ENCODED_NS = Soap11.getInstance().getSoapEncodingStyle(); + protected static final QName ENCODED_STRING = new QName(ENCODED_NS, "string"); + protected static final QName ENCODED_LONG = new QName(ENCODED_NS, "long"); + protected static final QName ENCODED_FLOAT = new QName(ENCODED_NS, "float"); + protected static final QName ENCODED_DOUBLE = new QName(ENCODED_NS, "double"); + protected static final QName ENCODED_INT = new QName(ENCODED_NS, "int"); + protected static final QName ENCODED_SHORT = new QName(ENCODED_NS, "short"); + protected static final QName ENCODED_BOOLEAN = new QName(ENCODED_NS, "boolean"); + protected static final QName ENCODED_DATETIME = new QName(ENCODED_NS, "dateTime"); + protected static final QName ENCODED_BASE64 = new QName(ENCODED_NS, "base64Binary"); + protected static final QName ENCODED_DECIMAL = new QName(ENCODED_NS, "decimal"); private Hashtable registry; @@ -84,7 +118,15 @@ private TypeMapping defaultTM; private TypeCreator typeCreator; - + + private boolean defaultExtensibleElements = true; + + private boolean defaultExtensibleAttributes = true; + + private boolean defaultNillable = true; + + private int defaultMinOccurs = 0; + public DefaultTypeMappingRegistry() { this(false); @@ -94,13 +136,13 @@ { this(null, createDefault); } - + public DefaultTypeMappingRegistry(TypeCreator typeCreator, boolean createDefault) { registry = new Hashtable(); - + this.typeCreator = typeCreator; - + if (createDefault) { createDefaultMappings(); @@ -156,7 +198,8 @@ } /** - * @see org.codehaus.xfire.aegis.type.TypeMappingRegistry#createTypeMapping(String, boolean) + * @see org.codehaus.xfire.aegis.type.TypeMappingRegistry#createTypeMapping(String, + * boolean) */ public TypeMapping createTypeMapping(String parentNamespace, boolean autoTypes) { @@ -166,9 +209,10 @@ protected TypeMapping createTypeMapping(TypeMapping parent, boolean autoTypes) { CustomTypeMapping tm = new CustomTypeMapping(parent); - - if (autoTypes) tm.setTypeCreator(getTypeCreator()); - + + if (autoTypes) + tm.setTypeCreator(getTypeCreator()); + return tm; } @@ -176,9 +220,9 @@ { if (typeCreator == null) { - typeCreator = createTypeCreator(); + typeCreator = createTypeCreator(); } - + return typeCreator; } @@ -190,45 +234,69 @@ protected TypeCreator createTypeCreator() { AbstractTypeCreator xmlCreator = createRootTypeCreator(); - xmlCreator.setNextCreator(new DefaultTypeCreator()); + xmlCreator.setNextCreator(createDefaultTypeCreator()); if (isJDK5andAbove()) { try { String j5TC = "org.codehaus.xfire.aegis.type.java5.Java5TypeCreator"; - + Class clazz = ClassLoaderUtils.loadClass(j5TC, getClass()); - + AbstractTypeCreator j5Creator = (AbstractTypeCreator) clazz.newInstance(); - j5Creator.setNextCreator(new DefaultTypeCreator()); - + setDefaults(j5Creator); + j5Creator.setNextCreator(createDefaultTypeCreator()); + xmlCreator.setNextCreator(j5Creator); } catch (Throwable t) { - logger.info("Couldn't find Java 5 module on classpath. Annotation mappings will not be supported."); - + logger + .info("Couldn't find Java 5 module on classpath. Annotation mappings will not be supported."); + if (!(t instanceof ClassNotFoundException)) logger.debug("Error loading Java 5 module", t); } } - + return xmlCreator; } boolean isJDK5andAbove() { - String v = System.getProperty("java.class.version","44.0"); - return ("49.0".compareTo(v) <= 0); + String v = System.getProperty("java.class.version", "44.0"); + return ("49.0".compareTo(v) <= 0); } - + protected AbstractTypeCreator createRootTypeCreator() { - return new XMLTypeCreator(); + AbstractTypeCreator result = new XMLTypeCreator(); + setDefaults(result); + return result; } - + + protected AbstractTypeCreator createDefaultTypeCreator() + { + AbstractTypeCreator result = new DefaultTypeCreator(); + setDefaults(result); + return result; + } + /** + * Set defaults on Type Creator + * + * @param typeCreator + */ + protected void setDefaults(AbstractTypeCreator typeCreator) + { + typeCreator.setDefaultExtensibleElements(isDefaultExtensibleElements()); + typeCreator.setDefaultExtensibleAttributes(isDefaultExtensibleAttributes()); + typeCreator.setDefaultNillable(isDefaultNillable()); + typeCreator.setDefaultMinOccurs(getDefaultMinOccurs()); + } + + /** * @see org.codehaus.xfire.aegis.type.TypeMappingRegistry#unregisterTypeMapping(java.lang.String) */ public TypeMapping unregisterTypeMapping(String encodingStyleURI) @@ -338,8 +406,8 @@ soapTM.register(Calendar.class, XSD_DATETIME, new CalendarType()); soapTM.register(byte[].class, XSD_BASE64, new Base64Type()); soapTM.register(BigDecimal.class, XSD_DECIMAL, new BigDecimalType()); - soapTM.register(URI.class, XSD_URI, new URIType()); - soapTM.register(Document.class, XSD_ANY, new DocumentType()); + soapTM.register(URI.class, XSD_URI, new URIType()); + soapTM.register(Document.class, XSD_ANY, new DocumentType()); soapTM.register(Source.class, XSD_ANY, new SourceType()); soapTM.register(XMLStreamReader.class, XSD_ANY, new XMLStreamReaderType()); soapTM.register(Element.class, XSD_ANY, new JDOMElementType()); @@ -349,4 +417,45 @@ return tm; } + + public boolean isDefaultExtensibleAttributes() + { + return defaultExtensibleAttributes; + } + + public void setDefaultExtensibleAttributes(boolean defaultExtensibleAttributes) + { + this.defaultExtensibleAttributes = defaultExtensibleAttributes; + } + + public boolean isDefaultExtensibleElements() + { + return defaultExtensibleElements; + } + + public void setDefaultExtensibleElements(boolean defaultExtensibleElements) + { + this.defaultExtensibleElements = defaultExtensibleElements; + } + + public int getDefaultMinOccurs() + { + return defaultMinOccurs; + } + + public void setDefaultMinOccurs(int defaultMinOccurs) + { + this.defaultMinOccurs = defaultMinOccurs; + } + + public boolean isDefaultNillable() + { + return defaultNillable; + } + + public void setDefaultNillable(boolean defaultNillable) + { + this.defaultNillable = defaultNillable; + } + } Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/Type.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/Type.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/Type.java (working copy) @@ -22,7 +22,9 @@ private TypeMapping typeMapping; private Class typeClass; private boolean abstrct = true; + private boolean nullable = true; private boolean nillable = false; + private int minOccurs = 1; private boolean writeOuter = true; public Type() @@ -68,7 +70,11 @@ */ public void setTypeClass( Class typeClass ) { - this.typeClass = typeClass; + this.typeClass = typeClass; + if ( typeClass.isPrimitive() ) + { + setNullable( false ); + } } /** @@ -88,7 +94,17 @@ { this.abstrct = abstrct; } - + + public boolean isNullable() + { + return nullable; + } + + public void setNullable(boolean nullable) + { + this.nullable = nullable; + } + public boolean isNillable() { return nillable; @@ -99,6 +115,16 @@ this.nillable = nillable; } + public int getMinOccurs() + { + return minOccurs; + } + + public void setMinOccurs(int minOccurs) + { + this.minOccurs = minOccurs; + } + /** * Return a set of Type dependencies. Returns null if this type * has no dependencies. Index: F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/XMLTypeCreator.java =================================================================== --- F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/XMLTypeCreator.java (revision 1316) +++ F:/work/xfire/xfire-aegis/src/main/org/codehaus/xfire/aegis/type/XMLTypeCreator.java (working copy) @@ -255,6 +255,12 @@ String typeNameAtt = null; if (mapping != null) typeNameAtt = mapping.getAttributeValue("name"); + String extensibleElements = null; + if (mapping != null) extensibleElements = mapping.getAttributeValue("extensibleElements"); + + String extensibleAttributes = null; + if (mapping != null) extensibleAttributes = mapping.getAttributeValue("extensibleAttributes"); + String defaultNS = NamespaceHelper.makeNamespaceFromClassName(info.getTypeClass().getName(), "http"); QName name = null; if (typeNameAtt != null) @@ -268,6 +274,8 @@ mappings, defaultNS); btinfo.setTypeMapping(getTypeMapping()); + if ( extensibleElements != null ) btinfo.setExtensibleElements( Boolean.valueOf( extensibleElements ).booleanValue() ); + if ( extensibleAttributes != null ) btinfo.setExtensibleAttributes( Boolean.valueOf( extensibleAttributes ).booleanValue() ); BeanType type = new BeanType(btinfo);