/**
         * Response from the soap call. Pulls the object from the wrapper object and returns it.
         *
         * @return response from the soap call.
         * @throws SoapFault
         * @since 2.0.3
         */

        public Object getResponse()
        {
            if (bodyIn == null)
            {
                return(null);
            }
            if (bodyIn is SoapFault)
            {
                throw (SoapFault)bodyIn;
            }
            FvmSerializable ks = (FvmSerializable)bodyIn;

            if (ks.getPropertyCount() == 0)
            {
                return(null);
            }
            else if (ks.getPropertyCount() == 1)
            {
                return(ks.getProperty(0));
            }
            else
            {
                List <object> ret = new List <object>();
                for (int i = 0; i < ks.getPropertyCount(); i++)
                {
                    ret.Add(ks.getProperty(i));
                }
                return(ret);
            }
        }
        /**
         * Writes the body of an FvmSerializable object. This method is public for access from Marshal subclasses.
         */

        public void writeObjectBody(XmlSerializer writer, FvmSerializable obj)
        {
            int          cnt          = obj.getPropertyCount();
            PropertyInfo propertyInfo = new PropertyInfo();
            String       namespace_;
            String       name;
            String       type;

            for (int i = 0; i < cnt; i++)
            {
                // get the property
                Object prop = obj.getProperty(i);
                // and importantly also get the property info which holds the name potentially!
                obj.getPropertyInfo(i, properties, propertyInfo);

                if (!(prop is SoapObject))
                {
                    // prop is a PropertyInfo
                    if ((propertyInfo.flags & PropertyInfo.TRANSIENT) == 0)
                    {
                        Object objValue = obj.getProperty(i);
                        if ((prop != null || !skipNullProperties) && (objValue != SoapPrimitive.NullSkip))
                        {
                            writer.startTag(propertyInfo.namespace_, propertyInfo.name);
                            writeProperty(writer, objValue, propertyInfo);
                            writer.endTag(propertyInfo.namespace_, propertyInfo.name);
                        }
                    }
                }
                else
                {
                    // prop is a SoapObject
                    SoapObject nestedSoap = (SoapObject)prop;
                    // lets get the info from the soap object itself
                    Object[] qName = getInfo(null, nestedSoap);
                    namespace_ = (String)qName[QNAME_NAMESPACE];
                    type       = (String)qName[QNAME_TYPE];

                    // prefer the name from the property info
                    if (propertyInfo.name != null && propertyInfo.name.Length > 0)
                    {
                        name = propertyInfo.name;
                    }
                    else
                    {
                        name = (String)qName[QNAME_TYPE];
                    }

                    // prefer the namespace_ from the property info
                    if (propertyInfo.namespace_ != null && propertyInfo.namespace_.Length > 0)
                    {
                        namespace_ = propertyInfo.namespace_;
                    }
                    else
                    {
                        namespace_ = (String)qName[QNAME_NAMESPACE];
                    }

                    writer.startTag(namespace_, name);
                    if (!implicitTypes)
                    {
                        String prefix = writer.getPrefix(namespace_, true);
                        writer.attribute(xsi, TYPE_LABEL, prefix + ":" + type);
                    }
                    writeObjectBodyWithAttributes(writer, nestedSoap);
                    writer.endTag(namespace_, name);
                }
            }
            if (obj is HasInnerText)
            {
                if (((HasInnerText)obj).getInnerText() != null)
                {
                    writer.cdsect(((HasInnerText)obj).getInnerText());
                }
            }
        }
        /**
         * Read a FvmSerializable.
         */

        protected void readSerializable(XmlPullParser parser, FvmSerializable obj)
        {
            int tag = 0;

            try
            {
                tag = parser.nextTag();
            }
            catch (XmlPullParserException e)
            {
                if (obj is HasInnerText)
                {
                    ((HasInnerText)obj).setInnerText((parser.getText() != null) ? parser.getText() : "");
                }
                tag = parser.nextTag();
            }
            while (tag != XmlPullParser.END_TAG)
            {
                String name = parser.getName();
                if (!implicitTypes || !(obj is SoapObject))
                {
                    PropertyInfo info          = new PropertyInfo();
                    int          propertyCount = obj.getPropertyCount();
                    bool         propertyFound = false;

                    for (int i = 0; i < propertyCount && !propertyFound; i++)
                    {
                        info.clear();
                        obj.getPropertyInfo(i, properties, info);

                        if ((name.Equals(info.name) && info.namespace_ == null) ||
                            (name.Equals(info.name) && parser.getNamespace().Equals(info.namespace_)))
                        {
                            propertyFound = true;
                            obj.setProperty(i, read(parser, obj, i, null, null, info));
                        }
                    }

                    if (!propertyFound)
                    {
                        if (avoidExceptionForUnknownProperty)
                        {
                            // Dummy loop to read until corresponding END tag
                            while (parser.next() != XmlPullParser.END_TAG || !name.Equals(parser.getName()))
                            {
                            }
                            ;
                        }
                        else
                        {
                            throw new Exception("Unknown Property: " + name);
                        }
                    }
                    else
                    {
                        if (obj is HasAttributes)
                        {
                            HasAttributes soapObject = (HasAttributes)obj;
                            int           cnt        = parser.getAttributeCount();
                            for (int counter = 0; counter < cnt; counter++)
                            {
                                AttributeInfo attributeInfo = new AttributeInfo();
                                attributeInfo.setName(parser.getAttributeName(counter));
                                attributeInfo.setValue(parser.getAttributeValue(counter));
                                attributeInfo.setNamespace(parser.getAttributeNamespace(counter));
                                attributeInfo.setType(parser.getAttributeType(counter));
                                soapObject.setAttribute(attributeInfo);
                            }
                        }
                    }
                }
                else
                {
                    // I can only make this work for SoapObjects - hence the check above
                    // I don't understand namespaces well enough to know whether it is correct in the next line...
                    ((SoapObject)obj).addProperty(parser.getName(), read(parser, obj, obj.getPropertyCount(),
                                                                         ((SoapObject)obj).getNamespace(), name, PropertyInfo.OBJECT_TYPE));
                }
                try
                {
                    tag = parser.nextTag();
                }
                catch (XmlPullParserException e)
                {
                    if (obj is HasInnerText)
                    {
                        ((HasInnerText)obj).setInnerText((parser.getText() != null) ? parser.getText() : "");
                    }
                    tag = parser.nextTag();
                }
            }
            parser.require(XmlPullParser.END_TAG, null, null);
        }