Skip to content

Working With Comments

GroundbreakingMC edited this page Oct 3, 2025 · 1 revision

Working With Comments

TOMLy can preserve and work with TOML comments, a unique feature among Java TOML libraries.

Types of Comments

TOML supports single-line comments starting with #:

Header Comments

Comments appearing before a key-value pair or table:

# This is a header comment
# It can span multiple lines
name = "MyApp"

Inline Comments

Comments on the same line as a value:

name = "MyApp"  # This is an inline comment
port = 8080     # Default port

Blank Lines

Empty lines that separate values or sections:

name = "MyApp"

version = "1.0.0"

[server]
host = "localhost"

Enabling Comment Preservation

PreserveOptions options = PreserveOptions.builder()
    .preserveHeaderComments(true)
    .preserveInlineComments(true)
    .preserveBlankLines(true)
    .build();

TomlDocument doc = Tomly.parse(toml, false, options);

Accessing Comments

Comments are stored in Node objects:

String toml = """
    # Application configuration
    # Version 1.0
    name = "MyApp"  # The application name
    version = "1.0.0"
    """;

PreserveOptions options = PreserveOptions.builder()
    .preserveHeaderComments(true)
    .preserveInlineComments(true)
    .build();

TomlDocument doc = Tomly.parse(toml, true, options);

Node nameNode = doc.get("name");

// Get header comments
List<String> headers = nameNode.headerComments();
// ["# Application configuration", "# Version 1.0"]

// Get inline comment
String inline = nameNode.inlineComment();
// "The application name"

// Get position
int line = nameNode.line();     // 3
int column = nameNode.column(); // 0

Blank Lines as Comments

With preserveBlankLines(), empty lines appear as empty strings:

PreserveOptions options = PreserveOptions.builder()
    .preserveBlankLines(true)
    .preserveHeaderComments(true)
    .build();

String toml = """
    # Comment

    name = "value"
    """;

TomlDocument doc = Tomly.parse(toml, true, options);
Node node = doc.get("name");
List<String> comments = node.headerComments();
// ["# Comment", ""]

Header Comments Details

Comment Collection Rules

  1. Only consecutive comment lines are collected
  2. Blank lines break the sequence if preserveBlankLines is set to false
  3. Leading # is not removing
  4. All whitespaces after # in header comments is preserved

Example:

# Comment 1
# Comment 2

#   Comment 3 (separate block)
name = "value"
Node node = doc.get("name");
List<String> comments = node.headerComments();
// ["# Comment 1", "# Comment 2", "", "#   Comment 3 (separate block)"]

Inline Comments Details

Comment Parsing

  1. Must be on the same line as the value
  2. Leading/trailing whitespace is trimmed
  3. # character is removed

Example:

name = "value"  # This is inline
port = 8080     #No leading space is still valid
count = 42#This works too
String comment1 = doc.get("name").inlineComment();   // "This is inline"
String comment2 = doc.get("port").inlineComment();   // "No leading space is still valid"
String comment3 = doc.get("count").inlineComment();  // "This works too"

No Inline Comment

If there's no inline comment, returns null:

String toml = "name = \"value\"";
TomlDocument doc = Tomly.parse(toml, true, options);
String comment = doc.get("name").inlineComment(); // null

Comments on Tables

Tables can also have comments:

# Server configuration
# Contains host and port settings
[server]
host = "localhost"  # Default host
port = 8080
Node serverNode = doc.get("server");
List<String> headers = serverNode.headerComments();
// [" Server configuration", " Contains host and port settings"]

TomlDocument server = doc.getSection("server");
Node hostNode = server.get("host");
String inline = hostNode.inlineComment(); // " Default host"

Comments on Arrays

Arrays but not their elements can have comments:

# List of servers
servers = [
    "server1",  # this will cause an exception
    "server2",
    "server3"
]
Node serversNode = doc.get("servers");
List<String> arrayComments = serversNode.headerComments();
// [" List of servers"]

