16 Troubleshooting Guide

This chapter aims to summarize some of the more common error scenarios. It was compiled based on questions asked on the forum and will most likely grow over time. It would be nice if you'd follow the guidelines in this chapter and do some investigation yourself before you post on the forum in case you run into any kind of problem. Please start with 16.1 Configure Logging, as logging should be turned on in all debugging scenarios, and then jump to the section which applies to your problem.

16.1 Configure Logging

Some services in Parsley and also Flex Bindings in general do not rethrow errors. Thus you'd be completely tapping in the dark for some sorts of errors if logging is not turned on. For debugging Parsley applications it's usually sufficient to set a filter for org.spicefactory.parsley.* and avoid the logs from the underlying Spicelib, as the reflection cache emits some pretty verbose logs which would distract from the things you'd be interested in.

Log output from Parsley covers things like Contexts getting created or destroyed, objects getting configured or removed from the Context, messages getting dispatched or views getting wired.

The logging setup is usually done in the top level application class. It differs depending on the environment:

Flex 4

<fx:Declarations>
    <s:TraceTarget 
        includeCategory="true" 
        includeLevel="true" 
        includeTime="true"
        level="{LogEventLevel.DEBUG}"
        >
        <s:filters>
            <fx:String>org.spicefactory.parsley.*</fx:String>
        </s:filters>
    </s:TraceTarget>
</fx:Declarations>

Flex 3

<mx:TraceTarget 
    includeCategory="true" 
    includeLevel="true" 
    includeTime="true"
    level="{LogEventLevel.DEBUG}"
    >
    <mx:filters>
        <mx:String>org.spicefactory.parsley.*</mx:String>
    </mx:filters>
</mx:TraceTarget>

Flash

For Flash it is recommended to use XML configuration files as described in 15.2 Logging Configuration for Flash. If you want to use other configuration mechanisms for the rest of the application, you can still combine the XML for the logging setup with the other configuration artifacts:

FlashLoggingXmlSupport.initialize();
ContextBuilder
    .newBuilder()
    .config(XmlConfig.forFile("logging.xml"))
    .config(ActionScriptConfig.forClass(MyApplicationConfig))
    .build();

16.2 Silent Failure

Even after you have configured logging as described in the preceding section, you still might run into a situation where an expected action is not performed while the logging output remains completely silent about it. Since Parsley generally logs all errors this usually hints at a problem where the framework does not even attempt to perform the desired action. This is usually caused by some sort of configuration error. The following sections list the most common scenarios that lead to silent failure:

The object is not managed

Some developers new to the concept of IOC containers simply add metadata like [Inject] to a class and then create an instance with new and are suprised that nothing happens. Such an instance is not known to the framework and thus will never get configured. Another common error is to add the class to a Parsley configuration file or class as required and then create an instance with new. This is a similar problem: Now you have two instances of the same class, but the one you created with new is not managed by the framework.

If you are not familiar with the concept of managed objects, please read 8.1 About Managed Objects first.

If you are not sure whether the object you are working with is managed, you can use the framework API to find out:

var obj:SomeClass = ...; // the object that does not work
trace("managed? " + ContextUtil.isManaged(obj));

Apart from that you'll also find logs for all objects that are getting added or removed from a Context. They look like this:

21:09:07.967 [INFO] org.spicefactory.parsley.core.lifecycle.impl.DefaultManagedObjectHandler 
    Configure managed object with [ObjectDefinition(type = com.foo::MyClass, id = someId)] 
    and 2 processor(s)

Metadata not compiled into the SWF or SWC

Another very common error. The mxmlc compiler of the Flex SDK has a confusingly inconsistent behavior when it comes to compiling metadata into SWFs. The outcome is different whether you merge Parsley into the code or whether you specify it as an external library. As a consequence it usually works in the top level application without additional configuration steps, but then fails when used in a Flex Module for example.

To find out whether metadata has actually been compiled into your application, you can trace the reflection output of the Flash Player for that class:

var obj:SomeClass = ...; // the object that does not work
trace(describeType(obj));

Here you can see whether the metadata is present on the property or method where you expect it. For Flex Modules or RSLs the metadata usually has to be specified explicitly. For detailed instructions see 3.1 Configuration with AS3 Metadata, specifically the section titled Compiling custom metadata into SWFs.

Metadata on private or protected members

The Reflection facility in the Flash Player will only consider metadata on public members. This is not a limitation of the Parsley framework, it's the way the Flash Player works. Thus the following will simply be ignored, you won't get any error messages:

[Inject]
private var service:RemoteObject;

Typos in metadata

Although this is pretty obvious it's worth mentioning it as this also leads to silent failure. When you misspell an attribute on a Parsley metadata tag the framework will throw an Error, but if you misspell the tag name itself it will simply get ignored.

Timing issues with object initialization

Also a pretty common scenario. The dependency injection does get performed in this case, just not at the time the developer expects it. The most extreme example is trying to access the value of a variable marked with [Inject] in the constructor of an object. It should be pretty obvious that it is virtually impossible that the injection has already happened at this point.

