10 Replies Latest reply on Sep 26, 2013 11:53 AM by Aaron Beall

    SOAP decoding collections

    Aaron Beall Level 3

      Hi all,

       

      So I have a soap response whose soap body looks something like this:

       

      <response>
           <models>
                <model>...</model>
                <model>...</model>
                <model>...</model>
           </models>
      </response>
      

       

      I have AS classes to represent the response like this:

       

      class Model {
           ...
      }
      

       

      class ModelsResponse {
           public var models:ArrayCollection;
      }
      

       

      And I register both the Model and ModelsResponse type.

       

      However, the result after decoding is just an ArrayCollection of Model objects, not a decoded ModelResponse object. What might be going wrong?

       

      -Aaron

        • 1. Re: SOAP decoding collections
          JoshBeall Level 1

          What do you mean when you say you registered those types?

           

          It's been a little while since I've worked with SOAP services (switched to JSON everywhere I could), but I believe this is done from the Data/Services tab in Flash Builder.  You've defined your service, right click on the service method, and choose "Configure Return Type".  You should be able to map your SOAP response to the appropriate types.

           

          Here's the Adobe product support page about configuring data types for data service operations.

           

          Hope that helps,

            -Josh

          • 2. Re: SOAP decoding collections
            Aaron Beall Level 3

            I'm registering my client side types using the schema registry:

             

            SchemaTypeRegistry.getInstance().registerClass(new QName(namespace, objectType), objectClass);
            

             

            I tried to use the "Connect to Data/Service" option and it says the WSDL is invalid because it can't resolve imported XSDs in the WSDL. I don't see a way to explicitly tell it where those additional XSDs are either.

             

            The strange thing is that a different service (login) is working as desired: the decoded result is a LoginResult object with populated properties. I can't wrap my mind around why getModels is giving a result of the <model> nodes and there's no sign of the <result> node anymore.

             

            - Aaron

            • 3. Re: SOAP decoding collections
              Aaron Beall Level 3

              In other words, this response:

               

              <response>
                   <user>...</user>
              </response>
              

               

              Maps correctly to this object:

               

              class LoginResponse {
                   public var user:User;
              }
              

               

              But this response:

               

              <response>
                   <models>
                        <model>...</model>
                        <model>...</model>
                        <model>...</model>
                   <models>
              </response>
              

               

              I would expect and want to map to this:

               

              class ModelResponse {
                   public var models:Array; // of Model
              }
              

               

              But instead I get an ArrayCollection of Model objects... what did the decoder do with the <response> and <models> nodes??

               

              -Aaron

              • 4. Re: SOAP decoding collections
                JoshBeall Level 1

                Interesting, I wasn't aware of this method of interacting with SOAP services.  I'm guessing it's how the Flash Builder's UI is working under the covers, but I've never messed with it.

                 

                How do you define your mapping between the types you've defined and the XML?  Does Flex just try to automagically figure out what XML looks like it's the same "shape" as one of your registered types?

                 

                I'm thinking there may be a way to explicitly map your types to different parts of your XML response.  That's what you would do in the "Configure return types" screen.

                 

                The other thing you could do is try stepping through the deserialization code to try and understand what it's doing.

                 

                  -Josh

                • 5. Re: SOAP decoding collections
                  JoshBeall Level 1

                  What's the exact error you get trying to import the WSDL?  If you post it here, maybe somebody could help get it figured out.  If you can get the data services UI in Flash Builder working, I bet it will make this problem more manageable.

                  • 6. Re: SOAP decoding collections
                    Aaron Beall Level 3

                    Yes I suppose the mapping is subject to Flex magic, I don't explicitly tell it what the return type of a service is, it [tries to] figure it out based on the WSDL I guess. That's the problem here I suppose. I'm looking for a way to define the return type, which it looks like there are some ways.

                     

                    The exact WSDL error on the Data/Service screen is:

                     

                    Unable to retrieve operations and entities from the specified WSDL.

                     

                    Reason:

                    There was an error during service introspection.

                     

                    >> Details

                      src-resolve: Cannot resolve the name 'user:user' to a(n) 'element declaration' component.

                      src-resolve: Cannot resolve the name 'admin:group' to a(n) 'element declaration' component.

                      src-resolve: Cannot resolve the name 'model:model' to a(n) 'element declaration' component.

                      src-resolve: Cannot resolve the name 'general:id' to a(n) 'element declaration' component.

                     

                    Those are types that are part of import XSD statements in the WSDL.

                     

                    - Aaron

                    • 7. Re: SOAP decoding collections
                      Aaron Beall Level 3

                      It gets weirder.

                       

                      I had the backend developer change the response to include a dummy string variable:

                       

                      <response>

                           <dummy>...</dummy>

                           <models>

                                <model>...</model>

                           </models>

                      </response>

                      And now it works. I get a ModelResponse with the "dummy" and "models" properties correctly populated.

                       

                      -Aaron

                      • 8. Re: SOAP decoding collections
                        JoshBeall Level 1

                        Definitely sounds like some Flex automagical stuff is happening... does the WSDL validate?  A quick Google search reveals some WSDL validators... I would have thought that Flash Builder would be able to pull in properly referenced XSD files, so I'm wondering if there's something wrong with the WSDL.  Possible?

                         

                        http://wsdl-analyzer.com/

                        http://www.validwsdl.com/

                        • 9. Re: SOAP decoding collections
                          Aaron Beall Level 3

                          Neither of those validators worked for my WSDL (the first one gave a server error, the second one requires a public web url but the WSDL is not public) but SoapUI says all is correct. There are actually multiple WSDLs involved and they all check-out fine according to SoapUI.

                           

                          It looks like individual soap operations have a resultType and resultElementType I'm going to look into on Tuesday.

                           

                          -Aaron

                          • 10. Re: SOAP decoding collections
                            Aaron Beall Level 3

                            This comment in XMLDecoder/decodeSequence() seems to be the problem:

                             

                                    // hasSiblings is passed down to decodeGroupElement to control whether

                                    // a maxOccurs > 1 element should be decoded as a nested array, or should

                                    // replace the parent. This handles the "wrapped array" special case,

                                    // where a sequence of one element with maxoccurs > 1 is meant to represent

                                    // an array, and not an object with a single property which is an array.

                                    // However, even if the current sequence definition matches the convention,

                                    // we should avoid assigning the array as the parent object if the sequence

                                    // context allows other elements outside this sequence to be siblings of

                                    // the array (such as elements defined in the base type of an extension).

                            Alright, so I think I get it, if the decoder finds a sequence that defines only one child with maxoccurs > 1 (ie a collection property) it wants to assign the property as the collection of children. This way you don't end up with a property which is an object with the collection assigned a property of the object. Eh, I just said differently the same thing as that comment. So in other words, it seems to be a way to make this XML:

                             

                            <message>
                                 <users>
                                      <user/>
                                      <user/>
                                      <user/>
                                 </users>
                            </message>
                            

                             

                            Map desirably to this structure:

                             

                            {
                                 users: [
                                      User,
                                      User,
                                      User
                                 ]
                            }
                            

                             

                            Instead of being undesirably mapped to this structure:

                            {
                                 users: {
                                      user: [
                                           User,
                                           User,
                                           User
                                      ]
                                 }
                            }
                            

                             

                            While having mixed children in the XML sequence:

                            <message>
                                 <count>3</count>
                                 <user/>
                                 <user/>
                                 <user/>
                            </message>
                            

                             

                            Magically maps to this structure:

                            {
                                 count: 3,
                                 user: [
                                      User,
                                      User,
                                      User
                                 ]
                            }
                            

                             

                            Which is fair, but after hours of XSD mucking I can't get this to work the way I want in any situation. It either collapses the collection into the parent and drops properties I want, or does not collapse the collection and I end up with the awkward object with collection property the comment seems to trying to avoid. Surely there's some way to make XSD and AS3 understand each other, but I can't figure it out. No wonder SOAP has fallen out of favor, this is ridiculously over-complicated!

                             

                            -Aaron