Skip to content

Comments

feat(job): introduce strategy pattern for index export format support#3036

Merged
marevol merged 1 commit intomasterfrom
feat/index-export-formatter-strategy
Feb 7, 2026
Merged

feat(job): introduce strategy pattern for index export format support#3036
marevol merged 1 commit intomasterfrom
feat/index-export-formatter-strategy

Conversation

@marevol
Copy link
Contributor

@marevol marevol commented Feb 7, 2026

Summary

  • Refactors IndexExportJob to use a strategy pattern for export format handling, making it easy to add new export formats without modifying the core export logic
  • Introduces IndexExportFormatter interface with HtmlIndexExportFormatter (existing behavior) and JsonIndexExportFormatter (new format)
  • Adds index.export.format configuration property to select the default export format

Changes Made

New Files

  • IndexExportFormatter.java - Strategy interface defining the contract for export formatters (getFileExtension(), getIndexFileName(), format())
  • HtmlIndexExportFormatter.java - HTML formatter that produces well-structured HTML documents with metadata as <meta> tags and proper HTML escaping
  • JsonIndexExportFormatter.java - JSON formatter that outputs documents as JSON objects with proper escaping and support for nested collections/maps

Modified Files

  • IndexExportJob.java - Refactored to accept an IndexExportFormatter via the format() method chain; falls back to the configured default format
  • FessConfig.java - Added INDEX_EXPORT_FORMAT constant and getIndexExportFormat() accessor
  • fess_config.properties - Added index.export.format=html default configuration
  • IndexExportJobTest.java - Comprehensive test coverage for both formatters, format selection, and updated existing tests to work with the new formatter parameter

Testing

  • All existing IndexExportJob tests updated to pass the formatter explicitly
  • Added tests for HtmlIndexExportFormatter: basic formatting, HTML escaping, collection fields, empty/null values
  • Added tests for JsonIndexExportFormatter: basic formatting, JSON escaping, collection/nested values, numbers/booleans, special characters
  • Added tests for createFormatter(): valid formats (html, json), case insensitivity, whitespace handling, invalid/null/empty inputs
  • Added tests for buildFilePath with JsonIndexExportFormatter to verify .json extensions

Breaking Changes

None. The default behavior remains HTML export, and the buildFilePath method signature change is internal (protected).

…#3026)

Refactor IndexExportJob to support multiple export formats through a
strategy pattern. The new IndexExportFormatter interface allows adding
new export formats without modifying the core export logic.

Changes:
- Add IndexExportFormatter interface for pluggable format support
- Add HtmlIndexExportFormatter for HTML output (existing behavior)
- Add JsonIndexExportFormatter for JSON output (new format)
- Add index.export.format config property to select default format
- Update IndexExportJob to use formatter strategy with method chaining
- Add comprehensive unit tests for both formatters and format selection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@marevol marevol requested a review from Copilot February 7, 2026 10:26
@marevol marevol self-assigned this Feb 7, 2026
@marevol marevol added this to the 15.5.0 milestone Feb 7, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Refactors IndexExportJob to support multiple export output formats via a strategy pattern, introducing JSON export alongside the existing HTML behavior and enabling format selection via configuration or fluent API.

Changes:

  • Introduced IndexExportFormatter with HtmlIndexExportFormatter and new JsonIndexExportFormatter
  • Refactored IndexExportJob to resolve and use a formatter (fluent API + config default)
  • Added config key index.export.format and expanded test coverage for format selection + JSON output

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/main/java/org/codelibs/fess/job/IndexExportJob.java Refactors export flow to delegate formatting + extension decisions to a formatter strategy
src/main/java/org/codelibs/fess/job/IndexExportFormatter.java Adds formatter strategy interface contract
src/main/java/org/codelibs/fess/job/HtmlIndexExportFormatter.java Extracts existing HTML export logic into a strategy implementation
src/main/java/org/codelibs/fess/job/JsonIndexExportFormatter.java Adds new JSON export formatter implementation
src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java Adds config key + accessor for default export format
src/main/resources/fess_config.properties Adds default index.export.format=html
src/test/java/org/codelibs/fess/job/IndexExportJobTest.java Updates tests for new formatter parameter and adds extensive JSON/format-selection coverage
Comments suppressed due to low confidence (1)

src/main/java/org/codelibs/fess/mylasta/direction/FessConfig.java:1

  • This method implements the FessConfig interface and should be annotated with @Override for consistency with neighboring accessors and to get compiler checking on signature mismatches.
/*

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 208 to 214
if (path == null || path.isEmpty()) {
path = "/index.html";
path = "/" + formatter.getIndexFileName();
} else if (path.endsWith("/")) {
path = path + "index.html";
path = path + formatter.getIndexFileName();
} else if (!path.contains(".") || path.lastIndexOf('.') < path.lastIndexOf('/')) {
path = path + ".html";
path = path + formatter.getFileExtension();
}
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

When exporting JSON, buildFilePath() preserves an existing URL extension (e.g. /page.html stays .html) but the content written is JSON, which creates a file-extension/content mismatch and can break downstream consumers (and is surprising given index.export.format=json). Consider enforcing formatter.getFileExtension() for non-HTML formatters (e.g., replace any existing extension unless it already matches the formatter), or introduce an explicit option like “preserve original URL extension” and default it to false for JSON.

Copilot uses AI. Check for mistakes.
Comment on lines +90 to +102
protected IndexExportFormatter createFormatter(final String format) {
if (format == null || format.trim().isEmpty()) {
throw new IllegalArgumentException("Export format must not be null or empty");
}
switch (format.trim().toLowerCase()) {
case "html":
return new HtmlIndexExportFormatter();
case "json":
return new JsonIndexExportFormatter();
default:
throw new IllegalArgumentException("Unsupported export format: " + format);
}
}
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

toLowerCase() should specify a locale to avoid locale-dependent behavior (e.g., Turkish locale casing issues). Use toLowerCase(Locale.ROOT) (and add the corresponding import) for stable format matching.

Copilot uses AI. Check for mistakes.
@marevol marevol merged commit 44093a8 into master Feb 7, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant