Reputation: 683
I'm using Spring Boot 1.5.10 and have a problem with my custom converters.
I'm defining multiple converters with target type Optional Something like this:
@Component
public class StringToSomeTypeConverter implements Converter<String, Optional<SomeType>> { ... }
@Component
public class StringToOtherTypeConverter implements Converter<String, Optional<OtherType>> { ... }
My problem is that there is apparently only one converter registered for the type Optional. So at runtime only one Converter gets called in all my Controllers. No matter the generic target type. (SomeType
or OtherType
in the example)
I did some digging and the converter is chosen in GenericConversionService#getConverter
.
The method takes TypeDescriptor targetType
as argument and constructs a ConverterCacheKey
from sourceType
and targetType
.
Sadly TypeDescriptor#equals
only compares getType()
(Optional) and not resolvableType
(SomeType
or OtherType
in our example).
This explains why only one Converter gets picked up.
Is there any way to make Spring aware of the ResolvableType
so I can use Optional as my target type for multiple Converters?
Upvotes: 2
Views: 2638
Reputation: 1162
I can not tell for sure what is going on, but having browsed Spring MVC source code many times I guess the problem would be in some code that is iterating thorugh registered Converters and checking if they can convert, so the target type would be Optional(not Optional< Class < Integer > >, but Optional), if you run this code:
Optional<Class<String>> ops = Optional.of(String.class);
Optional<Class<Integer>> ops2 = Optional.of(Integer.class);
System.out.println(ops2.getClass().equals(ops.getClass()));
You will see on the console, it prints true, meaning, they are considered as the same datatype !! so if Spring truly iterates through the list of converters, it makes sense that hte first one is always called, because it can handle all Optional objects no matter what, my suggestion would be:
Update: If you are interested in debugging that at Spring framework you have to place a breakpoint on methods from the ConversionService interface, it is the service that manages the conversions, at least this is how it works in Spring Core, and you will should see the execution flow and at one moment in time is checking which converter is suitable and if some of them implements ConditionalConverter, look at one of the core methods of this process yourself at: https://github.com/spring-projects/spring-framework/blob/master/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java#L560
Upvotes: 3