'Spring boot 2 Converting Duration java 8 application.properties

I need to define Duration value (spring.redis.timeout) by application.properties.

I was trying to use one point defined in Spring boot documentation:

Spring Boot has dedicated support for expressing durations. If you expose a java.time.Duration property, the following formats in application properties are available:

A regular long representation (using milliseconds as the default unit unless a @DurationUnit has been specified) The standard ISO-8601 format used by java.util.Duration A more readable format where the value and the unit are coupled (e.g. 10s means 10 seconds)

When i use spring.redis.timeout=3s Spring boot application throws this exception:

Cannot convert value of type 'java.lang.String' to required type 'java.time.Duration': no matching editors or conversion strategy found

Which would it be the best way to set a correct value to a Duration property in application.properties withs last Spring boot 2 release?



Solution 1:[1]

Any property which is of type duration can be injected via .properties or .yml files. All you need to do is use a proper formatting.

If you want to inject a duration of 5 seconds it should be defined as PT5S or pt5s or PT5s

  • case of the letters doesn't matter, so you use any combination which is readable for you
  • generally everyone uses all capital letters

Other examples

PT1.5S       = 1.5 Seconds
PT60S        = 60 Seconds
PT3M         = 3 Minutes
PT2H         = 2 Hours
P3DT5H40M30S = 3Days, 5Hours, 40 Minutes and 30 Seconds

You can also use +ve and -ve signs to denote positive vs negative period of time.

  • You can negate only one of the entity for example: PT-3H30M = -3 hours, +30 minutes, basically -2.5Hours
  • Or You can negate the whole entity: -PT3H30M = -3 hours, -30 minutes, basically -3.5Hours
  • Double negative works here too: -PT-3H+30M = +3 Hours, -30 Minutes, basically +2.5Hours

Note:

  • Durations can only be represented in HOURS or lower ChronoUnit (NANOS, MICROS, MILLIS, SECONDS, MINUTES, HOURS) since they represent accurate durations
  • Higher ChronoUnit (DAYS, WEEKS, MONTHS, YEARS, DECADES,CENTURIES, MILLENNIA, ERAS, FOREVER) are not allowed since they don't represent accurate duration. These ChronoUnits have estimated duration due to the possibility of Days varying due to daylight saving, Months have different lengths etc.
  • Exception - Java does automatic conversion of DAYS into HOURS, But it doesn't do it for any other higher ChronoUnit (MONTHS, YEARS etc.).

If we try to do a "P1D", java automatically converts it into "PT24H". So If we want to do duration of 1 MONTH, we will have to use PT720H or P30D. In case of P30D java's automatic conversion will take place and give us PT720H


Upvote, if it works for you or you like the explanation. Thanks,

Solution 2:[2]

It's possible to use @Value notation with Spring Expression Language

@Value("#{T(java.time.Duration).parse('${spring.redis.timeout}')}")
private Duration timeout;

Solution 3:[3]

The Duration in the moment (Spring-Boot 2.0.4.RELEASE) it is not possible to use together with @Value notation, but it is possible to use with @ConfigurationProperties

For Redis, you have RedisProperties and you can use the configuration:

spring.redis.timeout=5s

And:

@SpringBootApplication
public class DemoApplication {

  @Autowired
  RedisProperties redisProperties;

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }

  @PostConstruct
  void init() {
    System.out.println(redisProperties.getTimeout());
  }
}

It printed (parse as 5s):

PT5S

https://docs.oracle.com/javase/8/docs/api//java/time/Duration.html#parse-java.lang.CharSequence-

Solution 4:[4]

Spring Boot attempts to coerce the external application properties to the right type when it binds to the @ConfigurationProperties beans. If you need custom type conversion, you can provide a ConversionService bean (with a bean named conversionService)

See: https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/htmlsingle/#boot-features-external-config-conversion

Create new ApplicationConversionService bean (it must be named conversionService ). Here you are my code tested with Spring boot 2.0.4:

@Configuration
public class Conversion {

@Bean
public ApplicationConversionService conversionService()
{
    final ApplicationConversionService applicationConversionService = new ApplicationConversionService();
    return applicationConversionService;
}

Here you are an example project using this approach:

https://github.com/cristianprofile/spring-data-redis-lettuce

Solution 5:[5]

If your Spring-Boot version or its dependencies don't put ApplicationConversionService into context (and Spring-Boot doesn't until 2.1), you can expose it explicitly

@Bean
public ConversionService conversionService() {
    return ApplicationConversionService.getSharedInstance();
}

It invokes Duration.parse, so you may use PT3S, PT1H30M, etc in properties files.

Solution 6:[6]

I was getting this error, but only during testing; the bean using a @Value-annotated Duration was otherwise working. It turned out that I was missing the @SpringBootTest annotation on the test case class (and the spring-boot-test dependency that provides it) and that was causing only a subset of standard converters to be available for use.

Solution 7:[7]

Update for Spring Boot 2.5.5


We can use @Value annotation together with application.properties values. For example you have the next property in your application.properties file:

your.amazing.duration=100ms

Then you can use it in the @Value annotation:

@Value("${your.amazing.duration}") 
final Duration duration;

That is all.


Supported units:

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

Docs: link

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Serge
Solution 3 CRISTIAN ROMERO MATESANZ
Solution 4
Solution 5 Max
Solution 6 Donal Fellows
Solution 7 Volodya Lombrozo