# How to Disable Variable Expansion or Parameter Formatting with @DisableFeature in Owner

> Disable variable expansion and parameter formatting in Owner using @DisableFeature. Control config processing at method or class level for precise configuration management with the Owner library.

- Repository: [Matteo Baccan/owner](https://github.com/matteobaccan/owner)
- Tags: how-to-guide
- Published: 2026-03-07

---

**Use the `@DisableFeature` annotation to selectively turn off automatic variable expansion (`${…}`) or parameter formatting (`%s`, `%d`) at either the method or class level in the Owner configuration library.**

The Owner library (matteobaccan/owner) automatically processes configuration values by expanding variables like `${property}` and formatting strings using `String.format`. When you need raw, unprocessed values, the `@DisableFeature` annotation provides fine-grained control over these behaviors through the `Config.DisableableFeature` enum.

## Understanding @DisableFeature and DisableableFeature

The `@DisableFeature` annotation is defined in [`owner/src/main/java/org/aeonbits/owner/Config.java`](https://github.com/matteobaccan/owner/blob/main/owner/src/main/java/org/aeonbits/owner/Config.java) alongside the `DisableableFeature` enum (lines 274-277 and 284-286). This enum defines two constants you can disable:

- `VARIABLE_EXPANSION` – Controls substitution of `${…}` placeholders in property keys and values
- `PARAMETER_FORMATTING` – Controls `String.format` processing for method parameters containing format specifiers like `%s` or `%d`

The annotation accepts an array of `DisableableFeature` values, allowing you to disable one or both features simultaneously on methods or types.

## Disabling Variable Expansion

When you disable `VARIABLE_EXPANSION`, Owner bypasses the `expandKey` and `expandVariables` methods in [`PropertiesInvocationHandler.java`](https://github.com/matteobaccan/owner/blob/main/PropertiesInvocationHandler.java) (lines 105-110 and 135-139). This prevents `${…}` placeholders from being replaced with referenced property values.

Apply the annotation at the method level to return literal placeholder text:

```java
public interface GreetingConfig extends Config {
    @DefaultValue("Earth")
    String world();

    @DisableFeature(VARIABLE_EXPANSION)
    @DefaultValue("Hello ${world}.")
    String helloRaw();      // Returns "Hello ${world}." literally

    @DefaultValue("Hello ${world}.")
    String helloExpanded(); // Returns "Hello Earth."
}

```

```java
GreetingConfig cfg = ConfigFactory.create(GreetingConfig.class);
System.out.println(cfg.helloRaw());      // Output: Hello ${world}.
System.out.println(cfg.helloExpanded()); // Output: Hello Earth.

```

## Disabling Parameter Formatting

Parameter formatting uses `String.format` to inject method arguments into property values. When disabled via `PARAMETER_FORMATTING`, the `format` method in [`PropertiesInvocationHandler.java`](https://github.com/matteobaccan/owner/blob/main/PropertiesInvocationHandler.java) (lines 112-119) returns the original value unchanged.

Disable formatting to preserve format specifiers as literal text:

```java
public interface MessageConfig extends Config {
    @DisableFeature(PARAMETER_FORMATTING)
    @DefaultValue("Hello %s.")
    String raw(String name);      // Returns "Hello %s." literally

    @DefaultValue("Hello %s.")
    String formatted(String name); // Returns "Hello Luigi."
}

```

```java
MessageConfig cfg = ConfigFactory.create(MessageConfig.class);
System.out.println(cfg.raw("Luigi"));      // Output: Hello %s.
System.out.println(cfg.formatted("Luigi")); // Output: Hello Luigi.

```

## Disabling Both Features at Class Level

Apply `@DisableFeature` to the interface declaration to affect all methods. This is useful when you need raw configuration values throughout your application.

```java
@DisableFeature({VARIABLE_EXPANSION, PARAMETER_FORMATTING})
public interface MixedConfig extends Config {
    @DefaultValue("Earth")
    String planet();

    @DefaultValue("Hello %s, welcome on ${planet}!")
    String greeting(String name);   // Returns literal with both placeholders
}

```

```java
MixedConfig cfg = ConfigFactory.create(MixedConfig.class);
System.out.println(cfg.greeting("Luigi")); 
// Output: Hello %s, welcome on ${planet}!

```

## How the Disabling Mechanism Works

The Owner library implements feature disabling through the `Util.isFeatureDisabled` method in [`owner/src/main/java/org/aeonbits/owner/util/Util.java`](https://github.com/matteobaccan/owner/blob/main/owner/src/main/java/org/aeonbits/owner/util/Util.java) (lines 28-33). This utility checks both the method and its declaring class for the `@DisableFeature` annotation:

```java
public static boolean isFeatureDisabled(Method method, DisableableFeature feature) {
    DisableFeature annotation = method.getAnnotation(DisableFeature.class);
    if (annotation == null) 
        annotation = method.getDeclaringClass().getAnnotation(DisableFeature.class);
    return annotation != null && Arrays.asList(annotation.value()).contains(feature);
}

```

In [`PropertiesInvocationHandler.java`](https://github.com/matteobaccan/owner/blob/main/PropertiesInvocationHandler.java), this check determines whether to skip processing:

- **Key expansion** (lines 105-110): Returns the key unmodified if `VARIABLE_EXPANSION` is disabled
- **Value formatting** (lines 112-119): Returns the value unmodified if `PARAMETER_FORMATTING` is disabled  
- **Variable expansion** (lines 135-139): Skips placeholder substitution if `VARIABLE_EXPANSION` is disabled

The test suite in [`owner/src/test/java/org/aeonbits/owner/DisableFeatureTest.java`](https://github.com/matteobaccan/owner/blob/main/owner/src/test/java/org/aeonbits/owner/DisableFeatureTest.java) verifies these behaviors for both method-level and class-level annotations.

## Summary

- Use `@DisableFeature(VARIABLE_EXPANSION)` to prevent `${…}` placeholder substitution in property keys and values
- Use `@DisableFeature(PARAMETER_FORMATTING)` to skip `String.format` processing for method parameters
- Apply the annotation to individual methods or to the entire interface class to affect all methods
- The feature check is implemented in `Util.isFeatureDisabled` and honored in `PropertiesInvocationHandler` for key expansion, variable expansion, and parameter formatting

## Frequently Asked Questions

### Can I disable features for the entire configuration interface?

Yes. Apply `@DisableFeature` at the class level on your interface that extends `Config`. This disables the specified features for all methods in that interface. The `Util.isFeatureDisabled` method checks both the method and its declaring class, so class-level annotations are automatically inherited by all methods unless overridden by method-specific annotations.

### What happens to ${...} placeholders when variable expansion is disabled?

When `VARIABLE_EXPANSION` is disabled via `@DisableFeature`, Owner returns the property value exactly as defined in the source. The `${...}` syntax remains literal text rather than being replaced by referenced property values. This bypasses the `expandVariables` method in [`PropertiesInvocationHandler.java`](https://github.com/matteobaccan/owner/blob/main/PropertiesInvocationHandler.java) (lines 135-139) and the `expandKey` method (lines 105-110).

### Does @DisableFeature affect hot reloading or other Owner features?

No. The `@DisableFeature` annotation specifically targets only variable expansion and parameter formatting logic within `PropertiesInvocationHandler`. It does not impact other Owner capabilities such as hot reloading, event listeners, or variable interpolation strategies. The annotation is checked only during the method invocation handling phase when resolving property values in the `invoke` method flow.

### How do I verify that a feature is actually disabled?

You can verify the disabled state by testing method return values against expected literal strings. For variable expansion, configure a property with a `${...}` reference and ensure the raw placeholder appears in the output rather than the expanded value. For parameter formatting, pass arguments to a method with `%s` or similar specifiers and verify the format string returns unchanged. The test suite in [`DisableFeatureTest.java`](https://github.com/matteobaccan/owner/blob/main/DisableFeatureTest.java) demonstrates these verification patterns for both method-level and class-level annotations.