I was able to solve this issue after spending long hours reading the offcial docs, javadocs, and reading the source code for the spring-starter package. Here is what I understood so far.
The library can render templates outside of your java project that's why it doesn't treat your resources directory as a first class citizen. That's why you should consider your resources directory as a regular directory in your filesystem that you have to point to as any other directory.
Keep in mind that the TemplateEngine uses a CodeResolver to lookup for templates. In spring-starter it uses DirectoryCodeResolver by default which resolve templates by a given root directory on the filesystem. There is a second implementation (ResourceCodeResolver) that can be used to resolve templates in the resources directory.
Considering spring starter we can say that the library offers 3 modes:
Default
The default configuration based on the JteProperties sets the
gg.jte.template-suffix=.jte
gg.jte.use-precompiled-templates=false
gg.jte.template-location=src/main/jte
gg.jte.development-mode=false
This will lookup for templates under your project's source code under /src/main/jte/*.jte. When the TemplateEngine#render() is called. The template engine will compile the request template to a .class and caches the rendered class.
Cons (In production):
- Requires JDK to be present in the deployment machine to compile templates.
- The first render takes longer and consumes more resources based on the size and complexity of your templates.
- (This is more of an assumption) I'm not sure what is the cache invalidation policy but incase cached templates are invalidated there is a potential of multiple requests requesting the same template which resutls in mutliple compilation for the same template.
Development
You can enable the development mode by setting the:
gg.jte.development-mode=true
gg.jte.use-precompiled-templates=false
In this mode JTE will add a file watcher for each template called by the TemplateEngine#render(). The template is compiled the first time its rendered and the .class is cached until the template's hash is changed. This is usefull during development because it doesn't require restarting your appliaiton each time you make a change but it's not suitable for produciton.
Cons (In production):
- Same cons as for the Default mode
- Each template rendering request adds a file watcher to the template which can cause resource leaks and file locks that may cause unexpected issues.
Production
Production mode is enabled by setting:
gg.jte.development-mode=false
gg.jte.use-precompiled-templates=true
In this mode the TemplateEngine expects precompiled classes to be present on the classpath as commented in the JteAutoConfiguration#jteTemplateEngine. By calling the TemplateEngine#createPrecompiled() you are creating a new instance of a TemplateEngine that resolve template names by equivalent classes on the class path.
For example when calling TemplateEngine#render('/user/new-user.jte'). The template engine will try to load the equivalent precompiled class in the following package gg.jte.generated.precompiled.user.JtenewuserGenerated.class. If the ClassLoader fails to find the class in the class path an exception is occured.
Thus you should precompile your templates using the maven or gradle plugins.
Solution:
Going back to your problem. You should remove your TemplateConfiguration. The same can be achieved by just updating your
application-prod.properties
gg.jte.usePrecompiledTemplates=true
gg.jte.developmentMode=false
1. MAVEN
pom.xml
<plugin>
<groupId>gg.jte</groupId>
<artifactId>jte-maven-plugin</artifactId>
<version>${jte-gg.version}</version>
<configuration>
<sourceDirectory>${project.basedir}/src/main/resources/templates</sourceDirectory>
<targetDirectory>${project.build.directory}/jte-classes</targetDirectory>
<contentType>Html</contentType>
</configuration>
<executions>
<execution>
<id>precompile</id>
<phase>process-classes</phase>
<goals>
<goal>precompile</goal>
</goals>
</execution>
</executions>
</plugin>
After updating your pom.xml you need to run the following maven goals:
# required if you are packaging your app in your dev maching. This clean dev generated classes.
$mvn clean
# templates precompilation requires classes to be already compiled
$mvn compile
$mvn jte:precompile
$mvn package
2. GRADLE
jte {
precompile()
sourceDirectory.set(Path("src/main/resources/templates"))
}
Then execute
./gradlew clean
./gradlew precompileJte
./gradlew build