32 Replies Latest reply: Feb 10, 2013 11:53 AM by Rockit8 RSS

    Invoke webservice with complex types

    Rockit8 Community Member

      Hi

       

      I am trying to invoke a .net webservice method that receives an array of strings an i noticed that if i do this:

       

      <cfscript>

           text = arraynew(1);

           text[1] = "Hello";

           text[2] = "world";

      </cfscript>

       

      <cfinvoke method="Hello"

        webservice="http://localhost/Service1.asmx?wsdl"

        returnvariable="response">

           <cfinvokeargument name="array" value=#text#/>

      </cfinvoke>

       

      I get this error

      Cannot perform web service invocation Hello.

      The fault returned when invoking the web service operation is:

      ''java.lang.IlligalArgumentException: argument type mismatch

       

      however if i do this it works well:

       

      <cfscript>

           root = structnew();

           text = arraynew(1);

           text[1] = "Hello";

           text[2] = "world";

           root.string=text;

      </cfscript>

       

      <cfinvoke method="Hello"

        webservice="http://localhost/Service1.asmx?wsdl"

        returnvariable="response">

           <cfinvokeargument name="array" value=#root#/>

      </cfinvoke>

       

      I know this has to do with the generated java proxy because he generated a structure called ArrayOfString with a property called string (what i am replicating in the "root" variable).... Is there any way around this, or this is the right way to do it? It is a bit painfull to do it like this...

       

      Thanks.

        • 1. Re: Invoke webservice with complex types
          BKBK MVP

          I can imagine that. Run the following code, and you will find that a ColdFusion array isn't a Java array at all, but a Java vector!

           

          <cfscript>

               text = arraynew(1);

               text[1] = "Hello";

               text[2] = "world";

          </cfscript>

           

          <cfoutput>

              text: #text.getClass().getsuperclass().getname()#

          </cfoutput>

           

          One of the methods of the java.util.Vector class is toArray(). So, have a go with

           

          <cfscript>

               text = arraynew(1);

               text[1] = "Hello";

               text[2] = "world";

               textArray = text.toArray();

          </cfscript>

           

          <cfinvoke method="Hello"

            webservice="http://localhost/Service1.asmx?wsdl"

            returnvariable="response">

               <cfinvokeargument name="array" value="#textArray#" />

          </cfinvoke>

          • 2. Re: Invoke webservice with complex types
            Rockit8 Community Member

            Hi BFBK, thanks for your reply.

             

            I tried calling the toArray() but throws the same type mismatch error

            Dumping both the text and the textArray returns the same thing.

             

            Thanks.

            • 3. Re: Invoke webservice with complex types
              BKBK MVP

              Rockit8 wrote:

               

              I tried calling the toArray() but throws the same type mismatch error

              Sorry to hear that. We'll search on of course.

               

              Dumping both the text and the textArray returns the same thing.

              Not really. ColdFusion tells you they are both arrays, which is true. However, text is a ColdFusion array (a Java vector), whereas textArray is a Java Object array.

               

              <cfoutput>

                  text: #text.getClass().getsuperclass().getname()#<br>

                  textArray: #textArray.getClass().getname()#

              </cfoutput>

              • 4. Re: Invoke webservice with complex types
                BKBK MVP

                What is the signature of the hello method? Could you show us the WSDL?

                • 5. Re: Invoke webservice with complex types
                  Rockit8 Community Member

                  You are right, i was looking just at the basic <cfdump.../>

                   

                  The thing is, by decompiling the java stubs generated by the wsdl2java i can see this:

                   

                  public abstract interface Service1Soap extends Remote
                  {
                    public abstract String Hello(ArrayOfString paramArrayOfString)
                      throws RemoteException;
                  } 
                  

                   

                  He is expecting a structure of the type ArrayOfString. Looking at this class i can see the following property:

                   

                  public String[] string;
                  

                   

                  So this is basically the reason i created the structure and property with names that match this description in the first place... this is want i wanted to avoid.

                   

                  Of course i can do this dinamically for some cases but if there is an out-of-the-box method to do this i would like to know.

                   

                  Regarding the hello signature...its a .Net webservice and the method has the following signature:

                   

                  public string Hello(string[] array);
                  

                   

                  After looking at the WSDL i think there is not mutch i can do to avoid this:

                   

                   

                  <s:element name="Hello">
                       <s:complexType>
                            <s:sequence>
                                 <s:element minOccurs="0" maxOccurs="1" name="array" type="tns:ArrayOfString"/>
                            </s:sequence>
                       </s:complexType>
                  </s:element>
                       <s:complexType name="ArrayOfString">
                            <s:sequence>
                            <s:element minOccurs="0" maxOccurs="unbounded" name="string" nillable="true" type="s:string"/>
                       </s:sequence>
                  </s:complexType>
                  

                   

                  Thanks.

                   

                  Message was edited by: Rockit8

                  • 6. Re: Invoke webservice with complex types
                    BKBK MVP

                    Ah, a String[]! You could simulate it using the following, even more compact, code:

                     

                    <cfscript>

                         text = toString("Hello,World").split(",");

                    </cfscript>

                     

                    <cfinvoke method="Hello"

                      webservice="http://localhost/Service1.asmx?wsdl"

                      returnvariable="response">

                         <cfinvokeargument name="array" value="#text#" />

                    </cfinvoke>

                    • 7. Re: Invoke webservice with complex types
                      Rockit8 Community Member

                      True, but that would only work in case of String[]!

                       

                      I can fix the problem and develop something generic that does that kind of plumbing code for me...which would take me like 10 minutes or less to do.

                       

                      I just posted this to know if there were any alternatives to my aproach...maybe a specific wsdl2java parameter that i dont know about.

                       

                      Thanks.

                      • 8. Re: Invoke webservice with complex types
                        BKBK MVP

                        Rockit8 wrote:

                         

                        True, but that would only work in case of String[]!

                        Does it work?

                         

                        I can fix the problem and develop something generic that does that kind of plumbing code for me...which would take me like 10 minutes or less to do.

                         

                        I just posted this to know if there were any alternatives to my aproach...maybe a specific wsdl2java parameter that i dont know about.

                        I do believe that you, as client, should not aim to be generic. In the client-server model, the server (in this case, the web service) has the obligation to tell you precisely what type of argument it expects. If the server requires a string array, then you have to pass it a string array. 

                        • 9. Re: Invoke webservice with complex types
                          Rockit8 Community Member

                          BKBK wrote:

                           

                          Does it work?

                          No, it does not...the java proxy is expecting the structure i specified above.

                          BKBK wrote:


                          I do believe that you, as client, should not aim to be generic. In the client-server model, the server (in this case, the web service) has the obligation to tell you precisely what type of argument it expects. If the server requires a string array, then you have to pass it a string array.

                          Exactly...the server IS expecting a string[] as you can see by the signature of the method.

                           

                          If i call it in a .Net client i invoke the method with a string[] as parameter, from the coldfusion side i cannot do that because of the generated proxy...the problem is in the proxy generation.

                           

                          I'm guessing there is nothing i can do about that...

                           

                          Lets forget about the generic part...if there is a way to invoke that method without creating the "root structure" that solves my problem.

                           

                          Thanks.

                          • 10. Re: Invoke webservice with complex types
                            BKBK MVP

                            Rockit8 wrote:

                             

                            Exactly...the server IS expecting a string[] as you can see by the signature of the method.

                             

                            If i call it in a .Net client i invoke the method with a string[] as parameter, from the coldfusion side i cannot do that because of the generated proxy...the problem is in the proxy generation.~

                             

                            I'm guessing there is nothing i can do about that...

                            Very clear.

                            • 11. Re: Invoke webservice with complex types
                              BKBK MVP

                              Rockit8 wrote:

                               

                              No, it does not...the java proxy is expecting the structure i specified above.

                              Out of curiosity, what error message did you get when you passed the string array?

                               

                              Added update: I thought it might be a good idea to add the attribute refreshWSDL = "yes" to cfinvoke, during your tests, to prevent ColdFusion from reusing the cached version of the proxy.

                              • 12. Re: Invoke webservice with complex types
                                Rockit8 Community Member

                                Passing the ColdFusion array (java vector) or the solution you gave with the toArray() method i allways get the same error:

                                 

                                Cannot perform web service invocation Hello.

                                The fault returned when invoking the web service operation is:

                                ''java.lang.IlligalArgumentException: argument type mismatch

                                • 13. Re: Invoke webservice with complex types
                                  BKBK MVP

                                  Rockit8 wrote:

                                   

                                  Passing the ColdFusion array (java vector) or the solution you gave with the toArray() method i allways get the same error:

                                   

                                  Cannot perform web service invocation Hello.

                                  The fault returned when invoking the web service operation is:

                                  ''java.lang.IlligalArgumentException: argument type mismatch

                                  Thanks. I got that. I am now talking about the error you get when you do:

                                   

                                  <cfscript>

                                       text = toString("Hello,World").split(",");

                                  </cfscript>

                                   

                                  <cfinvoke method="Hello"

                                    webservice="http://localhost/Service1.asmx?wsdl"

                                    returnvariable="response">

                                       <cfinvokeargument name="array" value="#text#" />

                                  </cfinvoke>

                                  • 14. Re: Invoke webservice with complex types
                                    Rockit8 Community Member

                                    BKBK wrote:

                                     

                                     

                                    Thanks. I got that. I am now talking about the error you get when you do:

                                     

                                    <cfscript>

                                         text = toString("Hello,World").split(",");

                                    </cfscript>

                                     

                                    <cfinvoke method="Hello"

                                      webservice="http://localhost/Service1.asmx?wsdl"

                                      returnvariable="response">

                                         <cfinvokeargument name="array" value="#text#" />

                                    </cfinvoke>

                                    Its the same argument type mismatch error.

                                     

                                    It only works if you change it to this:

                                     

                                    <cfscript>

                                         text = toString("Hello,World").split(",");
                                          root.string = text; //create structure and property

                                    </cfscript>

                                     

                                    <cfinvoke method="Hello"

                                      webservice="http://localhost/Service1.asmx?wsdl"

                                      returnvariable="response">

                                         <cfinvokeargument name="array" value="#root#" />

                                    </cfinvoke>

                                    • 15. Re: Invoke webservice with complex types
                                      BKBK MVP

                                      Thanks.

                                      • 16. Re: Invoke webservice with complex types
                                        BKBK MVP

                                        I can now fully appreciate the extent of the problem. I have just created a test web service, and checked out the signature of the function in the generated stub(String array). But ColdFusion insists on a struct in the call!

                                         

                                        Message was edited by: BKBK

                                        • 17. Re: Invoke webservice with complex types
                                          Rockit8 Community Member

                                          Yes, he allways creates a struct wrapping the arrays.

                                           

                                          I was playing with the wsdl2java arguments and according to the documentation this one was worth trying:

                                          -w or --wrapArrays: Prefers building beans to straight arrays for wrapped XML array types. This switch is not in included in the Axis documentation.

                                          But the proxy generation was exactly the same and the error still occurred.

                                           

                                          Just because i'm curious...you created a webservice using .net or other technology?

                                           

                                          Message was edited by: Rockit8

                                          • 18. Re: Invoke webservice with complex types
                                            -==cfSearching==- Community Member
                                            I was playing with the wsdl2java arguments and according to the documentation this one was worth trying:
                                            -w or --wrapArrays: Prefers building beans to straight arrays for wrapped XML array types. This switch is not in included in the Axis documentation.

                                             

                                            No idea if it will work, but I would think you would want the opposite.

                                            • 19. Re: Invoke webservice with complex types
                                              Rockit8 Community Member

                                              Yes..that didnt work...made no difference. The opposite would be nice but as far as I know there isnt one.

                                              • 20. Re: Invoke webservice with complex types
                                                -==cfSearching==- Community Member

                                                To clarify, I meant try the nowrap option.  If that does not work, then yes you may be out of luck. I think there is a flag in Axis 2, which obviously does not help here since CF uses Axis 1.x. 

                                                 

                                                Message was edited by: -==cfSearching==-

                                                • 21. Re: Invoke webservice with complex types
                                                  BKBK MVP

                                                  Rockit8 wrote:

                                                   

                                                  Yes..that didnt work...made no difference. The opposite would be nice but as far as I know there isnt one.

                                                  Did you apply my earlier suggestion, refreshWSDL = "yes", to suppress the use of caching? I expect the following combination to work:

                                                   

                                                  refreshwsdl="yes" wsdl2JavaArgs="nowrapped"

                                                  • 22. Re: Invoke webservice with complex types
                                                    Rockit8 Community Member

                                                    Hi

                                                     

                                                    The "--nowrapped" arg changes the way the wsdl is generated but not in the way i wanted, using the same method as above what it creates in the java is this:

                                                     

                                                    public abstract HelloResponse Hello(hello paramHello)
                                                        throws RemoteException;
                                                    

                                                     

                                                    He creates a new class that wraps the request and response parameters:

                                                     

                                                    public class hello
                                                      implements Serializable
                                                    {
                                                    [...]
                                                      private ArrayOfString array;
                                                    [...]
                                                    

                                                     

                                                    So the --nowrap actually works like one more level of wrapping..

                                                    • 23. Re: Invoke webservice with complex types
                                                      BKBK MVP

                                                      In my web service test, the following call works as expected! I am looking into it to see if this is by accident or by design.

                                                       

                                                      <cfscript>

                                                           strArray = toString("Hello,World").split(",");

                                                      </cfscript>

                                                       

                                                      <cfinvoke method="myFunc"

                                                        webservice="http://127.0.0.1:8500/workspace/cf_proj/ws_complexTypes/Test.cfc?wsdl"

                                                        returnvariable="response" refreshwsdl="true" wsdl2JavaArgs="nowrapped" >

                                                           <cfinvokeargument name="arr" value="#strArray#" />

                                                      </cfinvoke>

                                                       

                                                      <cfdump var = "#response#">

                                                      • 24. Re: Invoke webservice with complex types
                                                        Rockit8 Community Member

                                                        How is your "myfunc" method described in the wsdl? (post the equivalent of what i posted above in your webservice wsdl).

                                                         

                                                        I copy-pasted your code, changed the webservice and got the same error...so the only difference between what you are using and what i am using is the webservice technology...you are using coldfusion, i am using .net.

                                                        • 25. Re: Invoke webservice with complex types
                                                          BKBK MVP

                                                          Rockit8 wrote:

                                                           

                                                          How is your "myfunc" method described in the wsdl? (post the equivalent of what i posted above in your webservice wsdl).

                                                          <xs:element name="myFunc">

                                                              <xs:complexType>

                                                                  <xs:sequence>

                                                                      <xs:element maxOccurs="unbounded" minOccurs="0" name="arr" nillable="true" type="xs:anyType"/>

                                                                  </xs:sequence>

                                                              </xs:complexType>

                                                          </xs:element>

                                                          • 26. Re: Invoke webservice with complex types
                                                            Rockit8 Community Member

                                                            Makes sense...my wsdl is enforcing the ArrayOf<type_name>...

                                                             

                                                            Guess i'll have to live with that

                                                             

                                                            Thanks for the replys.

                                                            • 27. Re: Invoke webservice with complex types
                                                              -==cfSearching==- Community Member

                                                              so the only difference between what you are using and what i am using is the webservice technology...you are using coldfusion, i am using .net.

                                                               

                                                              True, but that is the key. Since there is no direct mapping of the .NET ArrayOfString class in Axis, it is treated as a structure in CF. Just like any other custom/complex type.

                                                               

                                                              Makes sense...my wsdl is enforcing the ArrayOf<type_name>...

                                                               

                                                              So did you ultimately change anything .. or just leave it as ArrayOfString? (Though that is a  bit of a misnomer imo, since it is a class not an array.)

                                                              • 28. Re: Invoke webservice with complex types
                                                                Rockit8 Community Member

                                                                In the .net webservice the method still receives a string[] but i think there is nothing i can do to change the wsdl generation...and i do not want to do that since i'll be consuming other webservice done in some other technology.

                                                                 

                                                                In the coldfusion side its still expecting the ArrayOfString...

                                                                 

                                                                As said before, the transformation of a CF array to the ArrayOf<Type_name> can be one dynamically so i think i'll take that aproach.

                                                                • 29. Re: Invoke webservice with complex types
                                                                  -==cfSearching==- Community Member

                                                                  As said before, the transformation of a CF array to the ArrayOf<Type_name> can be one dynamically so i think i'll take that aproach.

                                                                  Okay, so ultimately you just went with the original code. Simple enough.

                                                                  • 30. Re: Invoke webservice with complex types
                                                                    henrylearn2rock Community Member

                                                                    Cool, how did you come up with root.string?  Trial and error??  I would love to know why root.string works.

                                                                    • 31. Re: Invoke webservice with complex types
                                                                      BKBK MVP

                                                                      henrylearn2rock wrote:

                                                                       

                                                                      Cool, how did you come up with root.string?  Trial and error??  I would love to know why root.string works.

                                                                      Your question seems irrelevant to this thread. Create your own thread, and you will surely get suggestions.

                                                                      • 32. Re: Invoke webservice with complex types
                                                                        Rockit8 Community Member

                                                                        Hi,

                                                                         

                                                                        The 'root' is just the name of the structure that will contain the array, doesn't matter what name you give to that variable, now the 'string' part is the important part. The 'string' is basically the name of the parameter in the webmethod...the method was something like:

                                                                        void myFunc(String[] string);

                                                                         

                                                                        You can know the correct name by looking at the wsdl. In this case since i was creating both the service and the client it was a easier.

                                                                        If you don't want to look at the WSDL you can use the wsdl2java to generate a proxy and see what's the structure of the objects. what you create in coldfusion has to match what wsdl2java is expecting.

                                                                         

                                                                        Hope it helps.