Build Your Own Generator#

At BESSER, you can also build your own code generator. Code generators consist of M2T model-to-text transformations to automatically generate software artifacts from an input model (could be any type of model).

BESSER provides an interface (abstract class) called GeneratorInterface that you can inherit to build your code generator. This way, we standardize the use of BESSER code generators, improve maintainability, and usability (you can check the code of the GeneratorInterface in the repository).

As an example, let’s look at our Python class code generator below. Notice how this generator inherits from the GeneratorInterface class and defines two methods:

  • Constructor method __init__()

    this method contains the parameters model (indicating the B-UML model) and output_dir (the directory where the generated code will be stored) which is optional.

  • generate() method

    to generate the classes.py file. The M2T transformation (lines 30 to 34) is performed using Jinja, a templating engine for generating template-based documents. However, you could use the tool of your choice for these transformations.

 1import os
 2from jinja2 import Environment, FileSystemLoader
 3from besser.BUML.metamodel.structural import DomainModel
 4from besser.generators import GeneratorInterface
 5
 6class PythonGenerator(GeneratorInterface):
 7    """
 8    PythonGenerator is a class that implements the GeneratorInterface and is responsible for generating
 9    the Python domain model code based on the input B-UML model.
10
11    Args:
12        model (DomainModel): An instance of the DomainModel class representing the B-UML model.
13        output_dir (str, optional): The output directory where the generated code will be saved. Defaults to None.
14    """
15    def __init__(self, model: DomainModel, output_dir: str = None):
16        super().__init__(model, output_dir)
17
18    def generate(self):
19        """
20        Generates Python domain model code based on the provided B-UML model and saves it to the specified output directory.
21        If the output directory was not specified, the code generated will be stored in the <current directory>/output
22        folder.
23
24        Returns:
25            None, but store the generated code as a file named classes.py 
26        """
27        file_path = self.build_generation_path(file_name="classes.py")
28        templates_path = os.path.join(os.path.dirname(
29            os.path.abspath(__file__)), "templates")
30        env = Environment(loader=FileSystemLoader(templates_path))
31        template = env.get_template('python_classes_template.py.j2')
32        with open(file_path, mode="w") as f:
33            generated_code = template.render(classes=self.model.classes_sorted_by_inheritance())
34            f.write(generated_code)
35            print("Code generated in the location: " + file_path)

Remember that in BESSER, B-UML models have a set of methods to facilitate their traversal. For example, for structural models, the class.attributes method gets the list of attributes of the class, class.all_attributes gets the list of attributes including the inherited ones (if the class inherits from another one), model.classes_sorted_by_inheritance() gets the classes of the model sorted according to the inheritance hierarchy, and so on. You can consult the API documentation for more information.