Page 1 of 1

The Build Class

PostPosted: Fri Jun 10, 2011 3:54 pm
by micha
The Build class is always avaiable in the template editor. It represents the build and contains methods to access all elements of a type as specified in the BuildConfig. For each Class X there is a method
Code: Select all
Build.allX

which returns all instances of the Class X as given by the selected packages and instances in the BuildConfig.

This is usually how you start in a template: You iterate over all instances of some class. An alternative is to specify
Code: Select all
Build.once

in your topmost context. This means that the context is iterated exaclty once. You can use this when you want to generate a single file.

It is possible that in future more methods get added to access further properties of the build.

Re: The Build Class

PostPosted: Fri Jun 10, 2011 6:30 pm
by GiUmaTo
On a related note, could you please provide documentation on BuildConfig (I guess in another thread).

Thanks

Re: The Build Class

PostPosted: Sat Jun 11, 2011 12:18 pm
by GiUmaTo
Apart from the request above, I do have an issue with templates and class hierarchies:

in my meta-model diagram I have a BaseEntity, then a DerivedEntity which inherits from the former:

ClassInheritanceDiagram.png
ClassInheritanceDiagram.png (5.25 KiB) Viewed 58995 times

They have one associated template each, BaseEntityTemplate and DerivedEntityTemplate.
BaseEntityTemplate selects by means of Build.allBaseEntity. DerivedEntityTemplate by means of Build.allDerivedEntity.
They both produce an output file with the same "rules", say: output/path/xxxEntity.name.java.

BaseEntityTemplate.png
BaseEntityTemplate.png (8.03 KiB) Viewed 58995 times

DerivedEntityTemplate.png
DerivedEntityTemplate.png (8.62 KiB) Viewed 58995 times

In my specific "instantiated" model, I have and instance of BaseEntity (MyBase) and an instance of DerivedEntity (MyDerived).
When I generate output starting from empty target folder, everything goes fine:

Code: Select all
*** Generate for scope ClassInheritance - src @ 11/06/11 14.10
Processing template com.example.classinheritance.templates.BaseEntityTemplate ...
  MyBase -> output/path/MyBase.java ... (Created)
  MyDerived -> output/path/MyDerived.java ... (Created)
Processing template com.example.classinheritance.templates.DerivedEntityTemplate ...
  MyDerived -> output/path/MyDerived.java ... (Overwritten)
*** End Generate for scope ClassInheritance @ 11/06/11 14.10 after 0.076 sec
*** processed 3 files, 2 new files, 1 file overwritten, wrote a total of 411 bytes.
scanning folder P/ClassInheritance for project config files..

But when I try to generate again the output without emptying the target folder, e.g. normally after some saved change, I got the following error:

Code: Select all
*** Generate for scope ClassInheritance - src @ 11/06/11 14.12
Processing template com.example.classinheritance.templates.BaseEntityTemplate ...
  MyBase -> output/path/MyBase.java ... (No Changes)

Generation Error in template com.example.classinheritance.templates.BaseEntityTemplate:
Attempted to overwrite the file src/output/path/MyDerived.java which was generated by another template!
Context stack:
- Build.allBaseEntity: BaseEntity=MyDerived
*** End Generate for scope ClassInheritance @ 11/06/11 14.12 after 0.017 sec
!!! 1 error, processed 1 file, 1 file unchanged, wrote a total of 0 bytes.

... and I suspect that after this error the output generation interrupts and does not update the remaining files. In this case, DerivedEntityTemplate is not run at all, as BaseEntityTemplate has encountered an error.

Anyway, how do I avoid this?

Thanks for your attention again.
Cheers

PS Please find attached the eclipse-exported project

Re: The Build Class

PostPosted: Sat Jun 11, 2011 1:08 pm
by micha
The first thing you should consider is, whether it makes sense to have completely different templates for BaseEntity and DerivedEntity. This makes only sense if the implementations are totally different.

Inside the template you can distinguish between BaseEntity and DerivedEntity using Filtering Contexts. If you want to generate some lines only for the DerivedEntities use a context with selector "BaseEntity:DerivedEntity" and put these lines there. Additionally, if you need to have something for BaseEntity only, you can put the break flag on the filtering context and put the lines for the BaseEntity below.

If you decide that two different templates is the way to go, you need to filter the subclasses out in the template for BaseEntity. To do this you need to create a context above (left of) the file context. (The file context is the context with the fatter line.) Then, on the topmost context you define the selector as "Build.allBaseEntity" and then use the second context as filter. To do so, you need to create a function with a name like"isBaseEntity" on the type BaseEntity which returns a boolean. Whenever the function returns false, the instance is skipped during generation. Therefore, you need to check the type in the function.

Step-by-step instructions:
  • Click on the file context to select it.
  • Use Alt-PageUp or the corresponding icon in the toolbar to navigate a context higher (The file context is deselected now)
  • Use Alt-Insert or the corresponding icon in the toolbar to create a new context. Specify "Build.allBaseEntity" as selector
  • Select the file context again
  • Write "BaseEntity" into the selector using content assist and type ".isNotDerived"
  • Choose new function from content assist
  • Specify BooleanLiteral as return type
  • CTRL-SHIFT click on the now underlined "isNotDerived" to get to the function implementation
  • Implement the function:
    "return !(baseEntity instanceof IDerivedEntity);"
    Be careful that the java import statement for the type IDerviedEntity at the beginning of the function is between the protected region tags. Otherwise the import will be removed from the generator.
  • The implementation can variy depending on what you expect to happen when there is a second class derived from BaseEntity.
  • You may have to remove the file that got previously falsely generated by the template.

The error that you have seen during generation is a protection against overwriting a file generated from one template by a file generated from a different template.

Hope this helps you :)

Re: The Build Class

PostPosted: Sun Jun 12, 2011 4:34 pm
by GiUmaTo
Actually in my actual project, I can go without two separate templates, and stick with a single template good for both of BaseEntities and DerivedEntities. So I tried to go that way.

What was blocking me was my understing that in a single template I cannot freely intermingle parts only for Base and parts only for Derived. As you said, if I want some lines only for Base (and not Derived), I have to mark the Break checkbox and put all the Derived part in the end, hence I cannot have something like the following:
Code: Select all
- Common part
--- Base only
------ Derived only
--- Base only
------ Derived only
- Common part

This is the way I solved it still using a single template, in case it might prove useful for someone else.
What I did was to change my meta-model so to have a common AbstractBaseEntity, then have both BaseEntity and DerivedEntity to inherit from that:
AbstractBaseInheritance.png
AbstractBaseInheritance.png (7.48 KiB) Viewed 58988 times

After that, the single template could be associated with AbstractBaseEntity, and inside that you can have separate sections for both BaseEntity and DerivedEntity.
AbstractBaseEntityTemplate.png
AbstractBaseEntityTemplate.png (7.92 KiB) Viewed 58988 times

Of course, as you can see, it's not that great solution if you really need to keep inheritance in place in your meta-model. Still, it is okay if you can put most of your base attributes in AbstractBase, then leave Base as a dummy placeholder, and Derived as a real derived entity. Again, if you have one more level of inheritance, you're stuffed :(

Re: The Build Class

PostPosted: Sun Jun 12, 2011 6:20 pm
by micha
As described in my last posting you can work with filtering Contexts: A context with a selector that returns a boolean is only generated if the selector retuns true. This also works inside a template. Like this you can write arbitrary filtering functions.