| View previous topic :: View next topic |
| Author |
Message |
giles.roadnight
Joined: 20 Jul 2009 Posts: 66 Location: London
|
Posted: Thu Aug 20, 2009 11:49 am Post subject: Creating an array of objects in context - created twice |
|
|
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 |
|
 |
Jens Halm Site Admin
Joined: 21 Sep 2007 Posts: 1498 Location: Cologne Germany
|
Posted: Thu Aug 20, 2009 12:07 pm Post subject: |
|
|
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 |
|
 |
Jens Halm Site Admin
Joined: 21 Sep 2007 Posts: 1498 Location: Cologne Germany
|
Posted: Fri Sep 18, 2009 2:59 pm Post subject: |
|
|
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 |
|
 |
giles.roadnight
Joined: 20 Jul 2009 Posts: 66 Location: London
|
Posted: Mon Sep 21, 2009 1:31 pm Post subject: |
|
|
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 |
|
 |
Jens Halm Site Admin
Joined: 21 Sep 2007 Posts: 1498 Location: Cologne Germany
|
Posted: Mon Sep 21, 2009 3:13 pm Post subject: |
|
|
| 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 |
|
 |
giles.roadnight
Joined: 20 Jul 2009 Posts: 66 Location: London
|
Posted: Mon Sep 21, 2009 3:18 pm Post subject: |
|
|
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 |
|
 |
|