Markdown
The org.apache.juneau.marshall.markdown package provides Markdown serialization and parsing for POJOs. Output is optimized for human readability and LLM/AI consumption.
Markdown support is included in juneau-marshall.
| Maven | |
|---|
Two Modes
| Mode | Serializer | Use Case |
|---|---|---|
| Fragment | MarkdownSerializer | Compact tables/lists for embedding |
| Document | MarkdownDocSerializer | Full documents with headings for nested structure |
Fragment Mode Mapping
| Input type | Markdown output |
|---|---|
Single Bean | 2-column key-value table |
Single Map | 2-column key-value table |
Collection<Bean> | Multi-column table with header row |
Collection<Map> | Multi-column table with header row |
Collection<SimpleType> | Bulleted list |
| Nested bean (in table cell) | Inline JSON5 in backticks |
Quick Start
// A simple bean
public class Person {
public String name;
public int age;
public Person() {}
public Person(String name, int age) { this.name = name; this.age = age; }
}
// Fragment mode - table output
List<Person> people = List.of(new Person("Alice", 30), new Person("Bob", 25));
String md = MarkdownSerializer.DEFAULT.write(people);
// Produces:
// | name | age |
// |------|-----|
// | Alice | 30 |
// | Bob | 25 |
// Document mode - with headings
String doc = MarkdownDocSerializer.create().title("Report").build().write(people);
// Use the marshaller
String md2 = Markdown.of(people);
List<Person> parsed = Markdown.to(md, List.class, Person.class);
Document Mode
Document mode uses headings for nested structure:
public class Person {
public String name;
public Address address;
}
MarkdownDocSerializer s = MarkdownDocSerializer.create().title("Person").build();
String md = s.write(person);
Produces:
# Person
| Property | Value |
|----------|-------|
| name | John |
## address
| Property | Value |
|----------|-------|
| city | Springfield |
| state | IL |
Marshallers: Markdown vs MarkdownDoc
Each mode has its own marshaller — a serializer/parser pairing with convenience of(...) / to(...) methods:
| Marshaller | Backing serializer/parser | Output |
|---|---|---|
| Markdown | MarkdownSerializer / MarkdownParser | Fragment — a bare table or list, ideal for embedding inside a larger document |
| MarkdownDoc | MarkdownDocSerializer / MarkdownDocParser | Document — a full Markdown document that uses headings (#, ##, …) to represent nested structure |
Use Markdown when the result will be spliced into another document (for example, a table inside an LLM prompt or a README). Use MarkdownDoc when you want a standalone document whose nesting is expressed as a heading hierarchy rather than inline JSON5.
List<Person> people = List.of(new Person("Alice", 30), new Person("Bob", 25));
// Fragment marshaller - just the table
String fragment = Markdown.DEFAULT.of(people);
// Document marshaller - full document with headings
String document = MarkdownDoc.DEFAULT.of(people);
// Both round-trip back to POJOs
List<Person> parsed = MarkdownDoc.DEFAULT.to(document, List.class, Person.class);
MarshallUtils convenience methods
For one-off conversions without holding a marshaller reference, MarshallUtils provides static shortcuts that delegate to the Markdown.DEFAULT and MarkdownDoc.DEFAULT instances:
| Method | Delegates to | Purpose |
|---|---|---|
markdown(Object) | Markdown.DEFAULT.of(...) | Serialize to a fragment |
markdown(Object, Class) | Markdown.DEFAULT.to(...) | Parse a fragment into a POJO |
markdownDoc(Object) | MarkdownDoc.DEFAULT.of(...) | Serialize to a whole document |
markdownDoc(Object, Class) | MarkdownDoc.DEFAULT.to(...) | Parse a whole document into a POJO |
import static org.apache.juneau.marshall.marshaller.MarshallUtils.*;
String fragment = markdown(people); // fragment mode
String document = markdownDoc(people); // document mode
Media Types
- Produces:
text/markdown - Accepts:
text/markdown,text/x-markdown
REST Integration
// Markdown is included in BasicUniversalConfig
@Rest
public class MyResource extends RestServlet implements BasicUniversalConfig { ... }
Annotations
@Markdown customizes rendering on classes, methods and fields:
| Attribute | Description |
|---|---|
format | Rendering format override (MarkdownFormat). |
heading | Custom heading text in document mode (overrides the property name). |
noTables | Force list rendering instead of tables for collections. |
noHeaders | Suppress the table header row. |
code | Render the value as inline backtick-quoted code. |
link | Render the value as a link; {value} in the URL template is replaced by the property value. |
public class Person {
@Markdown(code=true) public String id;
@Markdown(link="https://example.com/users/{value}") public String login;
@Markdown(noTables=true) public List<String> tags;
}
@MarkdownConfig currently exposes only rank
(serializer and parser settings are set through the builders), and
@MarkdownApply applies an @Markdown to other
classes/members via on()/onClass() (see Dynamically Applied Annotations).