-
Notifications
You must be signed in to change notification settings - Fork 38.6k
Description
Oleg Zhurakousky opened SPR-7488 and commented
We have the following scenario in Spring Integration. We are trying to extract MessageHeaders from the Message and map MessageHeaders as input parameter of the method that takes Properties type. SpEL uses ConversionService to convert MessageHeaders to Properties obviously trying to convert every element to a String. When it gets to $history header which is initially an empty ArrayList it attempts to convert it to a String.
When ArrayList is empty we get StackOverflowError. When ArrayList contains at least one element everything is fine.
First ConversionService finds the right Converter which is ObjectToCollectionConverter.
ObjectToCollectionConverter gets TypeDescriptor for target type and this is where things get really interesting.
TypeDescriptor attempts to resolve common type of the Collection via call to CollectionUtils.findCommonElementType(collection) which is based on looking at the first element and comparing it to every other element after that and if they all match that is the common type otherwise it will return 'null'. That explains why everything works when ArrayList contained at least one element. However in our case its empty so TypeDescriptor is making another attempt to extract the collection type by using GenericCollectionTypeResolver.getCollectionType() and that is where it gets fishy because the first line of code there is:
if (clazz.getName().startsWith("java.util.")) {
return null;
}
... which obviously results in null for our case and eventually results in elementType of this TypeDescriptor to be set to TypeDescriptor.NULL, which is then takes the actual type of the collection and makes it a target type via TypeDescriptor(object) where 'object' is the actual collection (instead of the its type or common type) thus resulting in the cycle causing StackOverflowError.
Questions:
- If target type is Properties should MapToMapConverter simply call toString() on every value? Although I personally disagree that toString() method should be used as default for conversion it is my understanding that it is currently the assumption of the ConversionService.
- Why GenericCollectionTypeResolver.getCollectionType() ignores java.util package?
I am attaching the test cases which reproduce all these plus few more minor issues in isolation.
Affects: 3.0.4
Attachments:
- StackOverflowExceptionTest.java (5.31 kB)
Issue Links:
- ConversionService.canConvert(..) is inconsistent with the behavior of ConversionService.convert(..) method. [SPR-7548] #12205 ConversionService.canConvert(..) is inconsistent with the behavior of ConversionService.convert(..) method.
Referenced from: commits 0a17e41