Skip to content

CAMEL-21208: Replace manual string-based code generation with FreeMarker templates#22200

Open
gnodet wants to merge 2 commits intomainfrom
CAMEL-21208-freemarker-templates
Open

CAMEL-21208: Replace manual string-based code generation with FreeMarker templates#22200
gnodet wants to merge 2 commits intomainfrom
CAMEL-21208-freemarker-templates

Conversation

@gnodet
Copy link
Contributor

@gnodet gnodet commented Mar 23, 2026

JIRA: CAMEL-21208

Summary

  • Add FreeMarker 2.3.34 as a template engine dependency to camel-jbang-core
  • Create TemplateHelper utility using FreeMarker's square bracket syntax ([=var], [#if]...[/#if]) to avoid conflicts with ${...} (Maven/Camel expressions) and <...> (XML tags) in generated content
  • Convert all 23 .tmpl template files to .ftl FreeMarker templates with proper directives for conditionals and loops
  • Refactor ExportCamelMain, ExportSpringBoot, ExportQuarkus, Export, Run, and Init commands to use TemplateHelper instead of manual StringBuilder/replaceAll/replaceFirst code generation
  • Extract shared helpers (buildRepositoryList, buildDependencyList, formatBuildProperties, mavenGavComparator) into ExportBaseCommand to eliminate duplication
  • Maintain backward compatibility for catalog-provided templates in ExportSpringBoot (legacy regex processing path)
  • Remove 4 unreferenced templates (main-docker-*.tmpl, main-jkube-pom.tmpl)
  • Keep deprecated bind templates (.tmpl) used by TemplateProvider

Motivation

The existing code generation approach used raw string manipulation (replaceFirst, replaceAll, StringBuilder.append) to produce POM files, Dockerfiles, README files, and source code. This was:

  • Error-prone (regex escaping issues, ordering dependencies between replacements)
  • Hard to read and maintain (XML structure buried in Java string concatenation)
  • Difficult to extend (adding new conditional sections required careful regex surgery)

FreeMarker templates make the generated output structure visible and maintainable, with proper control flow ([#if], [#list]) replacing ad-hoc string manipulation.

Test plan

  • All 311 camel-jbang-core tests pass
  • All 128 camel-jbang-plugin-kubernetes tests pass
  • CI build passes

…ker templates in camel-jbang

- Add FreeMarker 2.3.34 dependency to camel-jbang-core
- Create TemplateHelper utility using square bracket syntax ([=var], [#if]...[/#if])
  to avoid conflicts with ${...} (Maven) and <...> (XML) in generated content
- Convert all 23 .tmpl template files to .ftl FreeMarker templates
- Refactor Export*, Run, and Init commands to use TemplateHelper instead of
  manual StringBuilder/replaceAll/replaceFirst code generation
- Extract shared helpers (buildRepositoryList, buildDependencyList, formatBuildProperties,
  mavenGavComparator) into ExportBaseCommand
- Maintain backward compatibility for catalog-provided templates in ExportSpringBoot
- Remove 4 unreferenced templates (main-docker-*.tmpl, main-jkube-pom.tmpl)
- Keep deprecated bind templates (.tmpl) used by TemplateProvider

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using build-all, build-dependents, skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@github-actions github-actions bot added the dsl label Mar 23, 2026
- Add backward compat check for old .tmpl catalog template name in ExportSpringBoot
- Remove dead model variables (CamelVersion, QuarkusManagementPort)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

🧪 CI tested the following changed modules:

  • dsl/camel-jbang/camel-jbang-core
  • dsl/camel-jbang/camel-jbang-plugin-kubernetes
All tested modules (26 modules)
  • Camel :: Coverage
  • Camel :: Coverage [pom]
  • Camel :: JBang :: Core
  • Camel :: JBang :: Core [jar]
  • Camel :: JBang :: Integration tests
  • Camel :: JBang :: Integration tests [jar]
  • Camel :: JBang :: MCP
  • Camel :: JBang :: MCP [jar]
  • Camel :: JBang :: Main
  • Camel :: JBang :: Main [jar]
  • Camel :: JBang :: Plugin :: Edit
  • Camel :: JBang :: Plugin :: Edit [jar]
  • Camel :: JBang :: Plugin :: Generate
  • Camel :: JBang :: Plugin :: Generate [jar]
  • Camel :: JBang :: Plugin :: Kubernetes
  • Camel :: JBang :: Plugin :: Kubernetes [jar]
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: Route Parser [jar]
  • Camel :: JBang :: Plugin :: Testing
  • Camel :: JBang :: Plugin :: Testing [jar]
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: JBang :: Plugin :: Validate [jar]
  • Camel :: Launcher
  • Camel :: Launcher [jar]
  • Camel :: Launcher :: Container
  • Camel :: Launcher :: Container [pom]

String ftlName = "Dockerfile" + javaVersion + ".ftl";
String context;
try {
Map<String, Object> model = new HashMap<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be extracted to avoid code duplication?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code on behalf of Guillaume Nodet

Good catch. Looking at this more carefully — the Dockerfile template rendering now uses FreeMarker through the base class, and the Quarkus override handles the fast-jar vs uber-jar distinction which genuinely needs different logic. So the apparent duplication in Export.java line 311 is the shared base implementation. Will add a clarifying comment.

@apupier
Copy link
Contributor

apupier commented Mar 25, 2026

Hey AI agent, please rebase and resolve the conflict

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants