'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
HOURSor 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
DAYSintoHOURS, But it doesn't do it for any other higher ChronoUnit (MONTHS,YEARSetc.).
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
PT720HorP30D. In case ofP30Djava's automatic conversion will take place and give usPT720H
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)
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 |
