Migrate from JAnsi to JLine, introduce MessageBuilderFactory#11874
Migrate from JAnsi to JLine, introduce MessageBuilderFactory#11874slawekjaranowski wants to merge 2 commits intoapache:maven-3.10.xfrom
Conversation
|
Cool beanz! But, I am +0 on this... I am not blocking anything, so I am not blocking this, but this change is big, and may make "migration from 3.9.x to 3.10.x" a bit harder than anticipated? (unsure, I hope I am wrong). |
I added Most code is copied from master branch Also I hope that in 3.10.x we can introduce new classes, api - plugins will can drop dependencies to maven-shared when only use for message colorize |
571d3e1 to
e1f1b79
Compare
What changed: - Replaced JAnsi with JLine for terminal output handling. - Added new MessageBuilder and MessageBuilderFactory for JLine integration as replacement for maven-shared-utils Why: - JAnsi is going to EOL
gnodet
left a comment
There was a problem hiding this comment.
Claude Code on behalf of Guillaume Nodet
Review: Migrate from JAnsi to JLine, introduce MessageBuilderFactory
Well-motivated migration — JAnsi has been merged into JLine since 3.25.0 and is no longer maintained separately. The PR replaces the JAnsi dependency with JLine, introduces a proper injectable MessageBuilder/MessageBuilderFactory API in maven-core, and provides backward compatibility for org.fusesource.jansi.Ansi. Nice work on the breadth of this change. CI is fully green across all 3 platforms and Java 8-25.
Note: This review covers project conventions and code-level observations. It does not replace specialized review tools (CodeRabbit, Sourcery) or static analysis (SonarCloud).
Confirmed Issues
1. Public API breaking change in LifecycleExecutionException (High)
The constructor (MojoExecution, MavenProject, Throwable) now requires MessageBuilderFactory as the first parameter. This is a public class — plugins or extensions that construct this exception will break at compile time.
Suggested fix: keep the old constructor as a @Deprecated overload using the no-color fallback that's already in maven-core:
@Deprecated
public LifecycleExecutionException(MojoExecution execution, MavenProject project, Throwable cause) {
this(new DefaultMessageBuilderFactory(), execution, project, cause);
}Callers using the old signature still compile and get a plain-text message. Internal Maven code uses the new constructor with the injected factory for styled output.
2. org.fusesource.jansi.Ansi compat class could delegate instead of re-implement (Medium)
The 957-line Ansi class is a full standalone re-implementation. Since org.jline.jansi.Ansi has a nearly identical API, this could be a thin wrapper that delegates to it — significantly less code and no risk of behavioral drift. Currently only render() and isEnabled()/setEnabled() delegate; everything else (fg(), bg(), bold(), cursor/erase operations, etc.) is re-implemented from scratch.
3. No tests for new maven-jline module (Medium)
FastTerminal, JLineMessageBuilderFactory, MessageUtils, the Ansi compat class, and the DefaultMessageBuilder/DefaultMessageBuilderFactory in maven-core all have zero test coverage. Basic coverage for the builder implementations and style resolution would reduce regression risk.
4. FastTerminal thread is not a daemon thread (Medium)
FastTerminal.java — the new Thread(...) for async terminal initialization is not set as a daemon thread. If terminal construction hangs, this could prevent JVM shutdown. Consider thread.setDaemon(true).
5. Missing newline at end of file (Low)
apache-maven/src/main/appended-resources/licenses/BSD-3-Clause.txt — \ No newline at end of file.
6. TODO left in code (Low)
AbstractMavenTransferListener.java adds // TODO use MessageBuilder without addressing it. Should be done here or tracked as a follow-up.
Questions
1. Backward compatibility for the plugin ecosystem — maven-shared-utils is removed from maven-core and maven-embedder. Plugins that use maven-shared-utils logging bring their own transitive dependency, but are there consumers that relied on maven-core's transitive exposure of maven-shared-utils?
2. Static vs. injectable MessageUtils — The PR introduces MessageBuilderFactory as a proper injectable service, but ExecutionEventLogger, MavenCli, CLIReportingUtils, and MavenSimpleLogger still use MessageUtils.builder() statically. Is there a plan to gradually migrate these?
3. jline-terminal-ffm on older JDKs — FFM requires Java 22+. The enforcer exclusion and <optional>true</optional> suggest JNI is the fallback — CI confirms this works on Java 8. Just flagging for awareness.
Summary
The main concern is the public API break in LifecycleExecutionException, which can be fixed with a deprecated overload. The Ansi compat class works but could be simplified by delegating to org.jline.jansi.Ansi. Adding basic tests for the new module would strengthen confidence. Overall a solid and well-structured migration.
|
Issues:
Question:
|
What changed:
Why: