Axis2
  1. Axis2
  2. AXIS2-3797

"Unknown type can not serialize" Exception

    Details

    • Type: Bug Bug
    • Status: Reopened
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 1.4
    • Fix Version/s: None
    • Component/s: adb
    • Labels:
      None
    • Environment:
      Axis2 1.4, Tomcat 5.5.26

      Description

      I have a simple POJO service with the following method:

      package org.tempuri.test;

      import org.tempuri.test.data.arrays.ArrayOfanyType;

      public class TypeTest {
      public ArrayOfanyType retArrayAnyType1D(ArrayOfanyType inArrayAnyType1D)

      { return inArrayAnyType1D; }

      }

      The ArrayOfanyType is declared like this:

      public class ArrayOfanyType {

      private Object[] anyType;

      public Object[] getAnyType() {
      if (anyType == null)

      { anyType = new Object[0]; }

      return this.anyType;
      }

      public void setAnyType(Object[] anyType)

      { this.anyType = anyType; }

      }

      I deploy this POJO on an Axis2 1.4 runtime running on Tomcat.
      Then I generate a client stub using the following command:

      wsdl2java -ap -o ./generated -s -u -uw -uri http://localhost:8080/axis2-1.4/services/TypeTest?wsdl

      I use the stub to invoke the service passing an OMElement in the Object array:

      OMFactory factory = OMAbstractFactory.getOMFactory();
      OMNamespace ns = factory.createOMNamespace("http://www.serverside.com/articles/introducingAxiom", "article");
      OMElement articleElement = factory.createOMElement("Article", ns);

      ArrayOfanyType input = new ArrayOfanyType();
      input.setAnyType(new OMElement[]

      {articleElement}

      );
      stub.retArrayAnyType1D(input);

      While serializing the ArrayOfanyType ADBBean I get an "Unknown type can not serialize" exception:

      Caused by: javax.xml.stream.XMLStreamException: Unknow type can not serialize
      at org.apache.axis2.databinding.utils.ConverterUtil.serializeAnyType(ConverterUtil.java:1449)
      at org.tempuri.test.data.arrays.xsd.ArrayOfanyType.serialize(ArrayOfanyType.java:241)
      at org.tempuri.test.data.arrays.xsd.ArrayOfanyType.serialize(ArrayOfanyType.java:160)
      at org.tempuri.test.RetArrayAnyType1D.serialize(RetArrayAnyType1D.java:203)
      at org.tempuri.test.RetArrayAnyType1D.serialize(RetArrayAnyType1D.java:123)
      at org.tempuri.test.RetArrayAnyType1D$1.serialize(RetArrayAnyType1D.java:111)
      ...

      I did not have this problem on Axis2 1.3 so I guess something have been changed in ConverterUtil.

      1. TypeTestClient.java
        1 kB
        Detelin Yordanov
      2. TypeTest.aar
        3 kB
        Detelin Yordanov
      3. full stacktrace.txt
        3 kB
        Detelin Yordanov

        Issue Links

          Activity

          Hide
          Detelin Yordanov added a comment -

          The aar contains also the sources of the service.

          Show
          Detelin Yordanov added a comment - The aar contains also the sources of the service.
          Hide
          Nandana Mihindukulasooriya added a comment -

          Hi Detelin,
          Do you have a patch for this issue ?

          thanks,
          nandana

          Show
          Nandana Mihindukulasooriya added a comment - Hi Detelin, Do you have a patch for this issue ? thanks, nandana
          Hide
          Detelin Yordanov added a comment -

          Hi Nandana,
          No I don't have a patch, but, I think that if I could bring Amila's attention to this, he could explain why this is not working and a provide
          a possible workaround.
          My understanding so far is that in Axis2 1.3 the anyType was serialized and deserialized as OMElement, but now in Axis2 1.4 that is not so.
          I guess that decision was taken due to this jira: http://issues.apache.org/jira/browse/AXIS2-3331
          And since the sample above was taken from one of the integration test clases, namely
          org.apache.axis2.rpc.complex.ComplexDataTypesComplexDataTypesSOAP11Test#testretArrayAnyType1D(),
          I checked that method again in Axis2 trunk and saw that it has been commented out by Amila, with the following comment:

          "svn commit change the adb any type handling. currently it uses an om element to support
          the anytype. but this is wrong. so I have change it to use the object to represent the anytype and the
          serialize it accordingly. although this a current Axis2 1.3 bug, I put this commit only to trunk since
          this is a bit large change."

          So my question is whether there is a way to send OMElement in an Object array in the current version?

          Show
          Detelin Yordanov added a comment - Hi Nandana, No I don't have a patch, but, I think that if I could bring Amila's attention to this, he could explain why this is not working and a provide a possible workaround. My understanding so far is that in Axis2 1.3 the anyType was serialized and deserialized as OMElement, but now in Axis2 1.4 that is not so. I guess that decision was taken due to this jira: http://issues.apache.org/jira/browse/AXIS2-3331 And since the sample above was taken from one of the integration test clases, namely org.apache.axis2.rpc.complex.ComplexDataTypesComplexDataTypesSOAP11Test#testretArrayAnyType1D(), I checked that method again in Axis2 trunk and saw that it has been commented out by Amila, with the following comment: "svn commit change the adb any type handling. currently it uses an om element to support the anytype. but this is wrong. so I have change it to use the object to represent the anytype and the serialize it accordingly. although this a current Axis2 1.3 bug, I put this commit only to trunk since this is a bit large change." So my question is whether there is a way to send OMElement in an Object array in the current version?
          Hide
          Amila Chinthaka Suriarachchi added a comment -

          When generating code with the wsdl2java tool it takes inputs only from the wsdl file. So if there is an element of the type anyType it generates an object type parameter for this. xsd:anyType is the parent type for all XmlSchema types as java.lang.Object for java objects.

          eg.
          <complexType>
          <sequence>
          <element name="testValue" type="xsd:anyType" minOccurs="0" nillable="true"/>
          </sequence>
          </complexType>

          Here you can give any standard java class so that it serialize it with the type.

          eg. <testValue xsi:type="xsd:int">5</testValue>

          so at the other end it can creates the proper objects depends on the type.

          But if you have a schema like this

          <complexType>
          <sequence>
          <any/>
          </sequence>
          </complexType>

          then ADB generates an OMElement for the corresponding parameter and hence you can parse an OMElement.

          Here you can assume that the wsdl2java tool is something which try to generate a code, so that the generated code serialize java objects and parse xmlstreams according to the schema given in the wsdl. It does not have an idea about the implementation logic of the service.

          Show
          Amila Chinthaka Suriarachchi added a comment - When generating code with the wsdl2java tool it takes inputs only from the wsdl file. So if there is an element of the type anyType it generates an object type parameter for this. xsd:anyType is the parent type for all XmlSchema types as java.lang.Object for java objects. eg. <complexType> <sequence> <element name="testValue" type="xsd:anyType" minOccurs="0" nillable="true"/> </sequence> </complexType> Here you can give any standard java class so that it serialize it with the type. eg. <testValue xsi:type="xsd:int">5</testValue> so at the other end it can creates the proper objects depends on the type. But if you have a schema like this <complexType> <sequence> <any/> </sequence> </complexType> then ADB generates an OMElement for the corresponding parameter and hence you can parse an OMElement. Here you can assume that the wsdl2java tool is something which try to generate a code, so that the generated code serialize java objects and parse xmlstreams according to the schema given in the wsdl. It does not have an idea about the implementation logic of the service.
          Hide
          Amila Chinthaka Suriarachchi added a comment -

          this is not an issue ADB serialize anyType correctly

          Show
          Amila Chinthaka Suriarachchi added a comment - this is not an issue ADB serialize anyType correctly
          Hide
          Andreas Veithen added a comment -

          From the XML schema specification:

          "2.5.4 anyType

          The anyType represents an abstraction called the ur-type which is the base type from which all simple and complex types are derived. An anyType type does not constrain its content in any way. It is possible to use anyType like other types, for example:

          Example
          <xsd:element name="anything" type="xsd:anyType"/>
          The content of the element declared in this way is unconstrained, so the element value may be 423.46, but it may be any other sequence of characters as well, or indeed a mixture of characters and elements."

          Since on the other hand xsi:type is not mandatory, this issue is relevant, so I'm reopening it.

          To summarize: While the support for Java types is a real improvement over 1.3, not supporting OMElements and considering xsi:type as mandatory is a clear regression with respect to 1.3.

          Detelin, can you describe how exactly anyType was handled in 1.3?

          Show
          Andreas Veithen added a comment - From the XML schema specification: "2.5.4 anyType The anyType represents an abstraction called the ur-type which is the base type from which all simple and complex types are derived. An anyType type does not constrain its content in any way. It is possible to use anyType like other types, for example: Example <xsd:element name="anything" type="xsd:anyType"/> The content of the element declared in this way is unconstrained, so the element value may be 423.46, but it may be any other sequence of characters as well, or indeed a mixture of characters and elements." Since on the other hand xsi:type is not mandatory, this issue is relevant, so I'm reopening it. To summarize: While the support for Java types is a real improvement over 1.3, not supporting OMElements and considering xsi:type as mandatory is a clear regression with respect to 1.3. Detelin, can you describe how exactly anyType was handled in 1.3?
          Hide
          Amila Chinthaka Suriarachchi added a comment -

          My interpretation of any type is it has to map to an object. And at runtime this object can have a simple type or an complex type. i.e. generated ADB bean object in ADB case.

          eg.
          if there this and xml schema part like this

          <xsd:element name="anything" type="xsd:anyType"/>
          then <anything xsi:type="xsd:string>test<anything> is a valid serialized xml element. how we going to represent this if we use an OMElement?

          And also lets say we get something like this
          <anything>
          <element1>test</element1>
          <element2>test</element2>
          </anything>

          then how <element1>test</element1><element2>test</element2> going to represent as an OMElment?

          In my interpretation anyType is like java.lang.Object. All classes are extend from Object class.

          when you use anyType for an element it is like using Object type for an java field. At runtime the element can have any type but the type should be a defined one. And hence you should have a value to xsi:type.

          I Agree with you that what schema says is ambiguous. This is the only interpretation I can come up with to write a possible
          implementation. In this way I could interoperate the anyType with the MSFT wsdl where with OMElement it was not possible.

          Show
          Amila Chinthaka Suriarachchi added a comment - My interpretation of any type is it has to map to an object. And at runtime this object can have a simple type or an complex type. i.e. generated ADB bean object in ADB case. eg. if there this and xml schema part like this <xsd:element name="anything" type="xsd:anyType"/> then <anything xsi:type="xsd:string>test<anything> is a valid serialized xml element. how we going to represent this if we use an OMElement? And also lets say we get something like this <anything> <element1>test</element1> <element2>test</element2> </anything> then how <element1>test</element1><element2>test</element2> going to represent as an OMElment? In my interpretation anyType is like java.lang.Object. All classes are extend from Object class. when you use anyType for an element it is like using Object type for an java field. At runtime the element can have any type but the type should be a defined one. And hence you should have a value to xsi:type. I Agree with you that what schema says is ambiguous. This is the only interpretation I can come up with to write a possible implementation. In this way I could interoperate the anyType with the MSFT wsdl where with OMElement it was not possible.
          Hide
          Andreas Veithen added a comment -

          > My interpretation of any type is it has to map to an object. And at runtime this object can have a simple type or an complex type. i.e. generated ADB bean object in ADB case.
          >
          > eg.
          > if there this and xml schema part like this
          >
          > <xsd:element name="anything" type="xsd:anyType"/>
          > then <anything xsi:type="xsd:string>test<anything> is a valid serialized xml element. how we going to represent this if we use an OMElement?

          If there is an xsi:type attribute, then ADB should use the mapped Java type to represent the element.

          > And also lets say we get something like this
          > <anything>
          > <element1>test</element1>
          > <element2>test</element2>
          > </anything>
          >
          > then how <element1>test</element1><element2>test</element2> going to represent as an OMElment?

          The OMElement should actually represent the "anything" element. Alternatively it could be represented using some other object that stores a node list (the child nodes) and a list of attributes. That is why I asked how this was represented (as an OMElement) in Axis2 1.3.

          > In my interpretation anyType is like java.lang.Object. All classes are extend from Object class.

          In Java, classes are derived from java.lang.Object by extension. On the other hand, schema types are derived from anyType by restriction. They are therefore not comparable.

          > when you use anyType for an element it is like using Object type for an java field. At runtime the element can have any type but the type should be a defined one.

          The XML schema specs clearly say that an element declared with anyType can have any content, and this content is not necessarily described by an existing type. What you are describing here is not anyType, but <xsd:any processContents="strict"/> (for which ADB actually uses OMElement, while this should be represented as a Java object).

          > And hence you should have a value to xsi:type.

          > I Agree with you that what schema says is ambiguous.

          I don't pretend that the schema specs are ambiguous. They are very clear and they make sense if one avoids comparing the schema type system (which works by restriction and extension) with the Java type system (which only works by extension).

          > This is the only interpretation I can come up with to write a possible
          > implementation. In this way I could interoperate the anyType with the MSFT wsdl where with OMElement it was not possible.

          As I said above, supporting xsi:type correctly is a real improvement, but on the other hand, considering xsi:type as mandatory is a regression. IMHO the correct approach is as follows:

          • The property storing the anyType element should be of type Object.
          • During deserialization:
          • If xsi:type is present, map the content to a Java object.
          • Otherwise, map it to an OMElement.
          • During serialization:
          • If the property refers to an OMElement, serialize this element and don't add xsi:type.
          • Otherwise, map the Java object to a schema type and serialize it with an xsi:type attribute.
          Show
          Andreas Veithen added a comment - > My interpretation of any type is it has to map to an object. And at runtime this object can have a simple type or an complex type. i.e. generated ADB bean object in ADB case. > > eg. > if there this and xml schema part like this > > <xsd:element name="anything" type="xsd:anyType"/> > then <anything xsi:type="xsd:string>test<anything> is a valid serialized xml element. how we going to represent this if we use an OMElement? If there is an xsi:type attribute, then ADB should use the mapped Java type to represent the element. > And also lets say we get something like this > <anything> > <element1>test</element1> > <element2>test</element2> > </anything> > > then how <element1>test</element1><element2>test</element2> going to represent as an OMElment? The OMElement should actually represent the "anything" element. Alternatively it could be represented using some other object that stores a node list (the child nodes) and a list of attributes. That is why I asked how this was represented (as an OMElement) in Axis2 1.3. > In my interpretation anyType is like java.lang.Object. All classes are extend from Object class. In Java, classes are derived from java.lang.Object by extension. On the other hand, schema types are derived from anyType by restriction. They are therefore not comparable. > when you use anyType for an element it is like using Object type for an java field. At runtime the element can have any type but the type should be a defined one. The XML schema specs clearly say that an element declared with anyType can have any content, and this content is not necessarily described by an existing type. What you are describing here is not anyType, but <xsd:any processContents="strict"/> (for which ADB actually uses OMElement, while this should be represented as a Java object). > And hence you should have a value to xsi:type. > I Agree with you that what schema says is ambiguous. I don't pretend that the schema specs are ambiguous. They are very clear and they make sense if one avoids comparing the schema type system (which works by restriction and extension) with the Java type system (which only works by extension). > This is the only interpretation I can come up with to write a possible > implementation. In this way I could interoperate the anyType with the MSFT wsdl where with OMElement it was not possible. As I said above, supporting xsi:type correctly is a real improvement, but on the other hand, considering xsi:type as mandatory is a regression. IMHO the correct approach is as follows: The property storing the anyType element should be of type Object. During deserialization: If xsi:type is present, map the content to a Java object. Otherwise, map it to an OMElement. During serialization: If the property refers to an OMElement, serialize this element and don't add xsi:type. Otherwise, map the Java object to a schema type and serialize it with an xsi:type attribute.
          Hide
          Amila Chinthaka Suriarachchi added a comment -

          First of all if you take the root cause of this problem, you try to solve it in the wrong place.

          public class ArrayOfanyType {

          private Object[] anyType;

          public Object[] getAnyType() {
          if (anyType == null)

          { anyType = new Object[0]; }

          return this.anyType;
          }

          public void setAnyType(Object[] anyType)

          { this.anyType = anyType; }
          }

          At runtime what type of objects this.anyTpye Array can have? I don't think it is OMElement. it is some type of java objects. eg. String, Integer or any other class.

          So isn't is correct to generate those classes at the stub rather than an OMElement. So the correct solution is to POJO should check the type an serialise it properly. Then a question comes what happens for user defined classes (eg. Student, Vehicle)
          For those things I think there must be a way to specify them services.xml and should show in the wsdl in a separate complex type. Then any client generating code for that can create a data binding class for that and maps using the given xsi:type in the response.

          if some one has a method signature like this,
          public void setAnyType(OMElement[] anyType) { this.anyType = anyType; }

          then generated wsdl should have xs:any to represent this and Stub client generates accordingly.

          IMHO correct place to fix this issue is at POJO level.

          Taking your suggestion to add OMElement support as well to xsd:anyType
          Can you please first check how this done in jaxbri. (i.e -d jaxbri )
          I mean what this the type it generates for xs:anyType element and what happens when getting a response with the xsi:type and without it.

          Show
          Amila Chinthaka Suriarachchi added a comment - First of all if you take the root cause of this problem, you try to solve it in the wrong place. public class ArrayOfanyType { private Object[] anyType; public Object[] getAnyType() { if (anyType == null) { anyType = new Object[0]; } return this.anyType; } public void setAnyType(Object[] anyType) { this.anyType = anyType; } } At runtime what type of objects this.anyTpye Array can have? I don't think it is OMElement. it is some type of java objects. eg. String, Integer or any other class. So isn't is correct to generate those classes at the stub rather than an OMElement. So the correct solution is to POJO should check the type an serialise it properly. Then a question comes what happens for user defined classes (eg. Student, Vehicle) For those things I think there must be a way to specify them services.xml and should show in the wsdl in a separate complex type. Then any client generating code for that can create a data binding class for that and maps using the given xsi:type in the response. if some one has a method signature like this, public void setAnyType(OMElement[] anyType) { this.anyType = anyType; } then generated wsdl should have xs:any to represent this and Stub client generates accordingly. IMHO correct place to fix this issue is at POJO level. Taking your suggestion to add OMElement support as well to xsd:anyType Can you please first check how this done in jaxbri. (i.e -d jaxbri ) I mean what this the type it generates for xs:anyType element and what happens when getting a response with the xsi:type and without it.
          Hide
          Andreas Veithen added a comment -

          JAXB does it the right way. Here is the relevant part from the specs:

          "A schema author defines an element to be of type xs:anyType to defer constraining an element to a particular type to the xml document author. Through the use of xsi:type attribute or element substitution, an xml document author provides constraints for an element defined as xs:anyType. The JAXB unmarshaller is able to unmarshal a schema defined xsd:anyType element that has been constrained within the xml document to an easy to access JAXB mapped class. However, when the xml document does not constrain the xs:anyType element, JAXB unmarshals the unconstrained content to an element node instance of a supported DOM API."

          Show
          Andreas Veithen added a comment - JAXB does it the right way. Here is the relevant part from the specs: "A schema author defines an element to be of type xs:anyType to defer constraining an element to a particular type to the xml document author. Through the use of xsi:type attribute or element substitution, an xml document author provides constraints for an element defined as xs:anyType. The JAXB unmarshaller is able to unmarshal a schema defined xsd:anyType element that has been constrained within the xml document to an easy to access JAXB mapped class. However, when the xml document does not constrain the xs:anyType element, JAXB unmarshals the unconstrained content to an element node instance of a supported DOM API."
          Hide
          Amila Chinthaka Suriarachchi added a comment -

          this only talks about the unmarshaller.

          Lets see we have an element schema element like this,
          <element name="test" type="xs:anyType/>

          we get an xml like this for this,
          <test>test string<text>

          how it going to build a dom element from "test string" ?

          So I think it is better to try out a real sample an see how this handles. In other words you should
          be able to do what Yordanov has tried to do with jaxbri.

          If jaxbri supports this I am ok to add this support to ADB.

          Anyway I don't believe this is the correct fix for the reported issue.

          Show
          Amila Chinthaka Suriarachchi added a comment - this only talks about the unmarshaller. Lets see we have an element schema element like this, <element name="test" type="xs:anyType/> we get an xml like this for this, <test>test string<text> how it going to build a dom element from "test string" ? So I think it is better to try out a real sample an see how this handles. In other words you should be able to do what Yordanov has tried to do with jaxbri. If jaxbri supports this I am ok to add this support to ADB. Anyway I don't believe this is the correct fix for the reported issue.
          Hide
          Andreas Veithen added a comment -

          For "<test>test string</test>", JAXB creates an Element representing "test" and for "<test xsi:type='xs:string'>test string</test>", JAXB creates a String with value "test string".

          Show
          Andreas Veithen added a comment - For "<test>test string</test>", JAXB creates an Element representing "test" and for "<test xsi:type='xs:string'>test string</test>", JAXB creates a String with value "test string".
          Hide
          Amila Chinthaka Suriarachchi added a comment -

          I did a test with this pojo class with jaxbri data binding

          public Object getOMElement(String name)

          { OMFactory omFactory = OMAbstractFactory.getOMFactory(); OMNamespace omNamespace = omFactory.createOMNamespace("http://localhost/ns","test"); OMElement omElement = omFactory.createOMElement("test", omNamespace); omElement.setText("test element"); return omElement; }

          But the return DOM element actually represents the xml
          <ns:return>
          <test:test xmlns:test="http://localhost/ns">test element</test:test>
          </ns:return>

          So it gives the extra wrapper element.

          I am not sure this is part of xml schema or jaxb spec. But it is ok with me adding this to ADB (returning and OMElement with wrapper element) at least as a workaround for situations where we don't get xsi:type.

          Show
          Amila Chinthaka Suriarachchi added a comment - I did a test with this pojo class with jaxbri data binding public Object getOMElement(String name) { OMFactory omFactory = OMAbstractFactory.getOMFactory(); OMNamespace omNamespace = omFactory.createOMNamespace("http://localhost/ns","test"); OMElement omElement = omFactory.createOMElement("test", omNamespace); omElement.setText("test element"); return omElement; } But the return DOM element actually represents the xml <ns:return> <test:test xmlns:test="http://localhost/ns">test element</test:test> </ns:return> So it gives the extra wrapper element. I am not sure this is part of xml schema or jaxb spec. But it is ok with me adding this to ADB (returning and OMElement with wrapper element) at least as a workaround for situations where we don't get xsi:type.

            People

            • Assignee:
              Unassigned
              Reporter:
              Detelin Yordanov
            • Votes:
              5 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

              • Created:
                Updated:

                Development