question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ConversionService is inconsistently used in Spring Boot application

See original GitHub issue

I apologize in advance for cross-posting, but I have not received useful help on Stack Overflow and I suspect that the issue I am facing is either a bug in Spring Boot or at least very poor documentation. Original context here:

http://stackoverflow.com/questions/37952166/spring-boot-test-case-doesnt-use-custom-conversion-service

Short version is, I would like to configure my ConversionService to understand new types (i.e. java.time.Duration). Per the docs, I try to wire it up with:

@Configuration
public class ConversionServiceConfiguration {
    private static final FormattingConversionService SERVICE = new DefaultFormattingConversionService();

    static {
        new DateTimeFormatterRegistrar().registerFormatters(SERVICE);
    }

    @Bean
    public static ConversionService conversionService() {
        return SERVICE;
    }
}

but it keeps being ineffective:

>  Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'AttachClientRule': Unsatisfied dependency expressed through constructor parameter 0:
> Error creating bean with name 'MyServiceConfig': Unsatisfied dependency expressed through field 'maxWatchTime': Failed to convert value of type [java.lang.String] to required type [java.time.Duration];
> nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [java.time.Duration]: no matching editors or conversion strategy found;

The BeanFactory still has a DefaultConversionService sticking around from before I set my own.

I can fix this one with one hack:

... implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        beanFactory.setConversionService(SERVICE);
    }
}

and then I get a different problem, where again the Environment doesn’t have it set either!

> Caused by: java.lang.IllegalArgumentException: Cannot convert value [PT15s] from source type [String] to target type [Duration]
>   at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:94)
>   at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:65)
>   at org.springframework.core.env.AbstractPropertyResolver.getProperty(AbstractPropertyResolver.java:143)
>   at org.springframework.core.env.AbstractEnvironment.getProperty(AbstractEnvironment.java:546)

Time for another hack:

... implements EnvironmentAware {
    @Override
    public void setEnvironment(Environment environment) {
        ((AbstractEnvironment) environment).setConversionService(SERVICE);
    }
}

And that fixes this problem.

But how long until I find the next place one of these icky DefaultConversionService instances is lying around? How can I make Spring Boot actually use my custom one for everything without having to keep diving deep into the guts and find lingering problems?

Spring 4.3.0, Spring Boot 1.4.0M3

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:26 (11 by maintainers)

github_iconTop GitHub Comments

2reactions
ksperlingcommented, Sep 28, 2016

I’m running into a similar issue with ConversionService where something as seemingly trivial as @Value("${classifications:}") Set<String> classifications; doesn’t work as expected: It injects a set containing an empty string, rather than an empty set (unhelpfully they both toString to [] so I was scratching my head there for an hour…).

I tracked this down to the fact that even though PropertySourcesPropertyResolver (via AbstractPropertyResolver) has/uses a DefaultConversionService internally, that service isn’t actually used by the BeanFactory when it’s trying to convert that value. The bean factory seems to have no conversion service by default so falls back to some property editors that end up doing the wrong thing. In the end I used a BeanFactoryPostProcessor similar to the OP to work around this by setting a DefaultConversionService on the bean factory itself.

It would be nice if the usage of ConversionService within the configuration machinery were more obvious (i.e. using the same instance in all places as far as possible, making it easy to customize) and better documented (e.g. the fact that simply defining a conversionService bean doesn’t help for these sort of issues because it gets registered way too late.)

2reactions
jhoellercommented, Jul 6, 2016

As for further JSR-310 support at the DefaultConversionService level, note that we have convention-based support for class-contained valueOf/of/from methods there, actually aligned with JSR-310 by design. However, for the purposes above, Duration just has a parse(CharSequence) method. We could extend our convention there to find such parse methods for String input as well, which would take us a long way… probably with no specific converters to be added for JSR-310 at all.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Multiple conversionServices in spring-boot - Stack Overflow
I was experiencing a similar issue. The problem seems to be that you need to define which conversion service you want to use....
Read more >
Spring Autowiring - It's a kind of magic - Part 2 - Scott Logic Blog
The inconsistency was exactly the same as the one explored in this post, a constructor argument of type ConversionService was missing for a ......
Read more >
Spring Batch 5.0 Goes GA!
In this example, batchDataSource and batchTransactionManager refer to beans in the application context that are used to configure the job ...
Read more >
ConversionService (Spring Framework 6.0.2 API)
public interface ConversionService. A service interface for type conversion. This is the entry point into the convert system. Call convert(Object, Class) to ...
Read more >
Spring Boot with Redis conversion service and custom key ...
This article is all about Spring-boot and Redis integration with using ... Then we can use conversion service with a custom key converter ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found