5.7.1.2. Custom Functions

Besides the built-in functions in the expression language of the CodeComposer you can define your own custom functions for use in code instructions and snippets. This can be achieved by adding function libraries with custom functions to the code instructions XML.

5.7.1.2.1. Adding a function library with custom functions to the code instructions

Function libraries with custom functions can be added to the code instruction XML file for each external library.

Multiple function libraries can be added per external library (see lines 23 and 24 in the example code instructions XML file below).

Example of function libraries in the codeinstruction XML file

Listing 5.60 codecomposer-reference-input/src/codeinstruction/codeinstruction.xml
 1<?xml version="1.0" encoding="UTF-8"?>
 2<code_instruction xmlns="https://metafactory.io/xsd/v1/codeinstruction"
 3                  xmlns:java="https://metafactory.io/xsd/v1/java-codeinstruction"
 4                  xmlns:ts="https://metafactory.io/xsd/v1/typescript-codeinstruction"
 5                  xmlns:xi="http://www.w3.org/2001/XInclude"
 6                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 7                  xsi:schemaLocation="https://metafactory.io/xsd/v1/codeinstruction
 8                                      https://metafactory.io/xsd/v1/codeinstruction.xsd
 9                                      https://metafactory.io/xsd/v1/java-codeinstruction
10                                      https://metafactory.io/xsd/v1/java-codeinstruction.xsd
11                                      https://metafactory.io/xsd/v1/typescript-codeinstruction
12                                      https://metafactory.io/xsd/v1/typescript-codeinstruction.xsd">
13  <properties>
14        <java.main.directory>src/main/java</java.main.directory>
15        <java.test.directory>src/test/java</java.test.directory>
16        <java.package.base>io.metafactory.codecomposer_reference</java.package.base>
17  </properties>
18  <external_libraries>
19        <external_library name="libProject">
20          <path>./src</path>
21          <codeinstructions_folder>codeinstruction</codeinstructions_folder>
22          <snippets_folder>snippet</snippets_folder>
23          <function_library>codeinstruction/my-project-ci-functions.xml</function_library>
24          <function_library>codeinstruction/example-custom-functions.xml</function_library>
25        </external_library>
26  </external_libraries>

Best practice

BestPractice L You should group functions that belong together in a separate function library file.

5.7.1.2.2. Defining a custom function

A custom function can be defined by adding a <function> element to the <functions> element in the XML file of the function library. The custom function must be given a unique name and contain a <definition> element. In the <definition> element the result of the function can be defined.

Using function arguments

Custom functions can have zero to nine arguments. Arguments are named arg1, arg2, arg3, …, arg9.

5.7.1.2.3. Example of custom functions

In the following custom functions XML file an example is shown of 4 custom functions:
  • createSimpleDtoClassName

  • createSimpleEntityClassName

  • createSimpleServiceClassName and

  • createSpecialServiceClassName,

each having the name of the model object as argument:

Listing 5.61 codecomposer-reference-input/src/codeinstruction/example-custom-functions.xml
 1<?xml version="1.0" encoding="UTF-8"?>
 2<functions xmlns="https://metafactory.io/xsd/v1/codeinstruction"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="https://metafactory.io/xsd/v1/codeinstruction https://metafactory.io/xsd/v1/codeinstruction.xsd">
 5
 6        <function name="createSimpleDtoClassName">
 7                <!--Function must be called with 1 argument:
 8                        1) name of the model object
 9                -->
10                <definition>${arg1}SimpleDto</definition>
11        </function>
12
13        <function name="createSimpleEntityClassName">
14                <!--Function must be called with 1 argument:
15                        1) name of the model object
16                -->
17                <definition>${arg1}SimpleEntity</definition>
18        </function>
19
20        <function name="createSimpleServiceClassName">
21                <!--Function must be called with 1 argument:
22                        1) name of the model object
23                -->
24                <definition>${arg1}SimpleService</definition>
25        </function>
26
27        <function name="createSpecialServiceClassName">
28                <!--Function must be called with 1 argument:
29                        1) name of the model object
30                -->
31                <definition>${fmsnippet.examples.exampleSnippetToCreateSpecialServiceClassName}</definition>
32        </function>
33
34</functions>

Best practice

BestPractice L You should add a comment for each argument describing what the argument is.

Best practice

BestPractice L You should not use modelPackage, modelObject, modelAttribute or modelReference in custom functions: Only use arg1 t/m arg9.

The first three functions found in the example define the result of the function directly in the definition, while the fourth function uses a snippet to define the result of the function:

Listing 5.62 codecomposer-reference-input/src/snippet/examples/exampleSnippetToCreateSpecialServiceClassName.ftl
1<#--stop if arg1 is null-->
2<#if !(arg1)??>  <#stop "arg1 (model object name) not found in context" ></#if>
3
4<#--best practice: assign argument to a variable with a name that represents its contents -->
5<#assign modelObjectName = arg1/>
6
7${modelObjectName}SpecialService

