Index: src/main/org/codehaus/xfire/aegis/type/basic/BeanType.java
===================================================================
--- src/main/org/codehaus/xfire/aegis/type/basic/BeanType.java (revision 1455)
+++ src/main/org/codehaus/xfire/aegis/type/basic/BeanType.java (working copy)
@@ -1,10 +1,7 @@
package org.codehaus.xfire.aegis.type.basic;
import java.beans.PropertyDescriptor;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
+import java.lang.reflect.*;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
@@ -25,7 +22,7 @@
/**
* Serializes JavaBeans.
- *
+ *
* @author Dan Diephouse
* @author Jack Hong
*/
@@ -35,17 +32,17 @@
private BeanTypeInfo _info;
private boolean isInterface = false;
private boolean isException = false;
-
+
public BeanType()
{
}
-
+
public BeanType(BeanTypeInfo info)
{
- this._info = info;
+ this._info = info;
this.setTypeClass(info.getTypeClass());
}
-
+
/* (non-Javadoc)
* @see org.codehaus.xfire.aegis.type.Type#readObject(org.codehaus.xfire.aegis.MessageReader, org.codehaus.xfire.MessageContext)
*/
@@ -53,14 +50,14 @@
throws XFireFault
{
BeanTypeInfo info = getTypeInfo();
-
+
try
{
Class clazz = getTypeClass();
Object object = null;
InterfaceInvocationHandler delegate = null;
boolean isProxy = false;
-
+
if (isInterface)
{
String impl = null;
@@ -68,7 +65,7 @@
{
impl = (String) context.getService().getProperty(clazz.getName() + ".implementation");
}
-
+
if (impl == null)
{
delegate = new InterfaceInvocationHandler();
@@ -86,7 +83,7 @@
}
catch (ClassNotFoundException e)
{
- throw new XFireRuntimeException("Could not find implementation class " +
+ throw new XFireRuntimeException("Could not find implementation class " +
impl + " for class " + clazz.getName());
}
}
@@ -105,18 +102,18 @@
{
MessageReader childReader = reader.getNextAttributeReader();
QName name = childReader.getName();
-
+
Type type = info.getType(name);
if (type != null)
{
Object writeObj = type.readObject(childReader, context);
- if (isProxy)
+ if (isProxy)
{
delegate.writeProperty(name.getLocalPart(), writeObj);
}
- else
+ else
{
writeProperty(name, object, writeObj, clazz);
}
@@ -137,11 +134,11 @@
{
Object writeObj = type.readObject(childReader, context);
- if (isProxy)
+ if (isProxy)
{
delegate.writeProperty(name.getLocalPart(), writeObj);
}
- else
+ else
{
writeProperty(name, object, writeObj, clazz);
}
@@ -162,7 +159,7 @@
childReader.readToEnd();
}
}
-
+
return object;
}
catch (IllegalAccessException e)
@@ -191,7 +188,7 @@
* If the class is an exception, this will try and instantiate it with information
* from the XFireFault (if it exists).
*/
- protected Object createFromFault(MessageContext context)
+ protected Object createFromFault(MessageContext context)
throws SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
Class clazz = getTypeClass();
@@ -199,9 +196,9 @@
Object o;
Object body = context.getExchange().getFaultMessage().getBody();
- if (!(body instanceof XFireFault))
+ if (!(body instanceof XFireFault))
return clazz.newInstance();
-
+
XFireFault fault = (XFireFault) body;
try
@@ -242,14 +239,14 @@
try
{
PropertyDescriptor desc = getTypeInfo().getPropertyDescriptorFromMappedName(name);
-
+
Method m = desc.getWriteMethod();
-
- if (m == null)
+
+ if (m == null)
{
if (getTypeClass().isInterface())
m = getWriteMethodFromImplClass(impl, desc);
-
+
if (m == null)
throw new XFireFault("No write method for property " + name + " in " + object.getClass(), XFireFault.SENDER);
}
@@ -263,7 +260,7 @@
catch (Exception e)
{
if (e instanceof XFireFault) throw (XFireFault) e;
-
+
throw new XFireFault("Couldn't set property " + name + " on " + object + ". " + e.getMessage(), e, XFireFault.SENDER);
}
}
@@ -277,21 +274,21 @@
{
String name = pd.getName();
name = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
-
+
return impl.getMethod(name, new Class[] { pd.getPropertyType() });
}
/**
- * @see org.codehaus.xfire.aegis.type.Type#writeObject(Object, org.codehaus.xfire.aegis.MessageWriter, org.codehaus.xfire.MessageContext)
+ * @see org.codehaus.xfire.aegis.type.Type#writeObject(Object, org.codehaus.xfire.aegis.MessageWriter, org.codehaus.xfire.MessageContext)
*/
public void writeObject(Object object, MessageWriter writer, MessageContext context)
throws XFireFault
{
if (object == null)
return;
-
+
BeanTypeInfo info = getTypeInfo();
-
+
for (Iterator itr = info.getAttributes(); itr.hasNext(); )
{
QName name = (QName) itr.next();
@@ -300,24 +297,24 @@
if (value != null)
{
Type type = getType( info, name );
-
+
if ( type == null )
throw new XFireRuntimeException( "Couldn't find type for " + value.getClass() + " for property " + name );
-
+
MessageWriter cwriter = writer.getAttributeWriter(name);
type.writeObject(value, cwriter, context);
-
+
cwriter.close();
}
}
-
+
for (Iterator itr = info.getElements(); itr.hasNext(); )
{
QName name = (QName) itr.next();
Object value = readProperty(object, name);
-
+
Type type = getType( info, name );
MessageWriter cwriter;
@@ -325,27 +322,27 @@
if ( value != null)
{
cwriter = getWriter(writer, name, type);
-
+
if ( type == null )
throw new XFireRuntimeException( "Couldn't find type for " + value.getClass() + " for property " + name );
type.writeObject(value, cwriter, context);
-
+
cwriter.close();
}
else if (info.isNillable(name))
{
cwriter = getWriter(writer, name, type);
-
+
// Write the xsi:nil if it is null.
cwriter.writeXsiNil();
-
+
cwriter.close();
}
}
}
- private MessageWriter getWriter(MessageWriter writer, QName name, Type type)
+ private MessageWriter getWriter(MessageWriter writer, QName name, Type type)
{
MessageWriter cwriter;
if (type.isAbstract())
@@ -366,7 +363,7 @@
PropertyDescriptor desc = getTypeInfo().getPropertyDescriptorFromMappedName(name);
Method m = desc.getReadMethod();
-
+
if (m == null) throw new XFireFault("No read method for property " + name + " in class " + object.getClass().getName(), XFireFault.SENDER);
return m.invoke(object, new Object[0]);
@@ -378,47 +375,82 @@
}
/**
- * @see org.codehaus.xfire.aegis.type.Type#writeSchema(org.jdom.Element)
+ * @see org.codehaus.xfire.aegis.type.Type#writeSchema(org.jdom.Element)
*/
public void writeSchema(Element root)
{
BeanTypeInfo info = getTypeInfo();
-
+
Element complex = new Element("complexType",
SoapConstants.XSD_PREFIX,
SoapConstants.XSD);
complex.setAttribute(new Attribute("name", getSchemaType().getLocalPart()));
+
+ // Check for abstract classes
+ if(Modifier.isAbstract(info.getTypeClass().getModifiers()))
+ {
+ complex.setAttribute(new Attribute("abstract", "true"));
+ }
+
root.addContent(complex);
+ Type baseType = info.getBaseType();
+ if(baseType != null)
+ {
+ Element content = new Element("complexContent", SoapConstants.XSD_PREFIX, SoapConstants.XSD);
+ complex.addContent(content);
+ Element extension = new Element("extension", SoapConstants.XSD_PREFIX, SoapConstants.XSD);
+
+ QName baseSchemaType = baseType.getSchemaType();
+ String baseName = baseSchemaType.getLocalPart();
+ if(!baseSchemaType.getNamespaceURI().equals(getSchemaType().getNamespaceURI()))
+ {
+ String prefix = NamespaceHelper.getUniquePrefix((Element)root.getParent(), baseSchemaType.getNamespaceURI());
+ baseName = prefix + ":" + baseName;
+ }
+ extension.setAttribute(new Attribute("base", baseName));
+ content.addContent(extension);
+
+ // Shift complex
+ complex = extension;
+ }
+
Element seq = null;
-
+
// Write out schema for elements
for (Iterator itr = info.getElements(); itr.hasNext();)
{
+ QName name = (QName)itr.next();
+
+ if(_info.isInherited(name))
+ {
+ continue;
+ }
+
if (seq == null)
{
seq = new Element("sequence", SoapConstants.XSD_PREFIX, SoapConstants.XSD);
complex.addContent(seq);
}
-
- QName name = (QName) itr.next();
-
+
+
+
Element element = new Element("element",
SoapConstants.XSD_PREFIX,
SoapConstants.XSD);
seq.addContent(element);
-
+
Type type = getType(info, name);
-
- String nameNS = name.getNamespaceURI();
+
+ String nameNS = name.getNamespaceURI();
String nameWithPrefix = getNameWithPrefix(root, nameNS, name.getLocalPart());
-
- String prefix = NamespaceHelper.getUniquePrefix((Element) root.getParent(),
+
+ String prefix = NamespaceHelper.getUniquePrefix((Element) root.getParent(),
type.getSchemaType().getNamespaceURI() );
-
+
writeTypeReference(name, nameWithPrefix, element, type, prefix);
}
-
+
/**
* if future proof then add element
*/
@@ -429,30 +461,33 @@
seq = new Element("sequence", SoapConstants.XSD_PREFIX, SoapConstants.XSD);
complex.addContent(seq);
}
- seq.addContent( createAnyElement () );
+ seq.addContent( createAnyElement () );
}
-
+
// Write out schema for attributes
for (Iterator itr = info.getAttributes(); itr.hasNext();)
{
QName name = (QName) itr.next();
-
- Element element = new Element("attribute",
- SoapConstants.XSD_PREFIX,
- SoapConstants.XSD);
+
+ if(_info.isInherited(name))
+ {
+ continue;
+ }
+
+ Element element = new Element("attribute", SoapConstants.XSD_PREFIX, SoapConstants.XSD);
complex.addContent(element);
-
+
Type type = getType(info, name);
- String nameNS = name.getNamespaceURI();
+ String nameNS = name.getNamespaceURI();
String nameWithPrefix = getNameWithPrefix(root, nameNS, name.getLocalPart());
- String prefix = NamespaceHelper.getUniquePrefix((Element) root.getParent(),
+ String prefix = NamespaceHelper.getUniquePrefix((Element) root.getParent(),
type.getSchemaType().getNamespaceURI() );
element.setAttribute(new Attribute("name", nameWithPrefix));
element.setAttribute(new Attribute("type", prefix + ':' + type.getSchemaType().getLocalPart()));
}
-
+
/**
* If extensible attributes then add
*/
@@ -467,7 +502,7 @@
if (!nameNS.equals(getSchemaType().getNamespaceURI()))
{
String prefix = NamespaceHelper.getUniquePrefix((Element) root.getParent(), nameNS);
- if (prefix != null && prefix.length() > 0)
+ if (prefix != null && prefix.length() > 0)
return prefix + ":" + localName;
}
return localName;
@@ -476,13 +511,13 @@
private Type getType(BeanTypeInfo info, QName name)
{
Type type = info.getType(name);
-
+
if (type == null)
{
- throw new NullPointerException("Couldn't find type for" + name + " in class " +
+ throw new NullPointerException("Couldn't find type for" + name + " in class " +
getTypeClass().getName());
}
-
+
return type;
}
@@ -492,13 +527,13 @@
{
element.setAttribute(new Attribute("name", nameWithPrefix));
element.setAttribute(new Attribute("type", prefix + ':' + type.getSchemaType().getLocalPart()));
-
+
int minOccurs = getTypeInfo().getMinOccurs(name);
if ( minOccurs != 1 )
{
element.setAttribute(new Attribute("minOccurs", new Integer(minOccurs).toString()));
}
-
+
if (getTypeInfo().isNillable(name))
{
element.setAttribute(new Attribute("nillable", "true"));
@@ -509,18 +544,18 @@
element.setAttribute(new Attribute("ref", prefix + ':' + type.getSchemaType().getLocalPart()));
}
}
-
+
public void setTypeClass(Class typeClass)
{
super.setTypeClass(typeClass);
-
+
isInterface = typeClass.isInterface();
isException = Exception.class.isAssignableFrom(typeClass);
}
/**
* We need to write a complex type schema for Beans, so return true.
- *
+ *
* @see org.codehaus.xfire.aegis.type.Type#isComplex()
*/
public boolean isComplex()
@@ -533,7 +568,13 @@
Set deps = new HashSet();
BeanTypeInfo info = getTypeInfo();
-
+
+ Type baseType = info.getBaseType();
+ if(baseType != null)
+ {
+ deps.add(baseType);
+ }
+
for (Iterator itr = info.getAttributes(); itr.hasNext(); )
{
QName name = (QName) itr.next();
@@ -547,7 +588,7 @@
deps.add(info.getType(name));
}
-
+
return deps;
}
@@ -557,26 +598,26 @@
{
_info = createTypeInfo();
}
-
+
// Delay initialization so things work in recursive scenarios (XFIRE-117)
if (!_info.isInitialized())
{
_info.initialize();
}
-
+
return _info;
}
public BeanTypeInfo createTypeInfo()
{
- BeanTypeInfo info = new BeanTypeInfo(getTypeClass(),
+ BeanTypeInfo info = new BeanTypeInfo(getTypeClass(),
getSchemaType().getNamespaceURI());
info.setTypeMapping(getTypeMapping());
return info;
}
-
+
/**
* Create an element to represent any future elements
* that might get added to the schema
@@ -589,10 +630,10 @@
SoapConstants.XSD_PREFIX,
SoapConstants.XSD);
result.setAttribute(new Attribute("minOccurs", "0"));
- result.setAttribute(new Attribute("maxOccurs", "unbounded"));
+ result.setAttribute(new Attribute("maxOccurs", "unbounded"));
return result;
}
-
+
/**
* Create an element to represent any future attributes
* that might get added to the schema
@@ -603,8 +644,8 @@
{
Element result = new Element("anyAttribute",
SoapConstants.XSD_PREFIX,
- SoapConstants.XSD);
+ SoapConstants.XSD);
return result;
}
-
+
}
Index: src/main/org/codehaus/xfire/aegis/type/basic/BeanTypeInfo.java
===================================================================
--- src/main/org/codehaus/xfire/aegis/type/basic/BeanTypeInfo.java (revision 1455)
+++ src/main/org/codehaus/xfire/aegis/type/basic/BeanTypeInfo.java (working copy)
@@ -4,11 +4,7 @@
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import javax.xml.namespace.QName;
@@ -26,10 +22,18 @@
private Class beanClass;
+ private Class baseClass;
+
+ private BeanInfo baseBeanInfo;
+
+ private Type baseType;
+
private List attributes = new ArrayList();
private List elements = new ArrayList();
+ private Set inheritedProperties = new HashSet();
+
private PropertyDescriptor[] descriptors;
private TypeMapping typeMapping;
@@ -39,9 +43,9 @@
private String defaultNamespace;
private int minOccurs = 0;
-
+
private boolean nillable = true;
-
+
/**
* extensibleElements means adding xs:any to WSDL Complex Type Definition
*/
@@ -63,7 +67,7 @@
/**
* Create a BeanTypeInfo class.
- *
+ *
* @param typeClass
* @param defaultNamespace
* @param initiallize
@@ -108,10 +112,7 @@
public boolean isMapped(PropertyDescriptor pd)
{
- if (pd.getReadMethod() == null)
- return false;
-
- return true;
+ return pd.getReadMethod() != null;
}
public boolean isInitialized()
@@ -224,6 +225,20 @@
return true;
}
+ public Type getBaseType()
+ {
+ if(baseType == null && baseClass != null)
+ {
+ TypeMapping tm = getTypeMapping();
+ baseType = tm.getType(baseClass);
+ if(baseType == null)
+ {
+ baseType = tm.getTypeCreator().createType(baseClass);
+ }
+ }
+ return baseType;
+ }
+
public void mapType(QName name, Type type)
{
mappedName2type.put(name, type);
@@ -247,7 +262,7 @@
/**
* Specifies the name of the property as it shows up in the xml schema. This
* method just returns propertyDescriptor.getName();
- *
+ *
* @param desc
* @return
*/
@@ -260,17 +275,51 @@
{
mappedName2pdName.put(mappedName, property);
attributes.add(mappedName);
+ mapInheritance(property, mappedName);
}
public void mapElement(String property, QName mappedName)
{
mappedName2pdName.put(mappedName, property);
elements.add(mappedName);
+ mapInheritance(property, mappedName);
}
+ protected void mapInheritance(String property, QName mappedName)
+ {
+ if(isInherited(property))
+ {
+ inheritedProperties.add(mappedName);
+ }
+ }
+
+ public boolean isInherited(QName mappedName)
+ {
+ return inheritedProperties.contains(mappedName);
+ }
+
+ protected boolean isInherited(String property)
+ {
+ if(baseClass != null)
+ {
+ PropertyDescriptor[] pds = baseBeanInfo.getPropertyDescriptors();
+ if(pds != null)
+ {
+ for(int i = 0; i < pds.length; i++)
+ {
+ if(pds[i].getName().equals(property))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
/**
* Specifies the SchemaType for a particular class.
- *
+ *
* @param mappedName
* @param type
*/
@@ -309,6 +358,12 @@
else
{
beanInfo = Introspector.getBeanInfo(beanClass, Object.class);
+ Class superclass = beanClass.getSuperclass();
+ if(superclass != Object.class)
+ {
+ baseClass = superclass;
+ baseBeanInfo = Introspector.getBeanInfo(baseClass, Object.class);
+ }
}
}
catch (IntrospectionException e)
@@ -405,7 +460,7 @@
{
this.minOccurs = minOccurs;
}
-
+
public void setDefaultNillable (boolean nillable)
{
this.nillable = nillable;