Search

Dark theme | Light theme
Showing posts with label Spring Boot:Sweets. Show all posts
Showing posts with label Spring Boot:Sweets. Show all posts

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.

October 6, 2024

Spring Sweets: Using Configuration Properties With DataSize

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 DataSize to configure properties that express a size in bytes. When we set the value of the property we can use a long value. The size is then in bytes as that is the default unit. We can also add a unit to the value. Valid units are B for bytes, KB for kilobytes, MB for megabytes, GB for gigabytes and TB for terabytes.

We can also use the @DataSizeUnit annotation to specify the unit of the property in our class annotated with @ConfigurationProperties. In that case a the value without a unit assigned to the property is already in the specified unit.

In the following example we define a record StorageProperties annotated with @ConfigurationProperties and two properties maxFileSize and cacheSize. The property maxFileSize has no unit assigned to the value so it will be in the default unit of bytes. The property cacheSize has the unit MB assigned so the value will be in megabytes.

package mrhaki;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.convert.DataSizeUnit;
import org.springframework.util.unit.DataSize;
import org.springframework.util.unit.DataUnit;

@ConfigurationProperties(prefix = "storage")
public record StorageProperties(
    DataSize maxFileSize /* Default unit is bytes */,
    @DataSizeUnit(DataUnit.MEGABYTES) DataSize cacheSize /* Explicit unit is megabytes */
) {}

In the following test we test the values of the properties in the class StorageProperties. We set the value of the maxFileSize property to 10MB with an explicit unit and the value of the cacheSize property without an explicit unit. We also test the values of the properties in bytes.

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 org.springframework.util.unit.DataSize;
import org.springframework.util.unit.DataUnit;

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

@SpringBootTest
@TestPropertySource(properties = {
    "storage.max-file-size=10MB", // value with explicit unit
    "storage.cache-size=500" // value without explicit unit
})
class StoragePropertiesTest {

    @Autowired
    private StorageProperties storageProperties;

    @Test
    void testMaxFileSize() {
        assertThat(storageProperties.maxFileSize())
            .isNotNull()
            // The DataSize class has useful static methods
            // to get values for a certain unit.
            .isEqualTo(DataSize.ofMegabytes(10));
    }

    @Test
    void testCacheSize() {
        assertThat(storageProperties.cacheSize())
            .isNotNull()
            .isEqualTo(DataSize.of(500, DataUnit.MEGABYTES));
    }

    @Test
    void testValuesInBytes() {
        // We can use the toBytes() method to get the actual bytes.
        assertThat(storageProperties.maxFileSize().toBytes())
            .isEqualTo(10 * 1024 * 1024);
        assertThat(storageProperties.cacheSize().toBytes())
            .isEqualTo(500 * 1024 * 1024);
    }
}

Written with Spring Boot 3.3.4.