Note

The example snippet shown is a rather simple one, but a snippet has the ability to implement more complex custom functions as well.

Best practice

BestPractice L You should assign any argument of the snippet that implements a custom function to a variable with a name that represents the content of the variable at the start of the snippet and use the variable instead of the numbered argument in the rest of the snippet.

5.7.1.2.4. Usage of a custom function

Custom functions can be used in code instructions and in snippets.

5.7.1.2.5. Usage of a custom function in a code instruction

A custom function can be used in a code instruction. The following code instruction shows an example of the use of a custom function named createSimpleEntityClassName which has the object name as argument.

Listing 5.63 codecomposer-reference-input/src/codeinstruction/examples/example-code-instruction-simple-entity-foreach-object.xml
 1<?xml version="1.0" encoding="UTF-8"?>
 2<java_package xmlns="https://metafactory.io/xsd/v1/java-codeinstruction"
 3                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4                xsi:schemaLocation="https://metafactory.io/xsd/v1/java-codeinstruction https://metafactory.io/xsd/v1/java-codeinstruction.xsd"
 5                name="${pattern.property.java.package.base}.entities.simple"
 6                path="${pattern.property.java.main.directory}"
 7                package="domain_model">
 8  <class  name="${createSimpleEntityClassName(${object.name})}"
 9          foreach="object">
10  </class>
11</java_package>

Input

Given the code instruction XML in codecomposer-reference-input/src/codeinstruction/codeinstruction.xml, the code instruction in codecomposer-reference-input/src/codeinstruction/examples/example-code-instruction-simple-entity-foreach-object.xml, the custom function library in codecomposer-reference-input/src/codeinstruction/example-custom-functions.xml and the model in codecomposer-reference-input/src/model/model.xml shown below, CodeComposer will produce the files shown in the output in the following section.

Listing 5.64 codecomposer-reference-input/src/model/model.xml
 1<?xml version="1.0" encoding="UTF-8"?>
 2<model xmlns="https://metafactory.io/xsd/v1/model"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xsi:schemaLocation="https://metafactory.io/xsd/v1/model https://metafactory.io/xsd/v1/model.xsd">
 5  <package name="domain_model">
 6        <object name="ExampleObject1">
 7        </object>
 8        <object name="ExampleObject2">
 9        </object>
10        <object name="ExampleObject3">
11        </object>
12        <object name="ExampleObject4">
13        </object>
14  </package>
15</model>

Output

Listing 5.65 codecomposer-reference-output/src/main/java/io/metafactory/codecomposer_reference/entities/simple/ExampleObject1SimpleEntity.java
1package io.metafactory.codecomposer_reference.entities.simple;
2
3public class ExampleObject1SimpleEntity {
4
5}
Listing 5.66 codecomposer-reference-output/src/main/java/io/metafactory/codecomposer_reference/entities/simple/ExampleObject2SimpleEntity.java
1package io.metafactory.codecomposer_reference.entities.simple;
2
3public class ExampleObject2SimpleEntity {
4
5}
Listing 5.67 codecomposer-reference-output/src/main/java/io/metafactory/codecomposer_reference/entities/simple/ExampleObject3SimpleEntity.java
1package io.metafactory.codecomposer_reference.entities.simple;
2
3public class ExampleObject3SimpleEntity {
4
5}
Listing 5.68 codecomposer-reference-output/src/main/java/io/metafactory/codecomposer_reference/entities/simple/ExampleObject4SimpleEntity.java
1package io.metafactory.codecomposer_reference.entities.simple;
2
3public class ExampleObject4SimpleEntity {
4
5}

5.7.1.2.6. Usage of a custom function in a snippet

A custom function can be used in a snippet by importing the function library in which the custom function is defined (see line 1 of the example snippet below) and assigning it to a variable. A call of the custom function starts with the variable chosen in the import statement followed by a dot and the name of the function (see line 5). After assigning the return value of the function to a variable, the variable can be used in other statements in the snippet to produce the desired output of the snippet.

Listing 5.69 codecomposer-reference-input/src/snippet/examples/exampleSnippetUsingCustomFunction.ftl
1<#import "/library/custom_functions_libproject.ftl" as cf_libproject>
2
3<#if !(modelObject)??>  <#stop "modelObject not found in context" ></#if>
4
5<#assign simpleEntityClassName= cf_libproject.createSimpleEntityClassName(modelObject.name)>
6
7<!-- use of the value returned by cf_libproject.createSimpleEntityClassName assigned to variable simpleEntityClassName -->

Note

Multiple function libraries within a external library are combined by the CodeComposer in one single .ftl file named after the external library and placed in the /library directory.

In the example the two function libraries in the external library libProject are combined by the CodeComposer into /library/custom_functions_libproject.ftl.