Repository navigation
Type Safe API
TOMLy provides type-safe methods for accessing TOML values with automatic conversion and default value support.
Important
Methods returning lists may return null instead of an empty collection. This allows unambiguous detection of unset values without invoking additional methods.
Get a string value or null if missing:
String name = doc.getStr("app.name");
if (name != null) {
System.out.println("App name: " + name);
}
``
### getStr() with Default
Get a string value or return a default:
```java
String name = doc.getStr("app.name", "DefaultApp");
String env = doc.getStr("environment", "production");Compute default value lazily:
String name = doc.getStr("app.name", () -> {
return System.getProperty("app.name", "DefaultApp");
});
String timestamp = doc.getStr("created", () ->
LocalDateTime.now().toString()
);List<String> hosts = doc.getStrList("servers.hosts");
// Returns null if missing
if (hosts != null) {
hosts.forEach(System.out::println);
}List<String> hosts = doc.getStrList("servers.hosts", List.of("localhost"));
List<String> tags = doc.getStrList("tags", List.of());List<String> hosts = doc.getStrList("servers.hosts", () -> {
return List.of("localhost", "127.0.0.1");
});TOML integers are parsed as Integer if in range, otherwise as Long.
Integer port = doc.getInt("server.port");
if (port != null) {
startServer(port);
}int port = doc.getInt("server.port", 8080);
int timeout = doc.getInt("timeout", 30);
int retries = doc.getInt("retries", 3);int port = doc.getInt("server.port", () -> {
String envPort = System.getenv("PORT");
return envPort != null ? Integer.parseInt(envPort) : 8080;
});Returns fastutil's IntList for memory efficiency:
IntList ports = doc.getIntList("server.ports");
if (ports != null) {
for (int i = 0; i < ports.size(); i++) {
int port = ports.getInt(i);
System.out.println("Port: " + port);
}
}import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntLists;
IntList ports = doc.getIntList("server.ports", IntLists.emptyList());
IntList defaults = doc.getIntList("defaults", new IntArrayList(new int[]{1, 2, 3}));IntList ports = doc.getIntList("server.ports", () ->
new IntArrayList(new int[]{8080, 8081, 8082})
);For values that might exceed Integer range:
Long userId = doc.getLong("user.id");
Long timestamp = doc.getLong("timestamp");long userId = doc.getLong("user.id", 0L);
long maxSize = doc.getLong("max_size", 1000000L);long timestamp = doc.getLong("timestamp", () ->
System.currentTimeMillis()
);Returns fastutil's LongList:
LongList ids = doc.getLongList("user.ids");
if (ids != null) {
ids.forEach(id -> processUser(id));
}import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongLists;
LongList ids = doc.getLongList("user.ids", LongLists.emptyList());For floating-point numbers:
Double price = doc.getDbl("product.price");
Double rating = doc.getDbl("rating");TOML supports special float values:
tomlinfinity = inf
neg_infinity = -inf
not_a_number = nanDouble inf = doc.getDbl("infinity"); // Double.POSITIVE_INFINITY
Double negInf = doc.getDbl("neg_infinity"); // Double.NEGATIVE_INFINITY
Double nan = doc.getDbl("not_a_number"); // Double.NaNdouble price = doc.getDbl("product.price", 0.0);
double tax = doc.getDbl("tax_rate", 0.15);double price = doc.getDbl("product.price", () ->
calculateDefaultPrice()
);Returns fastutil's DoubleList:
DoubleList prices = doc.getDblList("products.prices");
if (prices != null) {
double total = prices.doubleStream().sum();
}import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import it.unimi.dsi.fastutil.doubles.DoubleLists;
DoubleList prices = doc.getDblList("prices", DoubleLists.emptyList());Boolean debug = doc.getBool("app.debug");
if (debug != null && debug) {
enableDebugMode();
}boolean debug = doc.getBool("app.debug", false);
boolean enabled = doc.getBool("feature.enabled", true);boolean debug = doc.getBool("app.debug", () ->
"development".equals(System.getenv("ENV"))
);Returns fastutil's BooleanList:
BooleanList flags = doc.getBoolList("feature.flags");
if (flags != null) {
for (int i = 0; i < flags.size(); i++) {
boolean flag = flags.getBoolean(i);
System.out.println("Flag " + i + ": " + flag);
}
}import it.unimi.dsi.fastutil.booleans.BooleanArrayList;
import it.unimi.dsi.fastutil.booleans.BooleanLists;
BooleanList flags = doc.getBoolList("flags", BooleanLists.emptyList());TOMLy supports all TOML date/time types.
Date without time or timezone:
release_date = 2025-10-01
birthday = 1990-05-15LocalDate release = doc.getLocalDate("release_date");
LocalDate birthday = doc.getLocalDate("birthday", LocalDate.now());
LocalDate defaultDate = doc.getLocalDate("date", () -> LocalDate.of(2025, 1, 1));Time without date or timezone:
start_time = 09:30:00
end_time = 17:45:30.500LocalTime start = doc.getLocalTime("start_time");
LocalTime end = doc.getLocalTime("end_time", LocalTime.of(17, 0));
LocalTime defaultTime = doc.getLocalTime("time", () -> LocalTime.now());Date and time without timezone:
created_at = 2025-10-01T09:30:00
updated_at = 2025-10-01T17:45:30.500LocalDateTime created = doc.getLocalDateTime("created_at");
LocalDateTime updated = doc.getLocalDateTime("updated_at", LocalDateTime.now());
LocalDateTime defaultDt = doc.getLocalDateTime("dt", () ->
LocalDateTime.of(2025, 1, 1, 0, 0)
);Date, time, and timezone:
timestamp = 2025-10-01T09:30:00+02:00
utc_time = 2025-10-01T09:30:00ZOffsetDateTime timestamp = doc.getOffsetDateTime("timestamp");
OffsetDateTime utc = doc.getOffsetDateTime("utc_time");
OffsetDateTime defaultOdt = doc.getOffsetDateTime("odt", () ->
OffsetDateTime.now()
);List<LocalDate> dates = doc.getLocalDateList("important_dates");
List<LocalTime> times = doc.getLocalTimeList("schedule");
List<LocalDateTime> events = doc.getLocalDateTimeList("events");
List<OffsetDateTime> timestamps = doc.getOffsetDateTimeList("logs");
// With defaults
List<LocalDate> dates = doc.getLocalDateList("dates", List.of(LocalDate.now()));For arrays of tables:
[[servers]]
name = "web1"
ip = "192.168.1.10"
[[servers]]
name = "web2"
ip = "192.168.1.11"List<TomlDocument> servers = doc.getSectionList("servers");
if (servers != null) {
for (TomlDocument server : servers) {
String name = server.getStr("name");
String ip = server.getStr("ip");
System.out.println(name + " -> " + ip);
}
}For mixed-type arrays:
mixed = [1, "text", true, 3.14]List<Object> mixed = doc.getList("mixed");
if (mixed != null) {
for (Object obj : mixed) {
if (obj instanceof Long) {
System.out.println("Number: " + obj);
} else if (obj instanceof String) {
System.out.println("String: " + obj);
}
}
}Get the raw Node object:
import com.github.groundbreakingmc.tomly.nodes.Node;
Node node = doc.get("server.port");
if (node != null) {
Object value = node.value();
int line = node.line();
int column = node.column();
List<String> comments = node.headerComments();
}Convert node value to plain Java object:
Object value = doc.raw("server.port"); // Returns Long
Map<String, Object> section = doc.raw(); // Entire document as MapCheck if a path exists:
if (doc.hasPath("database.url")) {
String url = doc.getStr("database.url");
connectToDatabase(url);
} else {
System.out.println("Database not configured");
}Navigate to a table:
TomlDocument server = doc.getSection("server");
if (server != null) {
String host = server.getStr("host");
int port = server.getInt("port", 8080);
}TOML supports multiple number formats:
# Decimal
decimal = 42
# Hexadecimal
hex = 0x2A
# Octal
octal = 0o52
# Binary
binary = 0b101010
# With underscores for readability
large = 1_000_000All are accessed the same way:
long decimal = doc.getLong("decimal"); // 42
long hex = doc.getLong("hex"); // 42
long octal = doc.getLong("octal"); // 42
long binary = doc.getLong("binary"); // 42
long large = doc.getLong("large"); // 1000000Values are NOT automatically converted between incompatible types:
port = 8080 # Integer
price = 19.99 # Float
enabled = true # Boolean
name = "MyApp" # String// Correct
int port = doc.getInt("port", 0);
// Returns 8080.0 because TOMLy automaticaly converts numbers
Double portDouble = doc.getDbl("port");
// Wrong - returns 0 because "MyApp" is not a number
int nameInt = doc.getInt("name", 0); // 0Match the getter to your expected TOML type:
// Good
int port = doc.getInt("server.port", 8080);
// Avoid if you know it's an int
Long portLong = doc.getLong("server.port");Always provide defaults for optional configuration:
int timeout = doc.getInt("timeout", 30);
String env = doc.getStr("environment", "production");
boolean debug = doc.getBool("debug", false);// Bad - always creates the list
List<String> hosts = doc.getStrList("hosts", createDefaultHosts());
// Good - only creates if needed
List<String> hosts = doc.getStrList("hosts", () -> createDefaultHosts());// Less efficient
String host = doc.getStr("server.host");
int port = doc.getInt("server.port");
int timeout = doc.getInt("server.timeout");
// More efficient
TomlDocument server = doc.getSection("server");
String host = server.getStr("host");
int port = server.getInt("port");
int timeout = server.getInt("timeout");Do not do this:
if (doc.hasPath("server.host")) {
String host = doc.getStr("server.host");
}Instead, simply check for null:
String host = doc.getStr("server.host");
if (host != null) {
// use host
}Avoid fetching the same configuration value multiple times at runtime.
Instead, read values once during initialization and store them in variables:
Example:
// Initialization
public class ConfigValues {
private String host;
private int port;
private int timeout;
public void setup() {
TomlDocument doc = ...
host = doc.getStr("server.host");
port = doc.getInt("server.port");
timeout = doc.getInt("server.timeout");
}
// ... Getters
}
ConfigValues configValues = new ConfigValues();
configValues.setup();
// Use later
ServerConnection connection = new ServerConnection(
configValues.getHost(),
configValues.getPort(),
configValues.getTimeout()
);This improves performance and keeps your code cleaner.
public class AppConfig {
private final Path configPath;
private String appName;
private String environment;
private boolean debug;
private ServerConfig serverConfig;
private List<String> enabledFeatures;
private Map<String, Object> databaseConfig;
public AppConfig(Path configPath) {
this.configPath = configPath;
}
public void setup() {
TomlDucument doc = Tomly.parse(configPath, false, PreserveOptions.defaultOptions());
appName = doc.getStr("app.name", "MyApp");
environment = doc.getStr("app.environment", "production");
debug = doc.getBool("app.debug", false);
TomlDocument server = doc.getSection("server");
if (server == null) {
serverConfig = new ServerConfig("localhost", 8080, 30);
} else {
String host = server.getStr("host", "localhost");
int port = server.getInt("port", 8080);
int timeout = server.getInt("timeout", 30);
serverConfig = new ServerConfig(host, port, timeout);
}
enabledFeatures = doc.getStrList("features.enabled", Collections.emptyList());
TomlDocument db = doc.getSection("database");
databaseConfig = db != null ? Map.copyOf(db.raw()) : Map.of();
}
public String getAppName() {
return appName;
}
public String getEnvironment() {
return environment;
}
public boolean isDebugEnabled() {
return debug;
}
public ServerConfig getServerConfig() {
return serverConfig;
}
public List<String> getEnabledFeatures() {
return enabledFeatures;
}
public Map<String, Object> getDatabaseConfig() {
return databaseConfig;
}
}- Learn about Working With Comments for documentation preservation
- See Modifying And Saving to change values