Skip to content

Migrate from JAnsi to JLine, introduce MessageBuilderFactory#11874

Draft
slawekjaranowski wants to merge 2 commits intoapache:maven-3.10.xfrom
slawekjaranowski:jline
Draft

Migrate from JAnsi to JLine, introduce MessageBuilderFactory#11874
slawekjaranowski wants to merge 2 commits intoapache:maven-3.10.xfrom
slawekjaranowski:jline

Conversation

@slawekjaranowski
Copy link
Copy Markdown
Member

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

@slawekjaranowski slawekjaranowski self-assigned this Apr 1, 2026
@slawekjaranowski slawekjaranowski added the enhancement New feature or request label Apr 1, 2026
@slawekjaranowski slawekjaranowski added this to the 3.10.0 milestone Apr 1, 2026
@cstamas
Copy link
Copy Markdown
Member

cstamas commented Apr 1, 2026

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).

@slawekjaranowski
Copy link
Copy Markdown
Member Author

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 org.fusesource.jansi.Ansi implentation with fallback to JLine
org.fusesource. package is exported so everything works with old implentation from maven-shared

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

@slawekjaranowski slawekjaranowski force-pushed the jline branch 2 times, most recently from 571d3e1 to e1f1b79 Compare April 3, 2026 06:58
@slawekjaranowski slawekjaranowski requested a review from Bukama April 3, 2026 07:15
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
Copy link
Copy Markdown
Contributor

@gnodet gnodet left a comment

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

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 ecosystemmaven-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.

@slawekjaranowski
Copy link
Copy Markdown
Member Author

Issues:

  • breaking change in LifecycleExecutionException fixed
  • copy from master
  • maven-jline copy from master - also has no test
  • FastTerminal copy from master
  • add new line at the end of BSD-3-Clause.txt
  • should be done in separate PR

Question:

  1. Backward compatibility for the plugin ecosystem - we have exported artifact org.fusesource.jansi:jansi and org.fusesource.jansi.Ansi the same as in master - so compatibility is preserved

  2. In places when static method is used we don't have a plexus context to easy inject

  3. jline-terminal-ffm jline provider implementation - used dynamically by jline

@slawekjaranowski slawekjaranowski requested a review from gnodet April 3, 2026 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request mvn3

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants