8 Replies Latest reply on Nov 24, 2009 8:39 AM by JennHysuick

    Web Service complex datatypes

    JennHysuick

      I'm trying to connect a CFC to a non-CF webservices.  I have the WSDL file, and I can GET all the information I need, but I keep failing on the PUT of information.

       

      the ws.putMarks() funciton takes in a string, a long and a complex data type.  This data type is a custom array-type, which contains custom type objects.  What ever I've tried sending keeps giving me the following error:

       

      "Cannot perform web service invocation putMarks().  The fault returned when invoking the web serivce operation is:

           ' ' java.lan.IllegalArgumentException: argument type mismatch

      "

       

      So, I'm stuck. I can't figure out how to create a coldfusion object of the correct datatype.  I tried sending it an array of structures, but that failed.

       

      The portion of the WSDL file that I am using is:

       

      <message name="myMarksInService_putMarks">
           <part name="instructorID" type="xsd:string"/>
            <part name="assessmentId" type="xsd:long"/>
           <part name="marks" type="tns:classAssessmentMarkRemoteArray"/>
      </message>

       

      The schema in the WSDL shows:

      <xs:complexType final="#all" name="classAssessmentMarkRemoteArray">
           <xs:sequence>
                <xs:element maxOccurs="unbounded" minOccurs="0" name="item" nillable="true" type="tns:classAssessmentMarkRemote"/>
           </xs:sequence>
      </xs:complexType>

       

      and

       

      <xs:complexType name="classAssessmentMarkRemote">
           <xs:sequence>    
                <xs:element minOccurs="0" name="studentID" type="xs:string"/>
                <xs:element minOccurs="0" name="mark" type="xs:string"/>
                <xs:element minOccurs="0" name="markFeedBack" type="xs:string"/>
           </xs:sequence>
      </xs:complexType>

       

       

      I've hunted everywhere, and can't find out how to create an object in CF of the right type.  Any help the group could offer would be most helpful!

       

      Thanks!

       

      Jenn

        • 1. Re: Web Service complex datatypes
          JR "Bob" Dobbs-qSBHQ2 Level 3

          Can you post the entire WSDL and the code you have attempted to use?

          • 2. Re: Web Service complex datatypes
            JennHysuick Level 1

            We managed to successfully sent putMarks() the required parameters, but we still cannot create the objects.  What I did was call getMarks(), and then take the results, and put them directly into putMarks().  While this confirms that the WSDL and WS methods work, I still need to be able to create the necessary objects from scratch.  Haveing to getMarks(), empty them out, and then clone the results as many time for adding new marks is clearly not the best solution to this problem.

             

            The WSDL file is attached.  By reques of our administrators, I have removed the acutual domain in the URLs.

             

            I am using the following code to connect to the WS:

             

            <cfscript>
                    //create the web service object
                    nsid = "usersname";
                    password = "anything";
                    wsns = "http://www.jboss.org/seam/webservice";
                    ws = CreateObject("webservice", "URLtoWSDL");
                    ws.setMaintainSession(true);
                    ret = ws.login(nsid,password);
                    responseHeader = getSOAPResponseHeader(ws,wsns,"conversationId",true);
                      //get conversationID from response header
                      theHeader = AddSOAPRequestHeader(ws,wsns,"conversationId",#responseHeader#);

                   marksList = ws.getMarks("usermame","role","12347");
                   marksPut = ws.putMarks("username",1234, marksList);
                       ws.logout();
                </cfscript>

             

            As far as trying  to create the object, I hvae tried:

            <cfobject type="webservice" action="create" name="marks" webservice="URLtoWSDL">, which gives me an object of type MyMarksInServiceBindingStub.

             

            I need to findout how to create objects of type tns:classAssessmentMarkRemote, and add them to an object of type tns:classAssessmentMarkRemoteArray.  This is what stumps me.

             

            Thanks for any help you may have to offer.


            Jenn


            • 3. Re: Web Service complex datatypes
              JR "Bob" Dobbs-qSBHQ2 Level 3

              This looks like the definition for the type classAssessmentMarkRemote

               

              <xs:complexType name="classAssessmentMarkRemote">

               

              <xs:sequence>
              <xs:element minOccurs="0" name="bannerId" type="xs:string"/>
              <xs:element minOccurs="0" name="mark" type="xs:string"/>
              <xs:element minOccurs="0" name="markFeedBack" type="xs:string"/>
              </xs:sequence>
              </xs:complexType>

               

               

              Try create a struct for each classAssessmentMarkRemote item and add each struct to an array

              <!--- create a classAssessmentMarkRemote item --->
              <cfset myMarkItem=StructNew() />
              <cfset myMarkItem["bannerId"] = "AN_ID" />
              <cfset myMarkItem["mark"] = "A" />
              <cfset myMarkItem["markFeedBack"] = "TEST" />

               


              <!--- add item to array --->
              <cfset myMarkArray=ArrayNew(1) />
              <cfset myMarkArray=ArrayAppend(myMarkArray, myMarkItem) />

               


              <!--- line to invoke putMarks operation --->
              ws.putMarks("username",1234, myMarkArray);

               

               

              Note that none of this code is tested.

              • 4. Re: Web Service complex datatypes
                JennHysuick Level 1

                Well, I have a NEW error now

                 

                I tried:

                <cfscript>

                    arrMarks = StructNew();
                    strMark = StructNew();
                    strMark.bannerId = "11072914";
                    strMark.mark ="77";
                    strMark.markFeedBack = "Do Better";
                    //ArrayAppend(arrMarks,strMark);
                    StructInsert(arrMarks,"item",strMark);

                </cfscript>

                 

                I tried as an array, but got the type mismatch error again, so we tried as a structure, which gives me the error:

                 

                 

                Error converting CFML arguments to Java classes for web service invocation.
                Unable to create web service argument class [Lca.myURL.myMarks.action.ClassAssessmentMarkRemote;. Error: java.lang.InstantiationException: [Lca.myURL.myMarks.action.ClassAssessmentMarkRemote;. Often this is because the web service defines an abstract complexType as an input to an operation. You must create an actual instance of this type in Java.

                 

                 

                We are at a complete loss at this point.  I did a "getMarks(), and dumped the object I got in return, and this is what it gave me:

                 

                object of ca.myURL.myMarks.action.ClassAssessmentMarkRemoteArray
                Class Nameca.myURL.myMarks.action.ClassAssessmentMarkRemoteArray
                Methods
                Method Return Type
                equals(java.lang.Object)boolean
                getDeserializer(java.lang.String, java.lang.Class, javax.xml.namespace.QName)org.apache.axis.encoding.Deserializer
                getItem(int)ca.myURL.myMarks.action.ClassAssessmentMarkRemote
                getItem()ca.myURL.myMarks.action.ClassAssessmentMarkRemote[]
                getSerializer(java.lang.String, java.lang.Class, javax.xml.namespace.QName)org.apache.axis.encoding.Serializer
                getTypeDesc()org.apache.axis.description.TypeDesc
                hashCode()int
                setItem(ca.myURL.myMarks.action.ClassAssessmentMarkRemote[])void
                setItem(int, ca.myURL.myMarks.action.ClassAssessmentMarkRemote)void

                 

                What we're going to try next is to create a method in the web service that when I call it, it will return to me an empty object I seem to be unable to create so that I can populate it and send it back.

                 

                I don't see why there isn't a simple way to call the remote class to create an object!

                 

                Thanks for you help!

                 

                Jenn

                • 5. Re: Web Service complex datatypes
                  JR "Bob" Dobbs-qSBHQ2 Level 3

                  I reviewed the WSDL again.  I was mistaken about the type for the type "classAssessmentsRemoteArray".  It is not declared as an array.  It is zero or more "classAssessmentMarkRemote" items.

                   

                  Take a look at this blog entry.  The sample WSDL uses zero or more "nickname" elements similar to how your WSDL uses "classAssessmentsRemoteArray" containing 0 or "classAssessmentMarkRemote" items.

                  http://tjordahl.blogspot.com/2008/04/reprint-consuming-web-service-complex.html

                   

                  You might also try using the wsdl2java tool to look at the Java types created for the WSDL.

                  http://go.adobe.com/kb/ts_eaf0396_en-us

                  1 person found this helpful
                  • 6. Re: Web Service complex datatypes
                    BKBK Adobe Community Professional & MVP

                    What about cfproperty ? Something like this:

                     

                    Save the following code as classAssessmentMarkRemote.cfc

                     

                    <cfcomponent>
                       <cfproperty name="studentID" type="string" default="a1b2c3">
                       <cfproperty name="mark" type="string" default="80">
                       <cfproperty name="markFeedBack" type="string" default="Keep it up">
                    </cfcomponent>

                     

                    Then pass an instance of the cfc in the web service method.

                    • 7. Re: Web Service complex datatypes
                      Jochem van Dieten Level 4

                      BKBK is right. What you webservice needs as arguments are the instructorID, the assesmentId and an array of hisclassAssessmentMarkRemote.cfc, objects.

                      Webservices are typed. CFML is not. To make something typed in CF, you need an instance of a CFC with its properties defined using cfproperty.

                      • 8. Re: Web Service complex datatypes
                        JennHysuick Level 1

                        The first link you listed had the answer for me once I dug into the post.

                         

                        What I had to do was:

                         

                        <cfscript>
                            arrMarks = structNew();
                            arrMarks.item = ArrayNew(1);
                            arrMarks.item[1] = StructNew();
                            arrMarks.item[1].bannerId = "nks457it's ";
                            arrMarks.item[1].mark ="77";
                            arrMarks.item[1].markFeedBack = "Do Better";
                         
                        </cfscript>

                         

                        And then when I called the component, I passed in arrMarks.  In the component function, I took in the argument, but did not type it.

                         

                        What a confusing way to do things, but its now working, so I'm happy.

                         

                        Thank you for all your help!

                         

                        Jenn