SWDES
Published on SWDES (https://swdes.net)

Home > Projects > Java projects > JGEN > JGEN - examples

JGEN - examples

How to use the JGEN template engine

JGEN is designed to generate Java source files from templates by information gathered from Java class files and other information provided by generator presets. JGEN might be extended in the future to support futher file types as well. JGEN is based on pure Java and when we configure it by defining own generator setups and presets, we do that in pure Java as well (unless we implement in a preset to gather information from externalized configurations). This way we can enjoy the full power of Java to configure JGEN, that is, we are not restricted by the capabilities of a DSL, script language or whatsoever, and moreover we do not need to learn a complex proprietary DSL or another script language and keep that knowledge in our developer team over the years even if we need new configurations or changes just seldom. Of course, every tool needs some learning how to use it, but thats not comparable to the efforts to learn and maintain a complex proprietary DSL or the like.

The JGEN source files are also used to demonstrate how to use the Navigator framework (as one possibility out of many), since Navigators are also ideal for parsers or the like.

We create a template file with any file extension, but the standard is to use "jgen", e.g. "HelloWorld.jgen". The content should be exactly what we want to generate into each generated file, except those parts which we want to replace dynamically with gathered values. Those replacements are marked in the template by specific symbols.

Hello §$ ADDRESSEE $§!

Here we want to replace "§$ ADDRESSEE $§" with "world" as a fixed replacement value or maybe we gather other addressee names from resources to replace it on a per-resource basis. As you can see "§$" is the symbol that marks the start of the replacement and "$§" is the symbol that marks the end of the replacement. These symbols can be changed in the GeneratorPreset. JGEN differs start and end solely for better readability of templates. For the same reason you can add as many spaces as you want before and after the symbol that denotes the replacement (here "ADDRESSEE"). We can use as symbol any text we want, but uppercase is better visible again. If a symbol that denotes the replacement is used more than one time in the template then all these occurrences of that same symbol will be replaced with the same value.

Replacements can also be nested, that is, a certain symbol will be replaced by the results of a previous run of the generator (using another template). So we can define complex replacement structures with templates used for parts of other templates. This comes in handy if we want to generate repetitive contents like a list of constructors and methods, where we have one template for the entire Java source file and one constructor template and one method template.

 

In general we can use JGEN in three ways: as an external tool, invoked via "JGen.main(String[])" or we invoke JGEN from our own application code using one of the static "generate"-methods, to actually generate files, or using one of the static "getGeneratedContent"-methods, to just get the generated contents for our own further processing.

Note: the method "JGen.main(String[])" takes as arguments one or several GeneratorSetup class names, something like "com.my.company.project.jgen.Setup".

Either way we have to provide some information to JGEN how to generate the contents and files. The overall configuration for a generation is organized in a GeneratorSetup, which contains the GeneratorPreset as well as properties for the overall behavior, e.g. indicators if JGEN is allowed to write to files or if JGEN is allowed to print to the standard print stream (console). The GeneratorPreset is the configuration for the generation of the contents itself, where we define for instance

  • the template file
  • start and end symbol
  • custom path to look up (recursively)
  • classpath selectors (classpath look up)
  • class file & filename selectors
  • class file validators (to filter classes)
  • symbol references (to assign values to symbols)
  • output file strategy (how to write files)

 

 

 

With the GeneratorPreset property customPaths we tell JGEN where to look for resources (class files), to gather information from. It takes a

Map<File, Boolean>

where the the Boolean indicates if JGEN shall lookup that path recursively.

With the property classPathSelectors we we select the classpath where JGEN shall lookup for resources (class files). JGEN gets the split Java classpath and will ask each ClassPathSelector if it accepts the individual path given as argument.

With the properties classFileSelectors and classFilenameSelectors we we select the class files which JGEN has found in the same manner as with the classpath. ClassFileSelectors and ClassFilenameSelectors extend the JSE interfaces java.io.FileFilter respectively java.io.FilenameFilter.

After all these selections of paths and files we might still need to filter out files in a cross-cutting manner by other criteria, to assert the aggregation of files by many different selectors does not contain files we must omit. We can do that by adding ClassFileValidators to the property classFileValidators.

The core business of JGEN as a template engine is of course to replace the symbols with values.

Values can be fixed values, that is, the value does not depend on a resource and does not change (but is normally not a hard coded literal). The fixed value can be dynamically constructed at the time we assemble the GeneratorPreset, but keeps the same during generation.

Values can be assigned to a key, that is, for each given key a value is returned, e.g. from a Map or resources with key value pairs, at generation time.

Values can be gathered from a Java class, that is, for each given Java class a value is returned at generation time.

To tell JGEN which symbol in the template is to be replaced by which value, we use the Map symbolReferences where assign the symbol in the template as Map key with a SymbolReference as Map value. The type SymbolReference has 3 direct extensions:

  • FixedSymbol (for fixed values)
  • KeySymbolAssignment (for key value assignments)
  • ClassElementType (for values gathered from classes)

 

At generation time, JGEN will pick the SymbolReference for the assigned template symbol and pass an argument to that SymbolReference. The type and content of the argument will depend on the type of the SymbolReference. For a FixedSymbol it is obsolete. For a KeySymbolAssignment it is a key, which is the template symbol. For a ClassElementType it is a found, selected and validated Java class.

 

Last but not least we should define an OutputFileStrategy. This will determine if files can be overwritten, existing files will be skipped and which is the output file. For the latter JGEN passes the found class to the strategy, so the strategy can use this to create the name and path / package for the output file.

Note: there is a DefaultOutputFileStrategy that can be extended for very easy changes of the path / package and file name.

 

Discover what you can do with JGEN to save implementation efforts!

 

 

 

More coming soon.

 

 


 

About the creator & author

 

 

© Some copyrights reserved. Please find the copyrights information in the web page footer.

Source URL: https://swdes.net/en/content/jgen-examples?page=2