3. Gas3 Code Generator

Overview

Externalizers usage in GraniteDS requires ActionScript3 beans that implement the flash.utils.IExternalizable interface for externalized JavaBeans. Writing and maintaining these ActionScript3 beans is tedious and a source of many errors. In order to solve this problem and accelerate Flex/J2EE application development, GraniteDS comes with an ActionScript3 code generator that writes AS3 beans for all externalized JavaBeans, with specific support for lazily loaded EJB 3 entities.

Additionally this ActionScript3 generator is able to write AS3 typed client proxies for exposed remote services. Compared to the usual Flex RemoteObject, this can greatly help development by bringing auto-completion and improved type-safety in Flex when using remote services. Starting with GraniteDS 2.2, Gas3 may also replicate validation annotations in order to use the Flex side validation framework (see 8. Bean Validation (JSR-303)) and may also be configured to generate Long, BigInteger and BigDecimal variable for their Java equivalents (see 2. Big Number Implementations).

This generator (named GAS3) is implemented as an Eclipse Builder plugin and as an Ant task. This Ant task is packaged as an Eclipse 3.2+ Ant plugin but may also be used outside of Eclipse for command line Ant calls.

The next sections introduce both Eclipse Builder and Ant task configurations and usages. You may also have a look at the Eclipse Plugins Installation section and at the Hello World revisited tutorial for a sample Eclipse Builder usage.

"Base" & Inherited ActionScript3 Classes

A common problem with code generators is the potential loss of manual modifications made in generated files. A generated file must be either generated once and only once, allowing for safe manual modifications, but it will not be able to reflect the modifications made in its model (JavaBeans), or regenerated each time its model has been changed, thus preventing safe manual modifications.

Gas3 uses the principle of "Base" and customizable inherited classes that lets you add methods to generated classes without facing the risk of losing them when a new generation process is executed. For example, here are the two files generated for a given Java entity bean:

Welcome.java
package org.test;

import java.io.Serializable;

import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Welcome implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id @GeneratedValue
    private Integer id;
    
    @Basic
    private String name;

    public Welcome() {
    }

    public Welcome(String name) {
        this.name = name;
    }
	
    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

 

Welcome.as
/**
 * Generated by Gas3 v2.0.0 (Granite Data Services).
 *
 * NOTE: this file is only generated if it does not exist. You may safely put
 * your custom code here.
 */

package org.test {

    [Bindable]
    [RemoteClass(alias="org.test.Welcome")]
    public class Welcome extends WelcomeBase {
    }
}

 

WelcomeBase.as
/**
 * Generated by Gas3 v2.0.0 (Granite Data Services).
 *
 * WARNING: DO NOT CHANGE THIS FILE. IT MAY BE OVERWRITTEN EACH TIME YOU USE
 * THE GENERATOR. INSTEAD, EDIT THE INHERITED CLASS (Welcome.as).
 */

package org.test {

    import flash.utils.IDataInput;
    import flash.utils.IDataOutput;
    import flash.utils.IExternalizable;
    import org.granite.collections.IPersistentCollection;
    import org.granite.meta;

    use namespace meta;

    [Bindable]
    public class WelcomeBase implements IExternalizable {

        private var __initialized:Boolean = true;
        private var __detachedState:String = null;

        private var _id:Number;
        private var _name:String;

        meta function isInitialized(name:String = null):Boolean {
            if (!name)
                return __initialized;

            var property:* = this[name];
            return (
                (!(property is Welcome) || (property as Welcome).meta::isInitialized()) &&
                (!(property is IPersistentCollection) ||
                  (property as IPersistentCollection).isInitialized())
            );
        }

        public function get id():Number {
            return _id;
        }

        public function set name(value:String):void {
            _name = value;
        }
        public function get name():String {
            return _name;
        }

        public function readExternal(input:IDataInput):void {
            __initialized = input.readObject() as Boolean;
            __detachedState = input.readObject() as String;
            if (meta::isInitialized()) {
                _id = function(o:*):Number {
                    return (o is Number ? o as Number : Number.NaN) } (input.readObject());
                _name = input.readObject() as String;
            }
            else {
                _id = function(o:*):Number {
                    return (o is Number ? o as Number : Number.NaN) } (input.readObject());
            }
        }

        public function writeExternal(output:IDataOutput):void {
            output.writeObject(__initialized);
            output.writeObject(__detachedState);
            if (meta::isInitialized()) {
                output.writeObject(_id);
                output.writeObject(_name);
            }
            else {
                output.writeObject(_id);
            }
        }
    }
}

The recommendations for manual editing are explicit in the header comments of each AS3 classes: while the "Base" class may be regenerated at any time, keeping it sync with its Java model class, the inherited one is only generated when it does not exist and you may safely add custom methods into it.

This two files generation principle is used for all generated classes except interface and enum: these classes are generated without any "Base" class and overwritten each time you have modified their Java counterparts. Note: Do not modify manually generated ActionScript3 interface or enum classes!.

Here are the details for (re)generation conditions:

Templates Conditions for (re)generation
Dual templates (base + inherited) The inherited AS3 class is generated only once if it does not exist. The AS3 base one is generated if it does not exist or if its timestamp (last modified time) is less than the Java class one
Single template (enums or interfaces) Like the base condition above, the AS3 class is (re)generated if it does not exist or if its timestamp is less than the Java class one

Note that for Java classes, relevant timestamp is the last modified time of the .class file, not the .java file.

Java Classes & Corresponding Templates

Here is the summary of templates used by the generator depending on the kind of Java class it encounters:

Java Class Template Base Template
JPA entity beans: all classes annotated by @Entity and @MappedSuperclass entity.gsp entityBase.gsp, or tideEntityBase.gsp for Tide projects
Java enums enum.gsp (none)
Java interfaces interface.gsp (none)
Java services: all classes annotated by @RemoteDestination remote.gsp remoteBase.gsp, or tideRemoteBase.gsp for Tide projects
Java events: all classes annotated by @TideEvent bean.gsp beanBase.gsp
All other Java classes bean.gsp beanBase.gsp

Note that all these templates are bundled in the granite-generator.jar archive, in the org.granite.generator.template package and accessible as resources via the class loader.

Known Limitations

Gas3 does not support inner classes except of enum type. You must declare your classes in separated source files if you want them to be correctly handled by the generator.

Gas3 never deletes files, if you have removed or renamed a Java class, the old AS3 class versions must be manually removed.


Browse Space

- Pages
- Blog
- Labels
- Attachments
- Bookmarks
- Mail
- Advanced

Explore Confluence

- Popular Labels
- Notation Guide

Your Account

Log In

Other Features

Add Content


Copyright © 2011 Granite Data Services S.A.S. All Rights Reserved.