Skip to content

perf: cache compiled XSLT Templates per XSL file in MessageCodeGenerator#1231

Draft
Copilot wants to merge 1 commit into
masterfrom
copilot/improve-messagecodegenerator-performance
Draft

perf: cache compiled XSLT Templates per XSL file in MessageCodeGenerator#1231
Copilot wants to merge 1 commit into
masterfrom
copilot/improve-messagecodegenerator-performance

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 19, 2026

Cache compiled XSLT Templates per XSL file in MessageCodeGenerator to avoid recompiling the same stylesheet on every generated file.

Problem

MessageCodeGenerator.createTransformer() was creating a new TransformerFactory instance and calling newTransformer(styleSource) on every invocation — once per output file. newTransformer(source) compiles the XSL stylesheet from scratch each time. For large FIX versions (e.g. FIX Latest) with hundreds of message/component/field files, the same handful of XSL stylesheets were being compiled hundreds of times unnecessarily.

Changes

quickfixj-codegenerator/src/main/java/org/quickfixj/codegenerator/MessageCodeGenerator.java

  • Shared TransformerFactory — moved from a local variable inside createTransformer() to a final instance field so Saxon is initialised once per MessageCodeGenerator instance.
  • Templates cache — added a ConcurrentHashMap<String, Templates> instance field. A javax.xml.transform.Templates object is a thread-safe, pre-compiled representation of an XSL stylesheet.
  • Cache key — computed per stylesheet:
    • Filesystem XSL: the absolute path of the file.
    • Classpath XSL: "classpath:" + xsltFile.
  • The first call for a given key compiles the stylesheet via transformerFactory.newTemplates(styleSource) and stores the result. Subsequent calls reuse the cached Templates and call the cheap templates.newTransformer() to get a fresh (non-thread-safe) Transformer instance — as required by the JAXP spec.
  • TransformerConfigurationException is still propagated correctly via the existing CodeGenerationException wrapper.

What is styleSource?

styleSource is a javax.xml.transform.stream.StreamSource — it wraps the raw byte stream of the XSL stylesheet file, loaded either from the filesystem (task.getTransformDirectory()/<file>.xsl) or from the classpath. It is passed once to transformerFactory.newTemplates(styleSource) to compile the stylesheet into a reusable Templates object. After the first compilation for a given stylesheet, styleSource is no longer needed; all subsequent calls reuse the cached Templates.

Before / After

// Before: new factory + full stylesheet compilation on every file generated
TransformerFactory transformerFactory = new net.sf.saxon.TransformerFactoryImpl();
return transformerFactory.newTransformer(styleSource);  // compiles XSL every time

// After: compile once, reuse pre-compiled Templates
Templates templates = templatesCache.computeIfAbsent(cacheKey,
    k -> transformerFactory.newTemplates(styleSource));  // compiled only on first call
return templates.newTransformer();                       // cheap — no recompilation

@chrjohn
Copy link
Copy Markdown
Member

chrjohn commented May 19, 2026

@copilot the pr description is not correct. Please add the changes that were done in this PR.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 19, 2026

@copilot the pr description is not correct. Please add the changes that were done in this PR.

Updated the PR description. It now explains the actual change: caching compiled XSLT Templates per XSL file in MessageCodeGenerator so that each stylesheet is compiled only once instead of once per generated file. It also explains what styleSource is — a StreamSource wrapping the raw XSL file bytes, passed to newTemplates() for the one-time compilation.

Copilot AI changed the title No changes made — analysis only perf: cache compiled XSLT Templates per XSL file in MessageCodeGenerator May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants