Spicefactory Forum Index Spicefactory
Discuss Spicefactory Open Source Projects
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Creating an array of objects in context - created twice

 
Post new topic   Reply to topic    Spicefactory Forum Index -> Spicefactory - General Discussions
View previous topic :: View next topic  
Author Message
giles.roadnight



Joined: 20 Jul 2009
Posts: 66
Location: London

PostPosted: Thu Aug 20, 2009 11:49 am    Post subject: Creating an array of objects in context - created twice Reply with quote

Hi All

I have code similar to this in my context:

Code:

<Object
   id="bootstrapper"
   type="{ Bootstrapper }"
   >
   
   <Property
      name="name"
      value="bootstrap"
      />
   
   <Property name="children">
      
      <Array>
         
         <Object
            type="{ ResourceBundleLoader }"
            >
            <Property
               name="localeProvider"
               idRef="localeProvider"
               />
            <Property
               name="name"
               value="loadResourceBundles"
               />
            <Property
               name="resourceBundleName"
               value="Modules"
               />
         </Object>
         
         <Object
            type="{ ChannelConfigurationWorkItem }"
            >
            <Property
               name="name"
               value="channelConfiguration"
               />
         </Object>
            
      </Array>
      
   </Property>
   
</Object>


The bootstrapper gets created once but all objects in the array get created twice, but only one of the items ends up in the array. Both instances of the object respond to events.

I have just downloaded the latest build ( the 2.0.1 zip ).

Is this a known bug? Is there a better / different / workaround way to do this?

Thanks
_________________
Giles Roadnight
http://giles.roadnight.name
blog: http://blog.giles.roadnight.name
Back to top
View user's profile Send private message
Jens Halm
Site Admin


Joined: 21 Sep 2007
Posts: 1498
Location: Cologne Germany

PostPosted: Thu Aug 20, 2009 12:07 pm    Post subject: Reply with quote

I assume that this is an unknown issue then. Will look into that.
Only workaround that comes to my mind is temporarily using ObjectRef tags instead of inline declarations.

Btw: Just have put some [code] tags around your example.
_________________
Jens Halm
Spicefactory
Back to top
View user's profile Send private message
Jens Halm
Site Admin


Joined: 21 Sep 2007
Posts: 1498
Location: Cologne Germany

PostPosted: Fri Sep 18, 2009 2:59 pm    Post subject: Reply with quote

I finally found time to look into this. The cause of the issue turned out to be a big surprise, and it's definitely something which is not easy to solve. It's unfortunately the way how the mxmlc compiler behaves. When you look at your example, then everywhere you are using a binding like
Code:
{ ResourceBundleLoader }

the compiler creates a public property to execute the binding for. This means that all nested tags with bindings end up in line with the root tags you declare the objects with! When Parsley loops over the properties of the MXML configuration class it has no way to find out if the property was created for a root tag or a nested tag. This is because any type of object is allowed as a root tag, not just the ones known by the framework like the <Object> tag.

So to at least decrease the number of use cases that cause unexpected behaviour I could create a special tag for nested objects:
Code:
<NestedObject type="{ ... }"/>

I could add a marker interface like "NestedTag" to all tags that are only used inline and skip those if I find them as properties on the configuration class. But that still leaves a window for issues if you use simple tags as nested tags:
Code:
<Array>
    <mymodel:Person name="Mary" age="33"/>
    <mymodel:Person name="Kate" age="27"/>
</Array>

As soon as you replace any of the property values with a binding the Person will suddenly appear as a property of the configuration class. It would then get created twice: Once for the Array and once as a root object that would be available by context.getObjectByType(Person) then. That would certainly not be desirable as it may even break the consistency of your configuration.

Hopefully my explanations were clear. Of course this problem does not exist if your are using XML configuration. But for MXML all I can do is introduce that NestedTag marker interface. Which unfortunately is a bit counter-intuitive to tell users that they shouldn't use the regular <Object> tag for nested definitions.
_________________
Jens Halm
Spicefactory
Back to top
View user's profile Send private message
giles.roadnight



Joined: 20 Jul 2009
Posts: 66
Location: London

PostPosted: Mon Sep 21, 2009 1:31 pm    Post subject: Reply with quote

