Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/himansaBro/JungleConfig/llms.txt

Use this file to discover all available pages before exploring further.

JungleConfig resolves how to serialize and deserialize each value through a three-layer type system managed by NativeTypeConverter. The first layer is a registry of built-in TypeConverterAdapter implementations that handle common Java primitives and java.time types. The second layer is a Jackson fallback that handles POJOs, collections, and any type not covered by the registry. The third layer is the pluggable adapter interface itself, which allows you to register custom converters for your own types at construction time.

Built-in Types

JungleConfig ships with ten built-in adapters registered automatically by JungleConfig.getDefaultAdapters(). Each adapter implements the TypeConverterAdapter interface, which declares three methods: getType() returns the simple class name used as the type tag in the config file, ConvertToSave(Object) converts a value to its string representation, and CastToUse(String) parses that string back to the correct Java type.
Type tagJava classgetType() return
Booleanjava.lang.Boolean"Boolean"
Integerjava.lang.Integer"Integer"
Stringjava.lang.String"String"
Longjava.lang.Long"Long"
Doublejava.lang.Double"Double"
Floatjava.lang.Float"Float"
UUIDjava.util.UUID"UUID"
LocalDatejava.time.LocalDate"LocalDate"
LocalDateTimejava.time.LocalDateTime"LocalDateTime"
LocalTimejava.time.LocalTime"LocalTime"
Reading and writing these types requires no extra configuration:
JungleConfig config = new JungleConfig(new File("app.conf"));

config.Set("app.port", 8080);               // stored as Integer
config.Set("app.debug", true);              // stored as Boolean
config.Set("launch.date", LocalDate.now()); // stored as LocalDate

int port      = config.get("app.port", Integer.class);
boolean debug = config.get("app.debug", Boolean.class);
LocalDate d   = config.get("launch.date", LocalDate.class);

POJO and Collection Types

When a value’s class simple name is not found in the adapter registry, NativeTypeConverter falls back to Jackson serialization — provided FALLBACK_TO_SERIALIZE is true (the default in all four built-in factory methods). For POJOs, use SetPOJO to make the intent explicit. The type tag written to the file will be Json and the value will be the Jackson-serialized JSON string, URL-encoded:
public class ServerConfig {
    public String host;
    public int port;
}

ServerConfig cfg = new ServerConfig();
cfg.host = "localhost";
cfg.port = 9090;

config.SetPOJO("server", cfg);

// Read back as a POJO
ServerConfig loaded = config.get("server", ServerConfig.class);
For generic collections such as List<String> or Map<String, Integer>, use getCollection with a Jackson TypeReference to preserve generic type information at runtime:
import com.fasterxml.jackson.core.type.TypeReference;

config.Set("tags", List.of("alpha", "beta", "gamma"));

List<String> tags = config.getCollection("tags", new TypeReference<List<String>>() {});
Both get and getCollection have Optional-returning counterparts — Get and GetCollection — that return Optional.empty() instead of null when a key does not exist.

Type Resolution Order

NativeTypeConverter.ConvertToSave() determines how to serialize a value through the following steps, in order:
  1. Null check — if the data object is null, the type tag is immediately set to "null" and the value string is "null". No further steps are evaluated.
  2. "Json" explicit hint — if Set(key, data, type) is called with type equal to "Json", Jackson serializes the object immediately, regardless of whether a built-in adapter exists for the class. The type tag stored is "Json".
  3. Class simple name derivation — if the type string passed to Set(key, data, type) is blank (or Set(key, data) is called without a type), the type string is derived from dataObj.getClass().getSimpleName() and the process continues to step 4.
  4. Adapter registry lookup — the type string (from step 2 or derived in step 3) is looked up in the adapter registry. If a matching TypeConverterAdapter is found, its ConvertToSave(Object) method handles serialization.
  5. Jackson fallback — if the type is not in the registry and FALLBACK_TO_SERIALIZE is true (the default), Jackson serializes the object to JSON and the type tag is set to "Json".
  6. Exception — if the type is not in the registry and FALLBACK_TO_SERIALIZE is false, an InvalidConfigFormatException is thrown.
On read, the stored type tag drives deserialization: if the tag is Json or the requested class is not in the adapter registry, Jackson’s ConvertToObject is called; otherwise the matching TypeConverterAdapter.CastToUse handles it.

Null Values

Setting a key to null is fully supported. NativeTypeConverter detects a null data object before any other step and records the type tag as "null" with the value string "null":
config.Set("optional.feature", null);

String val = config.get("optional.feature", String.class); // returns null

Custom Adapters

The TypeConverterAdapter interface is intentionally minimal:
public interface TypeConverterAdapter {
    String getType();                       // simple name used as the type tag
    String ConvertToSave(Object object);    // object → String for storage
    Object CastToUse(String data);          // String → Object on read
}
You can pass additional adapters to the NativeTypeConverter constructor alongside the defaults. The adapter’s getType() return value is the key used for registry lookup, so it must match the class simple name of the values you intend to store with that adapter.
Call config.getTypeSimpleName(key) to inspect the type tag stored for any key at runtime. This is useful for debugging serialization issues or for writing generic utilities that need to branch on the stored type without reading the value itself. The Optional-returning variant GetTypeSimpleName(key) is also available.

Build docs developers (and LLMs) love