How to Handle Parameter Formatting with Placeholders in Owner Configuration
Owner automatically injects method arguments into configuration values using Java's standard String.format with percent-style placeholders (%s, %d), not the indexed {0}, {1} syntax found in other frameworks.
Owner (matteobaccan/owner) is a lightweight Java library that maps property files to type-safe interfaces. When handling parameter formatting with placeholders in values, Owner delegates to java.util.Formatter, allowing dynamic substitution of method arguments into configuration strings at runtime.
How Owner Implements Parameter Formatting
Owner detects non-null argument lists on configuration interface methods and automatically applies String.format to the backing property value.
The %s Placeholder Syntax vs {0} Indexes
Unlike MessageFormat-style libraries that use {0} and {1} indexed placeholders, Owner follows the java.util.Formatter convention. In owner/src/main/java/org/aeonbits/owner/PropertiesInvocationHandler.java, the format(Method, String, Object...) method checks for arguments and invokes String.format(format, args).
The placeholders use standard Java conversion specifiers:
- %s for strings
- %d for integers
- %f for floating-point numbers
Automatic Formatting Trigger
When a method declaration includes parameters and the property value contains format specifiers, Owner substitutes arguments automatically. This occurs in PropertiesInvocationHandler.format(), which evaluates whether the PARAMETER_FORMATTING feature is enabled before processing.
Disabling Automatic Formatting
Sometimes configuration values contain literal percent signs or you need raw values without interpolation. Owner provides the @DisableFeature annotation defined in owner/src/main/java/org/aeonbits/owner/Config.java.
Method-Level Control
Apply @DisableFeature(PARAMETER_FORMATTING) to individual methods to return raw property values unchanged:
public interface RawConfig extends Config {
@DisableFeature(PARAMETER_FORMATTING)
@DefaultValue("Hello %s, welcome on ${planet}!")
String rawHello(String name);
}
When rawHello("Luigi") executes, it returns "Hello %s, welcome on ${planet}!" without attempting to format the %s placeholder.
Interface-Level Configuration
To disable formatting for all methods in an interface, annotate the interface itself:
@DisableFeature(PARAMETER_FORMATTING)
public interface AllRawConfig extends Config {
@DefaultValue("Path=%s")
String path(String dummy);
}
All methods inherit the disabled state, returning literal strings like Path=%s regardless of arguments passed.
Escaping Literal Percent Characters
When formatting remains enabled but values contain literal percent signs, use the standard Java escape sequence %%. This inserts a single % character without triggering format conversion.
public interface PercentConfig extends Config {
@DefaultValue("Discount is 20%% for %s")
String discount(String product);
}
Calling discount("books") produces: Discount is 20% for books.
Code Examples
Basic Parameter Substitution
public interface GreetingConfig extends Config {
@DefaultValue("Hello %s, welcome on %s!")
String hello(String name, String planet);
}
GreetingConfig cfg = ConfigFactory.create(GreetingConfig.class);
System.out.println(cfg.hello("Luigi", "Earth"));
// Output: Hello Luigi, welcome on Earth!
Owner passes the method arguments to String.format("Hello %s, welcome on %s!", "Luigi", "Earth") automatically.
Disabling Formatting for Passwords or URLs
public interface DatabaseConfig extends Config {
@DisableFeature(PARAMETER_FORMATTING)
@DefaultValue("jdbc:mysql://localhost?password=%s123")
String connectionString(String ignored);
}
The %s123 sequence remains unchanged in the output, preventing accidental format errors when passwords contain special characters.
Interface-Wide Raw Values
@DisableFeature(PARAMETER_FORMATTING)
public interface TemplateConfig extends Config {
@DefaultValue("Progress: 50%% complete")
String status();
}
Every method returns values literally, treating %% as two separate percent characters rather than an escaped sequence.
Summary
- Owner uses percent-style placeholders (
%s,%d) viaString.format, not{0}or{1}indexed syntax. - The PARAMETER_FORMATTING feature is enabled by default and implemented in
PropertiesInvocationHandler.java. - Use
@DisableFeature(PARAMETER_FORMATTING)to return raw configuration values without interpolation. - Escape literal percent signs with
%%when formatting is enabled. - The
DisableableFeatureenum and@DisableFeatureannotation are defined inConfig.java.
Frequently Asked Questions
Does Owner support MessageFormat-style {0} and {1} placeholders?
No. Owner exclusively uses java.util.Formatter syntax with percent-style conversion specifiers like %s and %d. The {0} and {1} syntax used by java.text.MessageFormat is not recognized by Owner's PropertiesInvocationHandler.format() method. You must convert existing {0} patterns to %s format strings.
How do I prevent Owner from interpreting % characters as format specifiers?
Annotate the method or interface with @DisableFeature(PARAMETER_FORMATTING) as defined in owner/src/main/java/org/aeonbits/owner/Config.java. This bypasses the automatic String.format call in PropertiesInvocationHandler.java, returning the raw property value including literal % characters.
Can I mix formatted and non-formatted methods in the same interface?
Yes. The @DisableFeature annotation works at the method level, allowing fine-grained control. Methods without the annotation process % placeholders normally, while annotated methods return raw values. This is demonstrated in owner/src/test/java/org/aeonbits/owner/DisableFeatureTest.java.
What happens if I pass more arguments than format specifiers?
Owner delegates to Java's String.format, which throws java.util.MissingFormatArgumentException if there are more arguments than format specifiers in the string. Ensure your property values contain the correct number of % placeholders matching the method parameter count.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →