-
Notifications
You must be signed in to change notification settings - Fork 38.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
StackOverflowError, ClassCastException and other issues with ConversionService [SPR-7488] #12146
Comments
Juergen Hoeller commented Researching those failing tests at the moment... A couple of quick initial comments:
Juergen |
Juergen Hoeller commented Another note: The simpleClassCastException test performs an invalid call to the ConversionService... It passes in a List as a source value but then claims a source type descriptor for a String and a target type descriptor for the list! Switching the type descriptors to the correct order makes the test pass. So the best we can do there is to catch such invalid arguments upfront and to throw an IllegalArgumentException in that case. Juergen |
Juergen Hoeller commented In the failWithEmptyListOnSimpleConversion test, do you really mean to pass in a plain Object TypeDescriptor and a list as a target type here, with the source value being a list as well? conversionService.convert(list, TypeDescriptor.forObject(new Object()), TypeDescriptor.forObject(list)); In general, the source type descriptor should be as specific as possible a match with the given source value. Is this possibly an accident as well, with the TypeDescriptor arguments to be switched? Juergen |
Juergen Hoeller commented I've fixed this as per my analysis above: We're catching invalid arguments early now, and we're avoiding a stack overflow in the object-to-collection case even if the passed-in source object happens to be a collection as well (along with a source TypeDescriptor for Object). If there is anything I've missed, let me know. Juergen |
Oleg Zhurakousky commented Thanks Juergen Just a few quick once: As for failWithEmptyListOnSimpleConversion test; Of course i didn't mean to pass the Object. This test was meant to spare you from some digging as it is a by-product of the first (main) test (look at the comments in the first test) where having empty ArrayList resulted in CS treating it as an Object type. Anyway, thanks for acting on it quickly. |
Juergen Hoeller commented Alright, I eventually figured that this might be the end result of your experiments - in a mission to break the ConversionService :-) I originally thought that some of those tests where derived from actual use cases. I guess they were, but not in the shape that they ended up with here. Anyway, I think this should be all sorted now. Feel free to give the latest 3.0.5 snapshot a try... Juergen |
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:
... 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:
I am attaching the test cases which reproduce all these plus few more minor issues in isolation.
Affects: 3.0.4
Attachments:
Issue Links:
Referenced from: commits 0a17e41
The text was updated successfully, but these errors were encountered: