Markdown View Rendering (juneau-console-views-markdown)
juneau-console-views renders data tables and juneau-console renders chrome — neither
has any concept of a rendered document. The optional juneau-console-views-markdown module fills that gap:
hand it a markdown string, get back an HTML fragment, the same way a ViewDef turns a list of beans into a themed
table.
Because it is a separate, opt-in module, consumers that don't need markdown pay nothing — no markdown parser is
dragged into juneau-rest-server or the views toolkit by default.
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-console-views-markdown</artifactId>
<version>${juneau.version}</version>
</dependency>
The MarkdownRenderer SPI
The module's single extension point is the library-neutral
MarkdownRenderer
interface — one method, String toHtml(String markdown), so any parser can sit behind it:
MarkdownRenderer renderer = MarkdownRenderer.resolve();
String html = renderer.toHtml("# Runbook\n\nStep one.");
MarkdownRenderer.resolve() selects the active renderer via the standard java.util.ServiceLoader mechanism:
- If a consumer registers their own provider (a
META-INF/services/org.apache.juneau.console.views.markdown.MarkdownRendererfile naming their implementation class), that provider wins. - Otherwise the built-in commonmark-java default is used.
The default is intentionally not registered as a service, so a single consumer-supplied provider is always unambiguous.
The default: commonmark-java with GFM tables
The shipped default, CommonmarkMarkdownRenderer, wraps commonmark-java (BSD-2-Clause) with the GFM tables extension enabled out of the box. GFM tables are on by default because real documents (runbooks, onboarding guides) routinely use pipe tables, and core CommonMark renders them as paragraphs of literal pipes.
CommonmarkMarkdownRenderer renderer = new CommonmarkMarkdownRenderer();
// A GFM pipe table renders as a real <table>, not literal pipes.
String html = renderer.toHtml("""
| Name | Role |
| --- | --- |
| Alice | Admin |
""");
commonmark-java's parser and renderer are immutable and thread-safe once built, so a single renderer instance is safe to share across threads and reuse for every render.
Swapping the parser
To use a different parser (or a differently-configured commonmark instance), implement MarkdownRenderer and
register it as a service:
public class MyMarkdownRenderer implements MarkdownRenderer {
@Override
public String toHtml(String markdown) {
// ... your parser here ...
}
}
META-INF/services/org.apache.juneau.console.views.markdown.MarkdownRenderer:
com.example.MyMarkdownRenderer
MarkdownRenderer.resolve() will now return your implementation instead of the commonmark default.
Styling the output
The rendered HTML is meant to be dropped inside a .jc-prose container so it inherits the console's prose
typography (heading scale, list rhythm, pre/code, blockquote, and a static-table rule):
<div class="jc-prose">
<!-- MarkdownRenderer.resolve().toHtml(...) output here -->
</div>
See Admin-Console Chrome for the .jc-prose contract.
Panel wiring
Wiring rendered markdown into a Tab/Subtab panel's content property is a deferred follow-on integration point,
not part of this module — this module ships the renderer SPI and the commonmark-java default only.