You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by Vikram Roopchand <vi...@infosys.com> on 2004/06/24 08:21:25 UTC

Possible Bug : Xsd type and Arrays : Axis 1.2 Beta

Hi,
   we are facing a peculiar problem. We have a setter and getter for
java.lang.Object[], something like this :-

void setValues(Object[] values);
Object[] getValues();

We use this to send/receive arrays of any type
(Integer,String,Float,MyClassA,YourClassB). WSDL generated for such code
via java2WSDL has array of xsd:anyType for this, which is okay.

When the SOAP xml(via RPC) is sent from the Client (using Axis) it gets
represented by it's XSD type for e.g.:-

Please look at "values" element.

<multiRef id="id19" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns17="http://localhost:8080/Contentbiz/sysTypes"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns17:CBAttributeValue">

  <name xsi:type="xsd:string">ct_NoOfEmployees</name> 

  <dataType href="#id30" /> 

  <values soapenc:arrayType="xsd:int[2]" xsi:type="soapenc:Array">

  <item>12</item> 

  <item>14</item> 

  </values>

  <multipleValues xsi:type="soapenc:boolean">true</multipleValues> 

  <validValue xsi:type="soapenc:boolean">true</validValue> 

  <isDirty xsi:type="soapenc:boolean">false</isDirty> 

  </multiRef>


Our system is built in such a way that we use the Getter on the Server
end and the "Type" (also sent from the client) and work with the Array
so returned .
Somewhat like:-

//identify the data type
DataType dataType = deserializedObject.getDataType();

//retrieve the "typed" array
getTypedArray(dataType,deserializedObject.getValues());

Now comes our problem :-

For all the Types which are our types (MyClassA,MyClassB) , the
deserialiazedObject contains an array of the proper type , getValues
will return an array of MyClassA objects.

For Other types like Integer/Float/Boolean (not String) it is returning
Object[] having the properly typed values within, which results for us
into a ClassCastException for us when we use our getTypedArray method
(this method assumes that Axis will return the correctly typed array).

The Subsystem (Axis) in BeanPropertyTarget.set() handles it in such a
way:-

 try {
            // Set the value on the bean property. 
            // Use the indexed property method if the 
            // index is set.
            if (index < 0) {
                pd.set(object, value);
            } else {
                pd.set(object, index, value);
            }
        } catch (Exception e) {

            try {
                // If an exception occurred, 
                // see it the value can be converted into
                // the expected type.
                Class type = pd.getType();
                
                if (JavaUtils.isConvertable(value, type)) {
                    value = JavaUtils.convert(value, type);
                    if (index < 0)
                        pd.set(object, value);
                    else
                        pd.set(object, index, value);
                } else {
                    // It is possible that an indexed
                    // format was expected, but the
                    // entire array was sent.  In such 
                    // cases traverse the array and 
                    // call the setter for each item.
                    if (index == 0 &&
                        value.getClass().isArray() &&
                        !type.getClass().isArray()) {
                        for (int i=0; i<Array.getLength(value); i++) {
                            Object item = 
                                JavaUtils.convert(Array.get(value, i),
type);
                            pd.set(object, i, item); 
                        }
                    } else {
                        // Can't proceed.  Throw an exception that
                        // will be caught in the catch block below.
                        throw e;
                    }
                }


In the CATCH block (It will come here for all basic xsd types , as code
executed before it in ArrayListExtension marks it to be a int[] array
and the setValues(Object[]) will fail with IllegalArgumentException), it
is attempted to figure out the Type and Convert it to the one in the
BeanPropertyDescriptor (which for us is Object[] class, which is okay
since it is an anyType). But there is a small deviation , instead of
identifying the underlying type (if it is an array) , CATCH block
creates an array of Object[] and fills it up with the values of correct
type. This results in the deserilialzedObject.getValues() resulting in
an Object[] array instead of an Integer[] (as expected). 

This is a discrepancy as for some XSD types like xsd:string,
xsd:dateTime it returns String[]/Calendar[] but for
xsd:int,xsd:float,xsd:boolean etc. it does not.

We would like to confirm whether or not do you consider this as a bug ,
we did a slight modification to CATCH BeanPropertyTarget and everthing
was working fine , :- 


catch {
                // If an exception occurred, 
                // see it the value can be converted into
                // the expected type.
                Class type = pd.getType();
                
                //Vikram - INFY - START
                if (value.getClass().isArray() &&
value.getClass().getComponentType().isPrimitive() 
                	&& type.isArray() &&
type.getComponentType().equals(Object.class))
                {
                	//we make our own array type here.
                	type =
Array.newInstance(JavaUtils.getWrapperClass(value.getClass().getComponen
tType()),0).getClass();
                }
                //Vikram - INFY - END 

                if (JavaUtils.isConvertable(value, type)) {
                    value = JavaUtils.convert(value, type);
                    if (index < 0)
                        pd.set(object, value);
                    else
                        pd.set(object, index, value);
                } else {
                    // It is possible that an indexed
                    // format was expected, but the
                    // entire array was sent.  In such 
                    // cases traverse the array and 
                    // call the setter for each item.
                    if (index == 0 &&
                        value.getClass().isArray() &&
                        !type.getClass().isArray()) {
                        for (int i=0; i<Array.getLength(value); i++) {
                            Object item = 
                                JavaUtils.convert(Array.get(value, i),
type);
                            pd.set(object, i, item); 
                        }
                    } else {
                        // Can't proceed.  Throw an exception that
                        // will be caught in the catch block below.
                        throw e;
                    }
              }


Only for primitive Arrays,We change the "type" to take in the underlying
type of the "value" array. This will work only for primitive arrays and
only when the bd has "type" set to Object[] (anytype).

I would appreciate a quick response from your side as most of our system
depends on this functionality.

Thanks a lot,
Vikram Roopchand
Programmwer Analyst,
INFOSYS Technologies Ltd. - Pune.
India


Re: Possible Bug : Xsd type and Arrays : Axis 1.2 Beta

Posted by Davanum Srinivas <da...@gmail.com>.
Are u using a nightly build? if so, please report this as a bug in
JIRA with some sample code to recreate the problem

thanks,
dims

On Thu, 24 Jun 2004 11:51:25 +0530, Vikram Roopchand
<vi...@infosys.com> wrote:
> 
> Hi,
>    we are facing a peculiar problem. We have a setter and getter for
> java.lang.Object[], something like this :-
> 
> void setValues(Object[] values);
> Object[] getValues();
> 
> We use this to send/receive arrays of any type
> (Integer,String,Float,MyClassA,YourClassB). WSDL generated for such code
> via java2WSDL has array of xsd:anyType for this, which is okay.
> 
> When the SOAP xml(via RPC) is sent from the Client (using Axis) it gets
> represented by it's XSD type for e.g.:-
> 
> Please look at "values" element.
> 
> <multiRef id="id19" soapenc:root="0"
> soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
> xmlns:ns17="http://localhost:8080/Contentbiz/sysTypes"
> xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
> xsi:type="ns17:CBAttributeValue">
> 
>   <name xsi:type="xsd:string">ct_NoOfEmployees</name>
> 
>   <dataType href="#id30" />
> 
>   <values soapenc:arrayType="xsd:int[2]" xsi:type="soapenc:Array">
> 
>   <item>12</item>
> 
>   <item>14</item>
> 
>   </values>
> 
>   <multipleValues xsi:type="soapenc:boolean">true</multipleValues>
> 
>   <validValue xsi:type="soapenc:boolean">true</validValue>
> 
>   <isDirty xsi:type="soapenc:boolean">false</isDirty>
> 
>   </multiRef>
> 
> Our system is built in such a way that we use the Getter on the Server
> end and the "Type" (also sent from the client) and work with the Array
> so returned .
> Somewhat like:-
> 
> //identify the data type
> DataType dataType = deserializedObject.getDataType();
> 
> //retrieve the "typed" array
> getTypedArray(dataType,deserializedObject.getValues());
> 
> Now comes our problem :-
> 
> For all the Types which are our types (MyClassA,MyClassB) , the
> deserialiazedObject contains an array of the proper type , getValues
> will return an array of MyClassA objects.
> 
> For Other types like Integer/Float/Boolean (not String) it is returning
> Object[] having the properly typed values within, which results for us
> into a ClassCastException for us when we use our getTypedArray method
> (this method assumes that Axis will return the correctly typed array).
> 
> The Subsystem (Axis) in BeanPropertyTarget.set() handles it in such a
> way:-
> 
>  try {
>             // Set the value on the bean property.
>             // Use the indexed property method if the
>             // index is set.
>             if (index < 0) {
>                 pd.set(object, value);
>             } else {
>                 pd.set(object, index, value);
>             }
>         } catch (Exception e) {
> 
>             try {
>                 // If an exception occurred,
>                 // see it the value can be converted into
>                 // the expected type.
>                 Class type = pd.getType();
> 
>                 if (JavaUtils.isConvertable(value, type)) {
>                     value = JavaUtils.convert(value, type);
>                     if (index < 0)
>                         pd.set(object, value);
>                     else
>                         pd.set(object, index, value);
>                 } else {
>                     // It is possible that an indexed
>                     // format was expected, but the
>                     // entire array was sent.  In such
>                     // cases traverse the array and
>                     // call the setter for each item.
>                     if (index == 0 &&
>                         value.getClass().isArray() &&
>                         !type.getClass().isArray()) {
>                         for (int i=0; i<Array.getLength(value); i++) {
>                             Object item =
>                                 JavaUtils.convert(Array.get(value, i),
> type);
>                             pd.set(object, i, item);
>                         }
>                     } else {
>                         // Can't proceed.  Throw an exception that
>                         // will be caught in the catch block below.
>                         throw e;
>                     }
>                 }
> 
> In the CATCH block (It will come here for all basic xsd types , as code
> executed before it in ArrayListExtension marks it to be a int[] array
> and the setValues(Object[]) will fail with IllegalArgumentException), it
> is attempted to figure out the Type and Convert it to the one in the
> BeanPropertyDescriptor (which for us is Object[] class, which is okay
> since it is an anyType). But there is a small deviation , instead of
> identifying the underlying type (if it is an array) , CATCH block
> creates an array of Object[] and fills it up with the values of correct
> type. This results in the deserilialzedObject.getValues() resulting in
> an Object[] array instead of an Integer[] (as expected).
> 
> This is a discrepancy as for some XSD types like xsd:string,
> xsd:dateTime it returns String[]/Calendar[] but for
> xsd:int,xsd:float,xsd:boolean etc. it does not.
> 
> We would like to confirm whether or not do you consider this as a bug ,
> we did a slight modification to CATCH BeanPropertyTarget and everthing
> was working fine , :-
> 
> catch {
>                 // If an exception occurred,
>                 // see it the value can be converted into
>                 // the expected type.
>                 Class type = pd.getType();
> 
>                 //Vikram - INFY - START
>                 if (value.getClass().isArray() &&
> value.getClass().getComponentType().isPrimitive()
>                         && type.isArray() &&
> type.getComponentType().equals(Object.class))
>                 {
>                         //we make our own array type here.
>                         type =
> Array.newInstance(JavaUtils.getWrapperClass(value.getClass().getComponen
> tType()),0).getClass();
>                 }
>                 //Vikram - INFY - END
> 
>                 if (JavaUtils.isConvertable(value, type)) {
>                     value = JavaUtils.convert(value, type);
>                     if (index < 0)
>                         pd.set(object, value);
>                     else
>                         pd.set(object, index, value);
>                 } else {
>                     // It is possible that an indexed
>                     // format was expected, but the
>                     // entire array was sent.  In such
>                     // cases traverse the array and
>                     // call the setter for each item.
>                     if (index == 0 &&
>                         value.getClass().isArray() &&
>                         !type.getClass().isArray()) {
>                         for (int i=0; i<Array.getLength(value); i++) {
>                             Object item =
>                                 JavaUtils.convert(Array.get(value, i),
> type);
>                             pd.set(object, i, item);
>                         }
>                     } else {
>                         // Can't proceed.  Throw an exception that
>                         // will be caught in the catch block below.
>                         throw e;
>                     }
>               }
> 
> Only for primitive Arrays,We change the "type" to take in the underlying
> type of the "value" array. This will work only for primitive arrays and
> only when the bd has "type" set to Object[] (anytype).
> 
> I would appreciate a quick response from your side as most of our system
> depends on this functionality.
> 
> Thanks a lot,
> Vikram Roopchand
> Programmwer Analyst,
> INFOSYS Technologies Ltd. - Pune.
> India
> 
> 


-- 
Davanum Srinivas - http://webservices.apache.org/~dims/