Summary
Currently, the Eclipse JDT formatter profile is bundled as a classpath resource (eclipse-java-format.xml) and cannot be customized by users. This ticket proposes adding a compiler argument -Asimplebuilder.formatterProfile that allows users to specify an external Eclipse formatter profile XML file, enabling project-specific code formatting conventions for generated builder source files.
Motivation
- Project-specific formatting: Teams have their own formatting conventions (indentation size, brace placement, line wrapping, etc.). Currently, generated builders use the bundled profile, which may not match the consuming project's style.
- Consistency with hand-written code: Generated builders should visually match the surrounding hand-written code in the project.
- No workaround today: The only way to change formatting is to fork the processor and replace the bundled
eclipse-java-format.xml, which is not maintainable.
Proposed API
Compiler argument
-Asimplebuilder.formatterProfile=<path>
<path> can be:
- An absolute or relative file system path (e.g.,
config/eclipse-formatter.xml, /home/user/profiles/custom.xml)
- A classpath resource path (e.g.,
eclipse-java-format.xml) — this is the current default behavior
- Default:
eclipse-java-format.xml (bundled resource, current behavior)
- Empty/unset: Falls back to the bundled default
Resolution logic
- If
-Asimplebuilder.formatterProfile is set:
- Try to resolve as a file system path first (relative to the current working directory or absolute)
- If the file does not exist, try to resolve as a classpath resource
- If neither works, log a warning and fall back to the bundled default
- If not set, use the bundled
eclipse-java-format.xml (current behavior)
Example usage
# Maven
mvn compile -Dsimplebuilder.formatterProfile=src/main/config/eclipse-formatter.xml
# Gradle
compileJava {
options.compilerArgs += ['-Asimplebuilder.formatterProfile=config/formatter.xml']
}
Implementation outline
1. New CompilerArgumentsEnum constant
Add to CompilerArgumentsEnum:
/** Option for external Eclipse formatter profile XML file path. */
FORMATTER_PROFILE("formatterProfile"),
2. Read the argument in ProcessingContext
In ProcessingContext constructor (or a new method on CompilerArgumentsReader):
String formatterProfilePath = argReader.readValue(CompilerArgumentsEnum.FORMATTER_PROFILE);
Pass this path through to RoasterSourceFormatter (or RoasterCodeGenerator) alongside the FormattingMode.
3. Update RoasterSourceFormatter to resolve the profile
Currently RoasterSourceFormatter loads the profile from the classpath via getResourceAsStream(). Extend loadFormatterProperties() to:
- If an external path is provided, try to load it as a file first (
new FileInputStream(path))
- If the file doesn't exist, try the classpath with the given path
- If both fail, fall back to the bundled default (
DEFAULT_FORMATTER_PROFILE_RESOURCE)
- Log appropriate warnings at each fallback step
The formatterProfileResource field (already injectable for testing) would carry the resolved path.
4. Thread the parameter through the pipeline
ProcessingContext → stores formatterProfilePath (like formattingMode)
RoasterCodeGenerator → passes it to RoasterSourceFormatter constructor
RoasterSourceFormatter → uses it in loadFormatterProperties()
5. Documentation
Update CONFIGURATION.md with a new section:
### Formatter Profile
| Option | Compiler argument | Default | Description |
|--------|-------------------|---------|-------------|
| `formatterProfile` | `-Asimplebuilder.formatterProfile` | `eclipse-java-format.xml` (bundled) | Path to an external Eclipse formatter profile XML file. Can be a file system path or classpath resource. |
6. Tests
- File system path: Create a temp file with a custom profile, pass its path, verify generated code uses the custom formatting (e.g., different indentation size)
- Classpath resource: Pass a custom classpath resource name, verify it's loaded
- Fallback to bundled default: Pass a non-existent path, verify warning is logged and bundled profile is used
- No argument: Verify current behavior is unchanged
- Per-annotation override (future): Consider adding
formatterProfile to @SimpleBuilder.Options for per-builder customization (similar to formattingMode)
Scope
- In scope: Compiler argument
-Asimplebuilder.formatterProfile for global configuration
- Future consideration: Per-annotation
@SimpleBuilder.Options(formatterProfile = "...") override (same priority resolution as formattingMode)
- Out of scope: Support for multiple formatter profiles per generated class, non-Eclipse formatter formats
Affected files
| File |
Change |
CompilerArgumentsEnum.java |
Add FORMATTER_PROFILE constant |
CompilerArgumentsReader.java |
Add readFormatterProfile() method |
ProcessingContext.java |
Read and store formatterProfilePath |
RoasterCodeGenerator.java |
Pass formatterProfilePath to RoasterSourceFormatter |
RoasterSourceFormatter.java |
Extend loadFormatterProperties() to resolve file system paths |
CONFIGURATION.md |
Document the new option |
RoasterSourceFormatterTest.java |
Add tests for external profile loading |
Summary
Currently, the Eclipse JDT formatter profile is bundled as a classpath resource (
eclipse-java-format.xml) and cannot be customized by users. This ticket proposes adding a compiler argument-Asimplebuilder.formatterProfilethat allows users to specify an external Eclipse formatter profile XML file, enabling project-specific code formatting conventions for generated builder source files.Motivation
eclipse-java-format.xml, which is not maintainable.Proposed API
Compiler argument
<path>can be:config/eclipse-formatter.xml,/home/user/profiles/custom.xml)eclipse-java-format.xml) — this is the current default behavioreclipse-java-format.xml(bundled resource, current behavior)Resolution logic
-Asimplebuilder.formatterProfileis set:eclipse-java-format.xml(current behavior)Example usage
Implementation outline
1. New
CompilerArgumentsEnumconstantAdd to
CompilerArgumentsEnum:2. Read the argument in
ProcessingContextIn
ProcessingContextconstructor (or a new method onCompilerArgumentsReader):Pass this path through to
RoasterSourceFormatter(orRoasterCodeGenerator) alongside theFormattingMode.3. Update
RoasterSourceFormatterto resolve the profileCurrently
RoasterSourceFormatterloads the profile from the classpath viagetResourceAsStream(). ExtendloadFormatterProperties()to:new FileInputStream(path))DEFAULT_FORMATTER_PROFILE_RESOURCE)The
formatterProfileResourcefield (already injectable for testing) would carry the resolved path.4. Thread the parameter through the pipeline
ProcessingContext→ storesformatterProfilePath(likeformattingMode)RoasterCodeGenerator→ passes it toRoasterSourceFormatterconstructorRoasterSourceFormatter→ uses it inloadFormatterProperties()5. Documentation
Update
CONFIGURATION.mdwith a new section:6. Tests
formatterProfileto@SimpleBuilder.Optionsfor per-builder customization (similar toformattingMode)Scope
-Asimplebuilder.formatterProfilefor global configuration@SimpleBuilder.Options(formatterProfile = "...")override (same priority resolution asformattingMode)Affected files
CompilerArgumentsEnum.javaFORMATTER_PROFILEconstantCompilerArgumentsReader.javareadFormatterProfile()methodProcessingContext.javaformatterProfilePathRoasterCodeGenerator.javaformatterProfilePathtoRoasterSourceFormatterRoasterSourceFormatter.javaloadFormatterProperties()to resolve file system pathsCONFIGURATION.mdRoasterSourceFormatterTest.java