Dashboard > Documentation > ... > 3. Developer Guide > 2. Gas3 Code Generator

View Info

2. Gas3 Code Generator

 Documentation Summary
 Page Summary

Overview

Externalizers usage in GraniteDS requires ActionScript3 beans that implement the flash.utils.IExternalizable interface for each externalized Java bean. 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 Java beans, with specific support for lazy-loaded EJB 3 entities.

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 (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" and 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 safe manual modifications) but it won't be able to reflect the modifications made in its model (a Java bean) or regenerated each time its model has been changed (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 v1.2.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 v1.2.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 __laziness:String = null;

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

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

            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 {
            __laziness = 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(__laziness);
            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 doesn't exist and you may safely add custom methods into it.

This two files generation principle is used for all generated classes except enum: those classes are generated without any "Base" class and overwritten each time you have modified their Java counterparts (do not modify manually generated ActionScript3 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 doesn't exist). The AS3 base one is generated if it doesn't exist or if its timestamp (last modified time) is less than the Java class one
Single template (enums) Like the base condition above, the AS3 class is (re)generated if it doesn't 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 and 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
EJB 3 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 interfaceBase.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 doesn't 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
- Labels
- Attachments
- Mail
- Bookmarks
- News
- Activity
- Advanced

Explore Confluence
- Popular Labels
- Notation Guide

Your Account
Log In

Other Features

View a printable version of the current page.

Add Content
- Add Comment


Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.6.0 Build:#913 Sep 27, 2007)
Bug/feature request - Contact Administrators

SourceForge.net Logo
Copyright © 2007-2008 Adequate Systems. All Rights Reserved.