Search

Dark theme | Light theme

October 10, 2024

Spring Sweets: Using Duration Type With Configuration Properties

With @ConfigurationProperties in Spring Boot we can bind configuration properties to Java classes. The class annotated with @ConfigurationProperties can be injected into other classes and used in our code. We can use the type Duration to configure properties that express a duration. When we set the value of the property we can use:

  • a long value with the unit to express milliseconds,
  • a value following the ISO-8601 duration format,
  • a special format supported by Spring Boot with the value and unit.

We can also use the @DurationUnit annotation to specify the unit for a long value. So instead of the default milliseconds we can specify the unit to be seconds or minutes for example. The unit is defined by the java.time.temporal.ChronoUnit enum and we pass it as an argument to the annotation.

The special format supported by Spring Boot supports the following units:

  • ns for nanoseconds,
  • us for microseconds,
  • ms for milliseconds,
  • s for seconds,
  • m for minutes,
  • h for hours,
  • d for days.

In the following example we define a record TimeoutProperties annotated with @ConfigurationProperties and four properties of type Duration. The property idleTimeout has the @DurationUnit annotation to specify the unit to be seconds.

package mrhaki;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.convert.DurationUnit;

import java.time.Duration;
import java.time.temporal.ChronoUnit;

@ConfigurationProperties(prefix = "timeout")
public record TimeoutProperties(
    Duration connectionTimeout,
    Duration readTimeout,
    Duration writeTimeout,
    @DurationUnit(ChronoUnit.SECONDS) Duration idleTimeout
) {}

In our application.properties file we can set the values of the properties:

# long value (in milliseconds)
timeout.connection-timeout=5000

# ISO-8601 format
timeout.read-timeout=PT30S

# Spring Boot's format
timeout.write-timeout=1m

# value in seconds (due to @DurationUnit annotation)
timeout.idle-timeout=300

In the following test we test the values of the properties in the class TimeoutProperties.

package mrhaki;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;

import java.time.Duration;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest
@TestPropertySource(properties = {
    "timeout.connection-timeout=5000", // use long value in milliseconds
    "timeout.read-timeout=PT30S", // use ISO-8601 duration format
    "timeout.write-timeout=1m", // use special format supported by Spring Boot
    "timeout.idle-timeout=300" // use long value in seconds (set by @DurationUnit)
})
class TimeoutPropertiesTest {

    @Autowired
    private TimeoutProperties timeoutProperties;

    @Test
    void testConnectionTimeout() {
        assertThat(timeoutProperties.connectionTimeout())
            .isEqualTo(Duration.ofMillis(5000))
            .isEqualTo(Duration.ofSeconds(5));
    }

    @Test
    void testReadTimeout() {
        assertThat(timeoutProperties.readTimeout())
            .isEqualTo(Duration.ofSeconds(30));
    }

    @Test
    void testWriteTimeout() {
        assertThat(timeoutProperties.writeTimeout())
            .isEqualTo(Duration.ofMinutes(1))
            .isEqualTo(Duration.ofSeconds(60));
    }


    @Test
    void testIdleTimeout() {
        assertThat(timeoutProperties.idleTimeout())
            .isEqualTo(Duration.ofSeconds(300))
            .isEqualTo(Duration.ofMinutes(5));
    }

    @Test
    void testTimeoutToMillis() {
        assertThat(timeoutProperties.connectionTimeout().toMillis()).isEqualTo(5000);
        assertThat(timeoutProperties.readTimeout().toMillis()).isEqualTo(30000);
        assertThat(timeoutProperties.writeTimeout().toMillis()).isEqualTo(60000);
        assertThat(timeoutProperties.idleTimeout().toMillis()).isEqualTo(300000);
    }
}

Written with Spring Boot 3.4.4.