21 Replies Latest reply on May 22, 2012 1:02 PM by neoX286

    Updated Groovy template for GraniteDS Builder (gas3)

    neoX286

      Just wanted to post this here in case anyone else was getting frustrated by the use of iExternalizable from the gas3 system from GraniteDS.  Just save the template as a .gsp file and update your GraniteDS nature to point the Entity template to your file (note: don't get confused by their docs, when you edit the location just put the DIRECT path to your file, and use forward slashes only...don't prefix it with 'file:' as they misleadingly insinuate (they are not wrong, just misleading)...i.e. c:/myTemplates/myTemplate.gsp)

       

      In addition to that, I also stripped out the specialized GraniteDS datatypes in favor of the LCDS serialization convention that Adobe uses (i.e. a Java map should translate to an 'Object' type, a Java enum should translate to a 'String', and Java collections should always serialize as 'ArrayCollection')

       

      For our application, we didn't do a 'base' version and a version that doesnt get touched by the code generator, but you could easily do so by modifying this template...it's not difficult...But if you just need a template that generates a LCDS compatible Actionscript class for your remoting service, this will do the trick:

       

      I have two versions, this one is meant for Managed entities:

      <%--

        GRANITE DATA SERVICES

        Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.

       

       

        This file is part of Granite Data Services.

       

       

        Granite Data Services is free software; you can redistribute it and/or modify

        it under the terms of the GNU Library General Public License as published by

        the Free Software Foundation; either version 2 of the License, or (at your

        option) any later version.

       

       

        Granite Data Services is distributed in the hope that it will be useful, but

        WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

        FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License

        for more details.

       

       

        You should have received a copy of the GNU Library General Public License

        along with this library; if not, see <http://www.gnu.org/licenses/>.

       

       

        @author Franck WOLFF

        Updated by Robert Petz

                Removed iExternalizable interface

                Switched 'Bindable' for 'Managed'

                Switched to Adobe's preferred serialization of Java to Actionscript

      --%><%

          Set as3Imports = new TreeSet();

       

       

          if (jClass.hasEnumProperty())

              as3Imports.add("org.granite.util.Enum");

       

       

          for (jImport in jClass.imports) {

              if (jImport.as3Type.hasPackage() && jImport.as3Type.packageName != jClass.as3Type.packageName)

                  as3Imports.add(jImport.as3Type.qualifiedName);

          }

       

       

      %>/**

      * WARNING: DO NOT CHANGE THIS FILE. IT WILL BE OVERWRITTEN EACH TIME YOU USE THE GENERATOR.

      * Modified by: Robert Petz, May 2012

      */

       

       

      package ${jClass.as3Type.packageName}

      {<%

      ///////////////////////////////////////////////////////////////////////////////

      // Write Import Statements.

          for (as3Import in as3Imports) { if (as3Import != "org.granite.math" && as3Import != "org.granite.collections") { if (as3Import == "mx.collections.ListCollectionView" || as3Import == "IList") { as3Import = "mx.collections.ArrayCollection" }%>

          import ${as3Import};<%

          }}

          if (jClass.as3Superclass != null) {%>

          import ${jClass.as3Superclass.qualifiedName};<%

          }

       

       

      ///////////////////////////////////////////////////////////////////////////////

      // Write Class Declaration.%>

       

       

          [Managed]

          [RemoteClass(alias="${jClass.qualifiedName}")]

          public class ${jClass.as3Type.name}<%

       

       

              boolean implementsWritten = false;

              if (jClass.superclass != null) {

                  %> extends ${jClass.superclass.as3Type.name}<%

              } else {

                        if (jClass.as3Superclass != null) {

                        %> extends ${jClass.as3Superclass.name}<%

                        }

              }

       

       

              for (jInterface in jClass.interfaces) {

                  if (!implementsWritten) {

                      %> implements ${jInterface.as3Type.name}<%

       

       

                      implementsWritten = true;

                  } else {

                      %>, ${jInterface.as3Type.name}<%

                  }

              }

          %>

          {<%  ///////////////////////////////////////////////////////////////////////////

          // Write Private Fields.

          for (jProperty in jClass.properties) {

                aName = jProperty.as3Type.name

                if (aName == "IList") { aName = "ArrayCollection" }

                if (aName == "ListCollectionView") { aName = "ArrayCollection" }

                if (aName == "IMap") { aName = "Object" }

                if (aName == "Long") { aName = "Number" }

                if (aName == "BigInteger") { aName = "Number" }

                if (aName == "BigDecimal") { aName = "Number" }

                if (aName == "MathContext") { aName = "Number" }

                if (aName == "RoundingMode") { aName = "Number" }

              if (jProperty instanceof org.granite.generator.as3.reflect.JavaMember) {%>

              ${jProperty.access} var _${jProperty.name}:${aName};<%

              }

              else {%>

              private var _${jProperty.name}:${aName};<%

              }

          }

       

       

          ///////////////////////////////////////////////////////////////////////////

          // Write Public Getter/Setter.

       

       

          for (jProperty in jClass.properties) {

                aName = jProperty.as3Type.name

                if (aName == "IList") { aName = "ArrayCollection" }

                if (aName == "ListCollectionView") { aName = "ArrayCollection" }

                if (aName == "IMap") { aName = "Object" }

                if (aName == "Long") { aName = "Number" }

                if (aName == "BigInteger") { aName = "Number" }

                if (aName == "BigDecimal") { aName = "Number" }

                if (aName == "MathContext") { aName = "Number" }

                if (aName == "RoundingMode") { aName = "Number" }

       

       

              if (jProperty.readable || jProperty.writable) {%>

       

       

                /**

                 * @public ${jProperty.name}

                 */<%

                  if (jProperty.writable) {%>

              public <%= jProperty.writeOverride ? "override " : "" %>function set ${jProperty.name}<% if (jProperty.name == aName) { %>_<% } %>(value:${aName}):void

                          { _${jProperty.name} = value; }<%

                  }

                  if (jProperty.readable) {

                      if (!jProperty.writable) {%>

              [Bindable(event="unused")]<%

                                        }

                      if (jClass.metaClass.hasProperty(jClass, 'constraints') && jClass.constraints[jProperty] != null) {

                                for (cons in jClass.constraints[jProperty]) {%>

                    [${cons.name}<%

                                                            if (!cons.properties.empty) {%>(<%}

                                                            cons.properties.eachWithIndex{ p, i -> if (i > 0) {%>, <%}%>${p[0]}="${p[1]}"<%}

                                                            if (!cons.properties.empty) {%>)<%}%>]<%

                                                  }

                      }%>

              public <%= jProperty.readOverride ? "override " : "" %>function get ${jProperty.name}<% if (jProperty.name == aName) { %>_<% } %>():${aName}

                          { return _${jProperty.name}; }<%

                  }

              }

          }

       

       

          ///////////////////////////////////////////////////////////////////////////

          // Write Public Getters/Setters for Implemented Interfaces.

       

       

          if (jClass.hasInterfaces()) {

              for (jProperty in jClass.interfacesProperties) {

                  if (jProperty.readable || jProperty.writable) {%>

      <%

                      if (jProperty.writable) {%>

              public function set ${jProperty.name}(value:${jProperty.as3Type.name}):void {

              }<%

                      }

                      if (jProperty.readable) {%>

              public function get ${jProperty.name}():${jProperty.as3Type.name} {

                  return ${jProperty.as3Type.nullValue};

              }<%

                      }

                  }

              }

          }%>

          }

      }

       

      And this one is meant for non managed entities:

       

      <%--

        GRANITE DATA SERVICES

        Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.

       

       

        This file is part of Granite Data Services.

       

       

        Granite Data Services is free software; you can redistribute it and/or modify

        it under the terms of the GNU Library General Public License as published by

        the Free Software Foundation; either version 2 of the License, or (at your

        option) any later version.

       

       

        Granite Data Services is distributed in the hope that it will be useful, but

        WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

        FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License

        for more details.

       

       

        You should have received a copy of the GNU Library General Public License

        along with this library; if not, see <http://www.gnu.org/licenses/>.

       

       

        @author Franck WOLFF

        Updated by Robert Petz

                Removed iExternalizable interface

                Switched to Adobe's preferred serialization of Java to Actionscript

      --%><%

          Set as3Imports = new TreeSet();

       

       

          if (jClass.hasEnumProperty())

              as3Imports.add("org.granite.util.Enum");

       

       

          for (jImport in jClass.imports) {

              if (jImport.as3Type.hasPackage() && jImport.as3Type.packageName != jClass.as3Type.packageName)

                  as3Imports.add(jImport.as3Type.qualifiedName);

          }

       

       

      %>/**

      * WARNING: DO NOT CHANGE THIS FILE. IT WILL BE OVERWRITTEN EACH TIME YOU USE THE GENERATOR.

      * Modified by: Robert Petz, May 2012

      */

       

       

      package ${jClass.as3Type.packageName}

      {<%

      ///////////////////////////////////////////////////////////////////////////////

      // Write Import Statements.

          for (as3Import in as3Imports) { if (as3Import != "org.granite.math" && as3Import != "org.granite.collections") { if (as3Import == "mx.collections.ListCollectionView" || as3Import == "IList") { as3Import = "mx.collections.ArrayCollection" }%>

          import ${as3Import};<%

          }}

          if (jClass.as3Superclass != null) {%>

          import ${jClass.as3Superclass.qualifiedName};<%

          }

       

       

      ///////////////////////////////////////////////////////////////////////////////

      // Write Class Declaration.%>

       

       

          [Bindable]

          [RemoteClass(alias="${jClass.qualifiedName}")]

          public class ${jClass.as3Type.name}<%

       

       

              boolean implementsWritten = false;

              if (jClass.superclass != null) {

                  %> extends ${jClass.superclass.as3Type.name}<%

              } else {

                        if (jClass.as3Superclass != null) {

                        %> extends ${jClass.as3Superclass.name}<%

                        }

              }

       

       

              for (jInterface in jClass.interfaces) {

                  if (!implementsWritten) {

                      %> implements ${jInterface.as3Type.name}<%

       

       

                      implementsWritten = true;

                  } else {

                      %>, ${jInterface.as3Type.name}<%

                  }

              }

          %>

          {<%  ///////////////////////////////////////////////////////////////////////////

          // Write Private Fields.

          for (jProperty in jClass.properties) {

                aName = jProperty.as3Type.name

                if (aName == "IList") { aName = "ArrayCollection" }

                if (aName == "ListCollectionView") { aName = "ArrayCollection" }

                if (aName == "IMap") { aName = "Object" }

                if (aName == "Long") { aName = "Number" }

                if (aName == "BigInteger") { aName = "Number" }

                if (aName == "BigDecimal") { aName = "Number" }

                if (aName == "MathContext") { aName = "Number" }

                if (aName == "RoundingMode") { aName = "Number" }

              if (jProperty instanceof org.granite.generator.as3.reflect.JavaMember) {%>

              ${jProperty.access} var _${jProperty.name}:${aName};<%

              }

              else {%>

              private var _${jProperty.name}:${aName};<%

              }

          }

       

       

          ///////////////////////////////////////////////////////////////////////////

          // Write Public Getter/Setter.

       

       

          for (jProperty in jClass.properties) {

                aName = jProperty.as3Type.name

                if (aName == "IList") { aName = "ArrayCollection" }

                if (aName == "ListCollectionView") { aName = "ArrayCollection" }

                if (aName == "IMap") { aName = "Object" }

                if (aName == "Long") { aName = "Number" }

                if (aName == "BigInteger") { aName = "Number" }

                if (aName == "BigDecimal") { aName = "Number" }

                if (aName == "MathContext") { aName = "Number" }

                if (aName == "RoundingMode") { aName = "Number" }

       

       

              if (jProperty.readable || jProperty.writable) {%>

       

       

                /**

                 * @public ${jProperty.name}

                 */<%

                  if (jProperty.writable) {%>

              public <%= jProperty.writeOverride ? "override " : "" %>function set ${jProperty.name}<% if (jProperty.name == aName) { %>_<% } %>(value:${aName}):void

                          { _${jProperty.name} = value; }<%

                  }

                  if (jProperty.readable) {

                      if (!jProperty.writable) {%>

              [Bindable(event="unused")]<%

                                        }

                      if (jClass.metaClass.hasProperty(jClass, 'constraints') && jClass.constraints[jProperty] != null) {

                                for (cons in jClass.constraints[jProperty]) {%>

                    [${cons.name}<%

                                                            if (!cons.properties.empty) {%>(<%}

                                                            cons.properties.eachWithIndex{ p, i -> if (i > 0) {%>, <%}%>${p[0]}="${p[1]}"<%}

                                                            if (!cons.properties.empty) {%>)<%}%>]<%

                                                  }

                      }%>

              public <%= jProperty.readOverride ? "override " : "" %>function get ${jProperty.name}<% if (jProperty.name == aName) { %>_<% } %>():${aName}

                          { return _${jProperty.name}; }<%

                  }

              }

          }

       

       

          ///////////////////////////////////////////////////////////////////////////

          // Write Public Getters/Setters for Implemented Interfaces.

       

       

          if (jClass.hasInterfaces()) {

              for (jProperty in jClass.interfacesProperties) {

                  if (jProperty.readable || jProperty.writable) {%>

      <%

                      if (jProperty.writable) {%>

              public function set ${jProperty.name}(value:${jProperty.as3Type.name}):void {

              }<%

                      }

                      if (jProperty.readable) {%>

              public function get ${jProperty.name}():${jProperty.as3Type.name} {

                  return ${jProperty.as3Type.nullValue};

              }<%

                      }

                  }

              }

          }%>

          }

      }

       

       

      Hope this saves someone some time, I just threw this together pretty quickly for my own uses (using my preferred brace formatting) but feel free to expand upon it...I should note that this is a modified version of Granite DS's stock template, and all credit goes to them for gas3 and the template and such and such

       

      When I get around to it I'll go ahead and add in some more data to the type ahead as well...

        • 1. Re: Updated Groovy template for GraniteDS Builder (gas3)
          Franck W

          Robert,

           

          Thanks for the updated templates. What about contributing these templates to GraniteDS? It wouldn't be complicated to add an option to the GraniteDS builder (and the Ant task) so it would use your LCDS templates instead of genuine GraniteDS' ones.

           

          If you are interested, post a JIRA issue with your files here.

           

          And we will fix the documentation about the misleading "file:" prefix and forward slashes, thanks for the hint.

           

          Franck.

          • 2. Re: Updated Groovy template for GraniteDS Builder (gas3)
            neoX286 Level 1

            Hi Franck!  You guys are more than welcome to use them, but if I were to do it the right way I wouldn't use these templates as they are only a patch rather than a fix...the type stuff is handled in the template through the use of if statements, but the proper way to resolve the type problem for Adobe's Java -> Actionscript serialization is to update the As3TypeFactory and As3Type classes to use Adobe's type conversions (as I'm sure you already know)...the change for creating a managed class as opposed to a non managed class is to replace the '[Bindable]' metadata with the '[Managed]' metadata, so that could easily be done with a passed in property from gas3...since you guys have the ability to do it the right way, that makes more sense of course

             

            and sorry, didn't mean any offense about the 'file:' prefix, just noted it because it took me a few tests to finally get it to work correctly haha

            • 3. Re: Updated Groovy template for GraniteDS Builder (gas3)
              Franck W Level 1

              I'm going to try to integrate your templates (together with a proper As3TypeFactory) and I'll ask you to test the next build (I don't have LCDS).

               

              No offense with your "misleading but not wrong" (though it is quite a sophisticated distinction )

               

              F.

              • 4. Re: Updated Groovy template for GraniteDS Builder (gas3)
                neoX286 Level 1

                sounds like a plan, I have no problem testing it out for you

                • 5. Re: Updated Groovy template for GraniteDS Builder (gas3)
                  Franck W Level 1

                  Quick question: how do you distinguish managed beans from bindable beans? Is there any specific LCDS runtime annotation (eg: @Managed) on the Java side that would indicate that we need a managed bean on the Flex side?

                  • 6. Re: Updated Groovy template for GraniteDS Builder (gas3)
                    neoX286 Level 1

                    not really, unfortunately the entities are typically in a DAO which can either be local to the project or referenced in.  In our case, we reference in the DAO and use GDS on the DAO project itself, which has no knowledge of the service which is the only piece annotated as managed.  I just ran through the GDS UI and I think the best place to add the hook for creating it as 'Managed' instead would be to the package translater.  That way we can specifically say 'any entities created from this package should be flagged as managed, and any from this other package should not be'

                    • 7. Re: Updated Groovy template for GraniteDS Builder (gas3)
                      Franck W Level 1

                      I ended up with the following solution (you can download a new build of the plugin here):

                       

                      1. In the "Java Sources" tab panel, you can now "annotate" an included path with arbitrary options which will passed to the template as a Map<String, String>. For example, you can configure included paths like this: path/to/managed/beans/*.java[managed=true] and path/to/bindable/beans/*.java (default is to generate Bindable beans).
                      2. In the "Templates" tab panel, you will find a new button "Use LCDS". If you click on it, the templates will be configured for LCDS: no more entity/remote/enum templates (these classes are ignored) and specific ones for beans. By default, the bean templates are using the "base" dual file generation. If you don't like that, edit the bean templates, remove the second one set the first one to "class:org/granite/generator/template/lcdsStandaloneBean.gsp".
                      3. When you select LCDS in the "Templates" tab panel, the As3TypeFactory is automatically set to "org.granite.generator.as3.LCDSAs3TypeFactory" on the "Options" panel.

                       

                      Of course, I couldn't test anything with LCDS, tell me if it works or no.

                      • 8. Re: Updated Groovy template for GraniteDS Builder (gas3)
                        neoX286 Level 1

                        Sounds like a good solution to me, but when I drop that new build in and then add the graniteDS nature to the project it says 'the chosen operation is not currently available'...also, oddly, the icon dissappeared for the context window...I pulled back to the last release build and added the nature through that, then switched to the new build as well to see if that would work and then when I go to the GraniteDS property page it pops up sayin g'Unable to create the selected property page'

                        • 9. Re: Updated Groovy template for GraniteDS Builder (gas3)
                          Franck W Level 1

                          Took me two hours to understand that you need to uninstall the builder from the Eclipse's "Help" menu: removing manually the old version from the plugins directory isn't enough, because the plugin was originally installed through an update site and it still exists has a kind of ghost extension... Hate this kind of problem .

                           

                          So: open Eclipse, select "Help" -> "Install New Software...". Click on the "What is already installed?" (bottom right of the panel), select the GraniteDS Builder in the list and push the "Uninstall..." button. Close Eclipse, drop the new version of the builder in your plugins directory (make sure there no older version) and restart. It should work this time.

                           

                          I just made a new build with few minor changes (cleanup, version updated, etc.), you can download it here.

                          • 10. Re: Updated Groovy template for GraniteDS Builder (gas3)
                            neoX286 Level 1

                            strange, it's not in my installed items...but I guess that makes sense because I didn't use an update site, I just dropped the jars into my plugins folder.  I tried the new jar, still no luck...is there a newer version I need oft eh graniteds jar itself besides 2.3.1 GA?

                            • 11. Re: Updated Groovy template for GraniteDS Builder (gas3)
                              Franck W Level 1

                              Ok, my fault, I referenced a new Eclipse 3.5+ method which didn't compile with our Bamboo build process (based on Eclipse 3.4). Bamboo wasn't reporting any failure and I was testing the plugin with a "home made" build...

                               

                              Anyway, this is fixed now (I just made a test with the last Bamboo build #223): remove any prior version of the plugin, start and close Eclipse (so it can noticed a change), drop the new version and start again Eclipse.

                               

                              Thanks.

                              • 12. Re: Updated Groovy template for GraniteDS Builder (gas3)
                                neoX286 Level 1

                                I litterally just went to test this again and you posted up haha...it adds the nature correctly now (you icon is also back), and it builds great, but for some reason it skips any class annotated as '@Entity'...I couldn't get it to build that by including only the path to that package, or by having it build every class

                                 

                                btw love the annotation of '[managed=true]' on the package location, that is one of the best solutions for that

                                • 13. Re: Updated Groovy template for GraniteDS Builder (gas3)
                                  Franck W Level 1

                                  I thought you were just using DTOs... Should we use the same templates for entities (ie: bean and entities would use the same template configuration)?

                                  • 14. Re: Updated Groovy template for GraniteDS Builder (gas3)
                                    neoX286 Level 1

                                    yes, they would use the same configuration because ultimately on the flash side the classes are the same...it only needs a mirror copy of the entity on the client side for serialization purposes and for compiling purposes (i.e. the client needs to know what the type 'Goal' is, but it doesn't care how the server handles it, it only needs it to work with it as a general object)

                                    • 15. Re: Updated Groovy template for GraniteDS Builder (gas3)
                                      Franck W Level 1

                                      Here it is: GDS-224. Note that the two Java file types aren't sharing the same configuration (you can still configure custom templates for each one). So, if you want to use a "standalone" template, you'll have to modify the configuration twice.

                                      • 16. Re: Updated Groovy template for GraniteDS Builder (gas3)
                                        neoX286 Level 1

                                        That sounds 100% okay, I'm going to test this out here in just a few minutes, in the middle of some other stuff at the moment...I'll let you know once I have it tested out

                                        • 17. Re: Updated Groovy template for GraniteDS Builder (gas3)
                                          neoX286 Level 1

                                          Looks good, awesome stuff!  appreciate the LCDS integration, as I'm sure others will as well

                                           

                                           

                                          A tip to those who are using this:

                                          Add the Flex library nature to your DAO project, then have Granite deploy the Actionscript classes to a flex source folder that you defined in the flex library build path...then you can reference your Java DAO project from your Actionscript project AND your service project, which ensures that everything stays in sync and all projects utilize the same exact entities

                                          • 18. Re: Updated Groovy template for GraniteDS Builder (gas3)
                                            Franck W Level 1

                                            Great! I will announce the official release in this forum in the next coming days.

                                            Thanks for your help.

                                            • 19. Re: Updated Groovy template for GraniteDS Builder (gas3)
                                              neoX286 Level 1

                                              Sounds like a plan, no problem.  [EDIT: retracting original question]

                                               

                                               

                                              On another topic though, I wanted to note that I ran across one more serialization difference for the LCDS typefactory:  ByteArray should import 'flash.utils.ByteArray' rather than 'javassist.bytecode.ByteArray'