Somewhat less obvious but still very common is to use a Flex component event like addedToStage or creationComplete and then access an expected injected value in the event handler. Please don't do this! There are lots of reasons not to use addedToStage for component initalization, some of them are not even related to Parsley. For the full story, please read 9.7 Component Lifecycle and specifically the section titled Be careful with Component Initialization Logic.

As a very short excerpt of that section, a safe place to put some initialization logic is a method marked with [Init]. This will only be invoked after all injections have been performed:

[Inject]
public var service1:SomeService;

[Inject]
public var service2:SomeOtherService;

[Init]
public function init () : void {
    // here it is guaranteed that service1 and service2 have been set already
}

16.3 Problems with View Wiring

For wiring components it's important to understand the lifecycle of Flex components in relation to Parsley object management. One problem with misplaced initialization logic (that does not only affect views) has already been described in the preceding section under Timing issues with object initialization. This section lists some of the most frequent issues purely related to wiring views.

Errors when re-adding a view to the stage

The default behavior for a wired view (no matter whether you are using view autowiring or the <Configure> tag) is to remove the view from the Context once the view is removed from the stage. This is the most convenient option as this is what is required in many scenarios where views are not developed for reuse. But when you do reuse a view and are not aware of this behavior you will encounter unexpected behavior. Dependencies like presentation models might get injected for a second time for example, causing the view to lose its internal state.

Fortunately there are ways to prevent this, as this is just the default behavior. For more details see 9.7 Component Lifecycle, preferrably including the section Beware of Memory Leaks as changing the default behavior might indeed solve your problem, but at the same time introduce leaks if not done correctly.

If the <ContextBuilder> tag itself is placed into a view, you might even encounter the situation where the entire Context gets destroyed when you remove the view from the stage. Again this is only the default that can be switched off like explained in 9.7 Component Lifecycle.

Error: Object of type [SomeViewClass] is already managed

Parsley 2.4 introduced checks to prevent the same object getting wired twice, potentially to two different Contexts which could cause non-deterministic behavior. If you see this error it might have any of the following causes:

Problems with popups and AIR windows

When wiring views in popups or AIR windows some additional steps need to be performed as these types of components are not placed into the normal view hierarchy below the root Application component. The basics are explained in 9.8 Flex Popups and Native AIR Windows. If you follow these instructions and still run into problems, they might be caused by one of the following issues:

16.4 Problems with Modules

Applications that load modules are usually also multi-Context applications, as each module normally creates at least one internal Context within the module. Errors when working with modules usually occur when the Contexts in the various layers do not "connect" correctly or when a view is wired to the wrong Context. This often comes as a surprise as there is a lot of magic happening under the hood when you load a module and/or create a child Context. Parsley usually connects them automatically, creating a Context hierarchy that matches the view hierarchy the Contexts were created in. This way any child Context does always automatically share all dependencies from a parent Context. In some scenarios this magic does not work, most often due to a configuration issues. In very rare cases it might even be necessary to specify the parent Context and/or ApplicationDomain manually, which can be done through attributes of the <ContextBuilder> tag for example.

Reflection Errors ("Specified ApplicationDomain does not contain the class MyClass")

This can only happen when you load modules into child ApplicationDomains. Reflection errors usually have one of the following two causes:

Missing Dependencies

If you see errors that a specific dependency cannot be found, although you are sure that you declared it in a Context configuration file, then it is very likely that the view got wired to the wrong Context. See Problems with popups and AIR windows for a common error scenario.

Examining the log output also helps in this case, as it allows you to easily find out which Context connected to which parent and which view got wired to which Context. For an example lets assume that you create the root application Context using MyRootConfig as the MXML configuration class and then MyModuleConfig as the configuration for the module. Inside the module you have a view of type MyWindow that needs to get wired. If all goes well you should find these three entries in the log output (intertwined with other logs):

22:18:54.953 [INFO] org.spicefactory.parsley.core.bootstrap.impl.DefaultBootstrapConfig
Creating Context [Context(FlexConfig{MyRootConfig})] without parent

[...]

22:19:01.270 [INFO] org.spicefactory.parsley.core.bootstrap.impl.DefaultBootstrapConfig 
Creating Context [Context(FlexConfig{MyModuleConfig})] 
with parent [Context(FlexConfig{MyRootConfig})]

[...]

22:19:01.544 [DEBUG] org.spicefactory.parsley.core.view.impl.DefaultViewConfigurator 
Add view 'My_Module.ApplicationSkin2._AppSkin_Group1.contentGroup.TestModule23.MyWindow25' 
to [Context(FlexConfig{MyModuleConfig})]

Here you can examine that the module Context found its parent (the root ApplicationContext) and the view MyWindow got wired to the module Context and not to the root Context.

You can also improve the readability of the logs when you set the description attribute explicitly in the ContextBuilder:

<parsley:ContextBuilder config="{MyRootConfig}" description="root"/>

This would turn the output [Context(FlexConfig{MyRootConfig})] into just [Context(root)]. This does not make such a big difference if you use only one configuration class, but if you use multiple ones the default description would list them all.