Appendix C. Forcing Actionscript class inclusion

C.1. Introduction

Once you move the configuration of your objects out of your source code and into an XML configuration you will notice a very common problem. Because there is not always a direct reference to certain classes inside your source code these classes will not end up being compiled into the resulting .swf file. Then, while running your application, you will encounter the dreaded "Error: A class with the name 'XXXXX' could not be found." message.

There is a variety of ways to force the compiler to include certain classes, in this section we will look at most of them.

C.1.1. Adding an anonymous code block

Place this anywhere in your code, at the top of your application source for instance:

{
  Myclass1, Myclass2
}

C.1.2. Declaring a list of variables

Another way is to just declare a whole list of dummy variables with the required types:

private var _dummy1:Myclass1;
private var _dummy2:Myclass2;

or just one array of class declarations:

private var _includeClass:Array = [Myclass1,Myclass2];

C.1.3. Using the [Frame] metadata

There is an undocumented piece of metadata that will force the compiler to include a second or third class to an existing class source.

package com.myclasses
{
    [Frame(extraClass="com.myclasses.Myclass1")]
    [Frame(extraClass="com.myclasses.Myclass2")]
    public class MyMainClass
    {
    }
}

After that you only need to declare one variable of type MyMainClass in your source code.

C.1.4. Using a resource bundle

Its possible to create a .properties file that contains all the class references you. Create a file in your project called classreferences.properties and add your classes like this:

Class1   = ClassReference("com.myclasses.Myclass1")
Class2   = ClassReference("com.myclasses.Myclass2")

Then in your application source code add a reference to the resource like this:

[ResourceBundle("classreferences")]
private var _classReferences:ResourceBundle;

C.1.5. Using an ANT task as a prebuilder to generate a compiler config file

The last solution is a little more involved but can eventually automate the whole task of class inclusion, in this section we will explain step-by-step how to configure Flexbuilder to run a prebuilder.

C.1.5.1. Step 1 - Add a compiler switch to your project

Right click on your project in Eclipse/Flexbuilder and choose the menu item 'Properties', in the following popup add the compiler switch like this:

C.1.5.2. Step 2 – Create an XSLT ANT Task

Step 2 – Create an XSLT ANT Task In your project root (NOT your 'src' directory) create an XML file, call it 'springasprebuild.xml' (the same filename you used in the compiler switch), and in this file add the following code:

<!--
======================================================================
Nov 17, 2008 4:33:15 PM
project SpringAS Pre build
description Extracts all the class paths from a Spring Actionscript
configuration file and dumps them into
a config file that can be added with a compiler
switch (i.e. -load-config+=custom.config)
Roland Zwaga
====================================================================== -
->
<project name="project" default="default">
<description>
Extracts all the class paths from a Spring Actionscript configuration file and
dumps them in a config file that can be added with a compiler switch
(i.e. -load-config+=custom.config)
</description>
<!--
=================================
target: default
=================================
-->
<target name="default" description="description">
<xslt in="src/application-context.xml" out="src/springas.config"
style="xslt/springasconfig.xsl" reloadstylesheet="false"></xslt>
</target>
</project>

Take notice of XSLT element in the code, it has4 attributes:

  • in – this is the path to your Spring Actionscript configuration file

  • out – this is the path to the output file for the XSLT task, this is the file that was added as a compiler switch in the previous step.

  • style – This is the actual stylesheet that contains the necessary code to generate the output.

  • reloadstylesheet – only set this to true when you have made changes to the XSLT, otherwise leave it set to false.

C.1.5.3. Step 3 – Add the XSLT to your project

Create a new directory in your project root and call it 'xslt', create a new file in this directory called 'springasconfig.xsl'. Add the following code to the file:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:springas="http://www.springactionscript.org/schema/objects"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springactionscript.org/schema/objects
                http://www.springactionscript.org/schema/objects/spring-actionscript-objects-1.0.xsd "
exclude-result-prefixes="xsi springas">
  <xsl:output method="xml" indent="yes"/>
  <xsl:key name="restriction" match="//springas:object" use="@class" />
  <xsl:key name="proprestriction" match="//springas:property"
  use="@value" />
  <xsl:key name="valrestriction" match="//springas:value" use="." />
  <xsl:template match="/">
    <flex-config>
      <includes append="true">
        <xsl:for-each
        select="//springas:object[count(.|key('restriction',@class)[1]) = 1]">
          <xsl:sort select="@class"/>
          <xsl:if test="@class!=''">
            <symbol>
              <xsl:value-of select="@class"/>
            </symbol>
          </xsl:if>
        </xsl:for-each>
        <xsl:for-each
        select="//springas:property[count(.|key('proprestriction',@value)[1]) = 1]">
          <xsl:sort select="@value"/>
          <xsl:if test="@type='Class'">
            <symbol>
              <xsl:value-of select="@value"/>
            </symbol>
          </xsl:if>
        </xsl:for-each>
        <xsl:for-each
        select="//springas:value[count(.|key('valrestriction',.)[1]) = 1]">
          <xsl:sort select="."/>
          <xsl:if test="@type='Class'">
            <symbol>
              <xsl:value-of select="."/>
            </symbol>
          </xsl:if>
        </xsl:for-each>
      </includes>
    </flex-config>
  </xsl:template>
</xsl:stylesheet>

C.1.5.4. Step 4 – Add the ANT task as a builder

In the last step you add the ANT task as a builder to your project, do this by right clicking on your project, Choose 'Properties' and select the tab called 'Builders':

Click on 'New' and choose 'ANT Builder' and click 'OK', this dialog should appear:

Give the builder a logical name, something like 'Spring AS Prebuilder', afterwards click 'Browse workspace' beneath the 'Buildfile' input field, in the following dialog choose the Buildfile from the root of your current project. In case of this example its called 'springasprebuild.xml':

Then click 'OK' to return to the builder list. The builder you just added is in the wrong order still though. We want it to be the first builder to be executed in the build process, so select the ‘Spring AS Prebuilder’ in the list and click on 'Up', after this the list will look like this:

Click 'OK' and your project is configured!. To test whether everything is in working order, build your project. If all went according to plan then in the root of your source folder a new file has been created called 'springas.config'. The contents of this file will look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<flex-config>
  <includes append="true">
    <symbol>mx.messaging.channels.AMFChannel</symbol>
    <symbol>mx.messaging.ChannelSet</symbol>
    <symbol>mx.rpc.remoting.mxml.RemoteObject</symbol>
  </includes>
</flex-config>

And that's it, once in place this will take care of filtering out the classes from your Spring Actionscript configuration file.

Well, at least in most cases :)

C.1.6. Using Maven

If you use Maven as a build system for your application, Spring Actionscript also offers a mojo that will generate a flex compiler config file based on an application context. You can download the mojo here.

Download the zip file and open the directory it is contained in and run "mvn install" on the mojo to get it into your local repository.

Then use it your build like this:

...
<!-- set up properties to make it easy for both plugins (the prebuild and the maven-mojo) to use the same file locations -->
    <properties>
        <generatedCompilerConfigName>spring-as-includes.config</generatedCompilerConfigName>
        <generatedCompilerConfigDir>${project.build.sourceDirectory}</generatedCompilerConfigDir>
    </properties>
 <build>
       ...
        <plugins>
            <plugin>
                <groupId>org.springextensions.actionscript</groupId>
                <artifactId>prebuild-mojo</artifactId>
                <version>0.1-SNAPSHOT</version>
                <executions>
                    <execution>
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>generate-compiler-config</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <springActionscriptContextFiles>
                        <param>${basedir}/src/main/flex/YOUR-CONTEXT-FILE.xml</param>
                    </springActionscriptContextFiles>                    
                    <outputDirectory>${generatedCompilerConfigDir}</outputDirectory>
                    <generatedConfigFileName>${generatedCompilerConfigName}</generatedConfigFileName>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.sonatype.flexmojos</groupId>
                <artifactId>flexmojos-maven-plugin</artifactId>
                <version>3.6-SNAPSHOT</version>
                <configuration>
            ...
                    <configFiles>
                       <file>${generatedCompilerConfigDir}/${generatedCompilerConfigName}</file>
                    </configFiles>
       ...
                </configuration>

            </plugin>
        </plugins>
    </build>
...

And that's all there is to it!