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
The first type, single-field periods, is new to version 1.4 of Joda-Time. These classes - Years, Months, Weeks, Days, Hours, Minutes, Seconds - all follow a very similar design, and only store the single field as implied by their name. Thus a Days object can only store a number of days.
The Spring framework uses standard Java bean setters, so we must declare setters for each of the properties. Note: If we don't use @Configuration in the POJO, then we need to add @EnableConfigurationProperties (ConfigProperties.class) in the main Spring application class to bind the properties into the POJO: That's it!
For a reminder, there are three ways of configuring a Spring container: Using XML configuration, here we list all our beans in the XML file, Using XML component scan, here we make use of Java annotation, which simply scans and looks for classes with @Component class, Using Java Configuration class, which we will discuss in this article.
For eg, had the bar bean been defined in a different @Configuration class , the way to inject the dependency then is along these lines: @Configuration public class AppConfig { @Autowired @Qualifier ("bar1") private Bar bar1; @Bean public Foo foo () { return new Foo (bar1); } }
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;
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);
}
}
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With