How to spring inject configuration value for Joda Period
Asked Answered
P

4

5

How can I use the @Value annotation to configure a Joda-Time Period field in my spring bean?

E.g. Given the following component class:

@Component
public class MyService {

  @Value("${myapp.period:P1D}")
  private Period periodField;
...
}

I want to use standard ISO8601 format to define the period in a properties file.

I get this error:

Caused by: java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [org.joda.time.Period]: no matching editors or conversion strategy found
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:302)
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:125)
    at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:61)
    ... 35 more
Punak answered 30/11, 2015 at 17:20 Comment(2)
It is likely that you need to register a converter String->JodaPeriodBouquet
Thanks. Do you know of any examples for this?Punak
D
5

What you can do is register a Spring ConversionService bean and implement a proper converter.

@Bean
public ConversionServiceFactoryBean conversionService() {
    ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
    Set<Converter<?, ?>> myConverters = new HashSet<>();
    myConverters.add(new StringToPeriodConverter());
    conversionServiceFactoryBean.setConverters(myConverters);
    return conversionServiceFactoryBean;
}

public class StringToPeriodConverter implements Converter<String, Period> {

    @Override
    public Period convert(String source) {
        return Period.parse(source);
    }
}
Dryden answered 15/12, 2015 at 10:38 Comment(1)
Great stuff. Thanks for your help.Punak
A
8

A simple solution that does not require any java code is to use Spring Expression Language (SpEL).

(My example uses java.time.Duration and not Joda stuff but I think you get it anyway.)

    @Value("#{T(java.time.Duration).parse('${notifications.maxJobAge}')}")
    private Duration maxJobAge;
Anabasis answered 23/8, 2016 at 15:52 Comment(1)
this requires a lot of tinkering if I must have a default value of null, since java.time.Duration::parse will be unhappy about null argument.Porky
D
5

What you can do is register a Spring ConversionService bean and implement a proper converter.

@Bean
public ConversionServiceFactoryBean conversionService() {
    ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
    Set<Converter<?, ?>> myConverters = new HashSet<>();
    myConverters.add(new StringToPeriodConverter());
    conversionServiceFactoryBean.setConverters(myConverters);
    return conversionServiceFactoryBean;
}

public class StringToPeriodConverter implements Converter<String, Period> {

    @Override
    public Period convert(String source) {
        return Period.parse(source);
    }
}
Dryden answered 15/12, 2015 at 10:38 Comment(1)
Great stuff. Thanks for your help.Punak
R
1

Another, not elegant, option, is to use a String setter who invokes the parse method.

@Value("${myapp.period:P1D}")
public void setPeriodField(String periodField)
{
    if (isBlank(periodField))
        this.periodField= null;
    this.periodField= Duration.parse(periodField);
}
Ratcliffe answered 23/8, 2017 at 15:11 Comment(0)
M
0

For joda-time:2.10.13 and spring-boot:2.3.2.RELEASE next example (like in question) is worked:

  @Value("${myapp.period:P1D}")
  private Period periodField;

If you use java.time.Period, in addition, worked a simple period property format (org.springframework.boot.convert.PeriodStyle):

  @Value("${myapp.period:1d}")
  private Period periodField;
Milled answered 2/2, 2022 at 8:18 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.