Examples
Maven build tool allows a lot of flexibility to end users to model their complex use cases.
Some specific use cases are described in the following sections. Resources for these examples can be found at this link .
Simple Substitution
This example uses a single value file for substitution into the JSON template file.
-
Use case: This is a simple use case of direct value substitution into the template file.
-
Template File:
{ "app_name": "{{name}}", "app_version": {{version}}, "env_name": "{{env}}", "db_connect": "{{db}}" }
- Value File:
{ "name": "SimpleApp", "version": 1.0, "env": "uat", "db_host": "1.2.3.4", "db_port": 9876, "db": "jdbc:mysql://{{db_host}}:{{db_port}}/" }
- Output File:
{ "app_name": "SimpleApp", "app_version": 1.0, "env_name": "uat", "db_connect": "jdbc:mysql://1.2.3.4:9876/" }
Complex Substitutions and Statements
This example uses multiple value files for direct and indirect substitutions into the YAML template file along with complex conditional statements.
See this link for more examples of Jinja Control Structures.
-
Use case: This is a rather complex use case, through which some of the capabilities of Jinja templating engine and the plugin are shown as mentioned below,
-
Multilevel substitution
-
Value overriding
-
Multiple contexts
-
Control Structure support
-
-
Template File:
server: ports: {{serverPorts}} context-path: {{contextPath}} config: app: name: {{name}} task: scheduling: pool: size: {{poolSize}} datasource: driverClassName: {{dbDriverClass}} url: {{connectString}} username: {{dbUserName}} password: {{dbPassword}} options: {{sourceOptions}}
-
Value Files:
- Common Properties for some sample system
{ "name": "ComplexApp", "contextPath": "/v1", "poolSize": 7, "dbDriverClass": "com.mysql.jdbc.Driver", "mysql": "mysql", "db2": "db2", "dbType": "{% if 'mysql' in dbDriverClass %}mysql{% else %}db2{% endif %}", "connectString": "jdbc:{{dbType}}://{{db_host}}:{{db_port}}/", "sourceOptions": { "prepStmtCacheSize": 250, "cachePrepStmts": true } }
- Common Properties for some sample system
{ "serverPorts": [ 4000, 4001, 4002 ], "db_host": "1.2.3.4", "db_port": "3306", "dbUserName": "db_user_uat", "dbPassword": "Password_uat_1234" }
- Common Properties for some sample system
-
Output File:
server: ports: [4000,4001,4002] context-path: /v1 config: app: name: ComplexApp task: scheduling: pool: size: 7 datasource: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://1.2.3.4:3306/ username: db_user_uat password: Password_uat_1234 options: {"prepStmtCacheSize":250,"cachePrepStmts":true}
Rendering Profiles
This example is more about the flexibility of how and when the output files are rendered.
- Use case: For this example we will assume a configuration driven application
TestApp
that runs in two environmentsuat
andprod
.
The values present in the configurations for both these environments would be different and specific to the environment they are running in. Consider the following scenarios that may rise,
- Rendering everything in one pass: When you want all outputs to be rendered at the same time. Like, rendering the configuration for all environments (
uat
andprod
) at the same time.- Rendering selectively by triggers: When you want to conditionally render selected outputs. Like, rendering when certain condition(s) are met.
For such scenarios, this plugin can be coupled with maven profiles to selectively render resources.
- Template File:
/path/to/template/a_template.j2
{ "app_name": "{{name}}", "app_version": {{version}}, "env_name": "{{env}}", "db_connect": "{{db}}" }
- Value Files:
/path/to/values/uat_values.json
{ "name": "SimpleApp", "version": 1.0, "env": "uat", "db_host": "localhost", "db_port": 1234, "db": "jdbc:mysql://{{db_host}}:{{db_port}}/" }
/path/to/values/prod_values.json
{ "name": "SimpleApp", "version": 1.0, "env": "prod", "db_host": "1.2.3.4", "db_port": 9876, "db": "jdbc:mysql://{{db_host}}:{{db_port}}/" }
- Plugin configuration: The project’s
pom.xml
can look something like below, with two different maven profilesuat_build
andprod_build
. They both use the same template, but the value file path and output file paths can be switched as per the activated profile.
<project> ... <profiles> ... <profile> <!-- Profile for UAT Environment --> <id>uat_build</id> <activation> <property> <name>uat_build</name> </property> </activation> ... <build> <plugins> ... <plugin> <groupId>com.github.chitralverma</groupId> <artifactId>jinja-maven-plugin</artifactId> <version>${latest.plugin.version}</version> <configuration> <skip>false</skip> <failOnMissingValues>true</failOnMissingValues> <overwriteOutput>false</overwriteOutput> <resourceSet> <resource> <templateFilePath>/path/to/template/a_template.j2</templateFilePath> <valueFiles> <param>/path/to/values/uat_values.json</param> </valueFiles> <outputFilePath>src/main/resources/jinja/results/uat_config.json</outputFilePath> </resource> </resourceSet> </configuration> </plugin> ... </plugins> </build> </profile> <profile> <!-- Profile for PROD Environment --> <id>prod_build</id> <activation> <property> <name>prod_build</name> </property> </activation> ... <build> <plugins> ... <plugin> <groupId>com.github.chitralverma</groupId> <artifactId>jinja-maven-plugin</artifactId> <version>${latest.plugin.version}</version> <configuration> <skip>false</skip> <failOnMissingValues>true</failOnMissingValues> <overwriteOutput>false</overwriteOutput> <resourceSet> <resource> <templateFilePath>/path/to/template/a_template.j2</templateFilePath> <valueFiles> <param>/path/to/values/prod_values.json</param> </valueFiles> <outputFilePath>src/main/resources/jinja/results/prod_config.json</outputFilePath> </resource> </resourceSet> </configuration> </plugin> ... </plugins> </build> </profile> ... </profiles> ... </project>
-
Execution:
- Going back to scenario (i) - Rendering everything in one pass - this can be achieved by removing the maven profiles altogether and create two separate resource in the plugin directly, like below,
<project> ... <build> ... <plugins> ... <plugin> <groupId>com.github.chitralverma</groupId> <artifactId>jinja-maven-plugin</artifactId> <version>${latest.plugin.version}</version> <configuration> <skip>false</skip> <failOnMissingValues>true</failOnMissingValues> <overwriteOutput>false</overwriteOutput> <resourceSet> <!-- Profile for UAT Environment --> <resource> <templateFilePath>/path/to/template/a_template.j2</templateFilePath> <valueFiles> <param>/path/to/values/uat_values.json</param> </valueFiles> <outputFilePath>src/main/resources/jinja/results/uat_config.json</outputFilePath> </resource> <!-- Profile for PROD Environment --> <resource> <templateFilePath>/path/to/template/a_template.j2</templateFilePath> <valueFiles> <param>/path/to/values/prod_values.json</param> </valueFiles> <outputFilePath>src/main/resources/jinja/results/prod_config.json</outputFilePath> </resource> </resourceSet> </configuration> </plugin> ... </plugins> ... </build> ... </project>
- As for the scenario (ii) - Rendering selectively by triggers - this can be achieved by running either of the below mentioned commands as per the requirement. See Plugin configuration section above.
# For UAT environment mvn clean package -Duat_build # For PROD environment mvn clean package -Dprod_build
-
Output Files:
src/main/resources/jinja/results/uat_config.json
{ "app_name": "SimpleApp", "app_version": 1.0, "env_name": "uat", "db_connect": "jdbc:mysql://localhost:1234/" }
src/main/resources/jinja/results/prod_config.json
{ "app_name": "SimpleApp", "app_version": 1.0, "env_name": "prod", "db_connect": "jdbc:mysql://1.2.3.4:9876/" }
Using Maven Properties
This example demonstrates how to use maven in resources of provided jinja template with or without value files.
-
Use case: This is a simple use case of direct value substitution of maven properties into the template file.
-
Template File:
Release Notes === - Project Name: {{ maven_properties.name }} - Project GroupId: {{ maven_properties.groupId }} - Project ArtifactId: {{ maven_properties.artifactId }} - Project Version: {{ maven_properties.version }} - Project Developers: {{ maven_properties['developers'][0].name }} - Custom Project Property: {{ maven_properties.properties['my.custom.property'] }}
- Plugin configuration: The project’s
pom.xml
can look something like below, with an additional configurationincludeMavenProperties
. To interpolate values from maven properties prefix them withmaven_properties.
. For example, to includegroupId
of the project define{{ maven_properties.groupId }}
in your j2 templates.
Note: The value for this configuration is set to true
by default. This can be toggled to exclude maven properties to be added to context.
<project> ... <build> ... <plugins> ... <plugin> <groupId>com.github.chitralverma</groupId> <artifactId>jinja-maven-plugin</artifactId> <version>${latest.plugin.version}</version> <configuration> <includeMavenProperties>true</includeMavenProperties> <resourceSet> <!-- Profile for UAT Environment --> <resource> <templateFilePath>/path/to/template/release_notes_md_template.j2</templateFilePath> <outputFilePath>src/main/resources/jinja/results/release_notes.md</outputFilePath> </resource> </resourceSet> </configuration> </plugin> ... </plugins> ... </build> ... </project>
- Output File:
Release Notes === - Project Name: jinja-maven-plugin-examples - Project GroupId: com.github.chitralverma - Project ArtifactId: jinja-maven-plugin-examples - Project Version: 1.0-SNAPSHOT - Project Developers: Jon Doe - Custom Project Property: test_value