Writing Comments

When saving TOML, control comment output with WriterOptions:

WriterOptions options = WriterOptions.builder()
    .writeHeaderComments(true)
    .writeInlineComments(true)
    .writeBlankLines(true)
    .build();

doc.save(Path.of("output.toml"), options);

Use Cases

Documented Configuration Files

Generate configuration with documentation:

// Create nodes with comments
StringNode appName = new StringNode(
    "MyApp",
    List.of("# Application name", "# Used in logs and UI"),
    "Change with care"
);

doc.set("app.name", appName);

WriterOptions options = WriterOptions.builder()
    .writeHeaderComments(true)
    .writeInlineComments(true)
    .build();

doc.save(Path.of("config.toml"), options);

Output:

# Application name
# Used in logs and UI
[app]
name = "MyApp"  # Change with care

Configuration Migration

Preserve comments when updating config files:

PreserveOptions parseOpts = PreserveOptions.builder()
    .preserveHeaderComments(true)
    .preserveInlineComments(true)
    .preserveBlankLines(true)
    .build();

WriterOptions writeOpts = WriterOptions.builder()
    .writeHeaderComments(true)
    .writeInlineComments(true)
    .writeBlankLines(true)
    .build();

// Load with comments
TomlDocument doc = Tomly.parse(oldConfigPath, true, parseOpts);

// Update values
doc.set("version", new StringNode("2.0.0", List.of(), null));

// Save with comments preserved
doc.save(newConfigPath, writeOpts);

Documentation Extraction

Extract documentation from TOML files:

TomlDocument doc = Tomly.parse(configPath, true, options);

Map<String, Node> raw = doc.value();
for (Map.Entry<String, Node> entry : raw.entrySet()) {
    Node node = entry.getValue();
    List<String> docs = node.headerComments();
    
    if (!docs.isEmpty()) {
        System.out.println("Key: " + entry.getKey());
        System.out.println("Documentation:");
        docs.forEach(comment -> System.out.println("  " + comment.substring(1).trim()));
        System.out.println();
    }
}

Template Generation

Create config templates with helpful comments:

public TomlDocument createTemplate() {
    TomlDocument doc = new DocumentNode(new LinkedHashMap<>(), 1, 0, List.of(), null);
    
    doc.set("app.name", new StringNode(
        "MyApp",
        List.of("# Application name"),
        "required"
    ));
    
    doc.set("app.version", new StringNode(
        "1.0.0",
        List.of("# Semantic version"),
        "format: major.minor.patch"
    ));
    
    doc.set("server.host", new StringNode(
        "localhost",
        List.of("# Server configuration", " Bind address"),
        "use 0.0.0.0 for all interfaces"
    ));
    
    doc.set("server.port", new NumberNode(
        8080L,
        1, 0,
        List.of("# Port number"),
        "1024-65535"
    ));
    
    return doc;
}

TomlDocument template = createTemplate();
WriterOptions options = WriterOptions.builder()
    .writeHeaderComments(true)
    .writeInlineComments(true)
    .writeBlankLines(true)
    .build();

template.save(Path.of("config.template.toml"), options);

Limitations

Element-Level Comments

Currently, individual array elements cannot have their own comments preserved:

servers = [
    "server1",  # This comment is lost
    "server2"   # This too
]

Only the array itself can have comments:

# This comment is preserved
servers = ["server1", "server2"]

Inline Table Comments

Inline tables have limited comment support:

server = { host = "localhost", port = 8080 }  # Only this is preserved

Individual fields in inline tables cannot have inline comments.


Recommendation: Use comment preservation only when needed (templates, documentation, config management).

Best Practices

  1. Enable only needed preservation: Don't enable preserveBlankLines if you don't need them
  2. Document your configuration: Use header comments for field documentation
  3. Keep inline comments short: They should fit on one line
  4. Use blank lines for grouping: Separate logical sections with blank lines

Next Steps