Skip to content
This repository has been archived by the owner on May 29, 2024. It is now read-only.

Creator: Create a Custom Generator

Tako Schotanus edited this page Aug 14, 2019 · 8 revisions

In our HOWTO Create a Generator we learned how to create simple but still pretty powerful Generators without having to write a single line of code.

That's great! But what do you do when your Generator needs to perform some actions that aren't covered by the existing features?

Well if your action is one you think might be reusable by other Generators it might be a good idea to create a new Action and add it to the list of Available Actions

But sometimes the only thing left to do is just to create a completely custom class for your Generator.

These are the requirements for making a Generator:

  • Generators need resources that are stored subfolders of the catalog folder in the resources/META-INF folder of the Creator module
  • The folder name should be lower case and only contain letters, digits and hyphens (eg. "super-duper")
  • Any files that have to be copied should be contained in a sub folder called files
  • A file named info.yaml must exist with the following contents:
type: generator
name: Short description
description: Some longer description for the Generator
  • Generators also need a class that must be created in the io.fabric8.launcher.creator.catalog package
  • The class must have the same name as the folder but now Camel Cased (and without hyphens, eg. "SuperDuper")
  • The class must implement Generator.
  • It's recommended the class extends BaseGenerator.
  • Finally we need to register our Generator in the GeneratorInfo list. Just add a item to the end of the list with the exact same name we gave our Generator resource folder (eg. super-duper) and pass the constructor of our class to it. It would look something like this:
enum class GeneratorInfo(val klazz: GeneratorConstructor) {
    `database-crud-dotnet`,
    `database-crud-nodejs`,
    `database-crud-quarkus`,
      .
      .
      .
    `rest-dotnet`,
    `rest-nodejs`,
    `rest-quarkus`,
    `rest-springboot`,
    `rest-thorntail`,
    `rest-vertx`,
    `rest-wildfly`,
    `super-duper(::SuperDuper)`;

The Generator class

A Generator must normally do a bunch of menial tasks: generate OpenShift resources, copy files, make changes to configuration. That sort of thing. All of that is done in a single method that gets called when the Generator gets "applied" to the project that we're generating. To do that it must implement Generator.

This is what the API looks like:

fun apply(resources: Resources, props: Properties, extra: Properties): Resources

When called this method allows the Generator to make changes to the project we're generating and to the OpenShift/K8s Resources list that get passed in. Files can be copied and/or generated. It's also possible to update already pre-existing files (for example to add new dependencies a Maven POM file). When the Generator also needs new Resources to be created in the user's OpenShift project it can add them to the list that gets passed in and in the end that will be sent to OpenShift.

See Implementation Details for more details on using this API.

⚠️ Try not to make a Generator do too much, think of who would be maintaining the module for example. If a Generator could generate the code for all the available languages it would soon become pretty complex and all the different people or teams that have the necessary expertise for their particular language would have to collaborate on that one module. Better to create one module for each language. If there are many common elements, for example they use a lot of the same supporting non-code files, consider splitting those out into a different Generator. So make Generators simple, split them up into several different Generators and move any remaining complexity to the Capabilities.