Thanks for investigating that Jens.

Now that we know why this is happening we can avoid it.

This solution:

Code:

<Array>
    <mymodel:Person name="Mary" age="33"/>
    <mymodel:Person name="Kate" age="27"/>
</Array>


Didn't work for me as I need these items to be configured and they are not in this case. Events are not routed.

This does work though:

Code:

<mx:Script>
   <![CDATA[
      import com.example.workitems.ChannelConfigurationWorkItem;
      import com.example.workitems.LogConfigurationWorkItem;
      
      //force import
      private var channelConfig : ChannelConfigurationWorkItem;
      private var logConfig : LogConfigurationWorkItem;
   ]]>
</mx:Script>

<Object
   id="bootstrapper"
   type="{ Bootstrapper }"
   >
   
   <Property
      name="name"
      value="bootstrap"
      />
   
   <Property name="children">
      
      <Array>
         
         <Object
            type="com.example.workitems.ChannelConfigurationWorkItem"
            >
            <Property
               name="name"
               value="channelConfiguration"
               />
         </Object>
         
         <Object
            type="com.example.workitems.LogConfigurationWorkItem"
            >
            <Property
               name="name"
               value="logConfiguration"
               />
         </Object>
         
      </Array>
      
   </Property>
   
</Object>

_________________
Giles Roadnight
http://giles.roadnight.name
blog: http://blog.giles.roadnight.name
Back to top
View user's profile Send private message
Jens Halm
Site Admin


Joined: 21 Sep 2007
Posts: 1498
Location: Cologne Germany

PostPosted: Mon Sep 21, 2009 3:13 pm    Post subject: Reply with quote

Quote:
This solution:

Code:

<Array>
<mymodel:Person name="Mary" age="33"/>
<mymodel:Person name="Kate" age="27"/>
</Array>

Didn't work for me as I need these items to be configured and they are not in this case. Events are not routed.

Just to avoid any confusion: I didn't post this example as a solution. Quite to the contrary I posted it as an example how you still might have problems in 2.1 where most other use cases have been fixed. Might become clear if you reread my post. The next release will require the use of a special tag (<NestedObject>) for inline definitions so I can skip them when they appear as properties on the class.
_________________
Jens Halm
Spicefactory
Back to top
View user's profile Send private message
giles.roadnight



Joined: 20 Jul 2009
Posts: 66
Location: London

PostPosted: Mon Sep 21, 2009 3:18 pm    Post subject: Reply with quote

Yup, thanks Jens. I was jsut trying a few different ways of declaring the objects whilst avoiding binding.

Using a string as type does solve the problem to some extent but not in this case:

Code:

<Object
   id="bootstrapper"
   type="{ Bootstrapper }"
   >
   
   <Property
      name="name"
      value="bootstrap"
      />
   
   <Property name="children">
      
      <Array>
         
         <Object
            id="parallelBundles"
            type="com.example.bootstrapper.WorkItemParallel">
            
            <Property name="children">
               
               <Array>
                  
                  <Object
                     type="com.example.bundles.ResourceBundleLoader"
                     >
                     <Property
                        name="resourceBundleName"
                        value="eui_client"
                        />
                  </Object>
                  
                  <Object
                     type="com.example.workitems.StylesWorkItem"
                     >
                     <Property
                        name="url"
                        value="assets/main.swf"
                        />
                  </Object>
                  
                  <Object
                     type="com.example.workitems.ChannelConfigurationWorkItem"
                     />
                  
               </Array>
               
            </Property>
            
         </Object>
         
         <Object
            type="com.example.workitems.LogConfigurationWorkItem"
            />
         
      </Array>
      
   </Property>
   
</Object>


Here LogConfigurationWorkItem is created once but ChannelConfigurationWorkItem, StylesWorkItem and ResourceBundleLoader all get created twice. I am assuming that this is because


Code:

<Property name="children">
    <Array>


behaves like a binding so we get the same problem. This should get fixed by your solution in 2.1 though.

Thanks again
_________________
Giles Roadnight
http://giles.roadnight.name
blog: http://blog.giles.roadnight.name
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Spicefactory Forum Index -> Spicefactory - General Discussions All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group