Skip to content
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

List-to-String conversion exception does not refer to element type [SPR-14971] #19537

Closed
spring-issuemaster opened this issue Dec 1, 2016 · 5 comments

Comments

@spring-issuemaster
Copy link
Collaborator

commented Dec 1, 2016

Luca Burgazzoli opened SPR-14971 and commented

I'm leveraging ConversionService to convert from different types and I found out an issue related to a conversion from a List of POJO to String.

The issue are:

  • the conversion services says that it can convert from List to String but then while converting elements it fails because FallbackObjectToStringConverter can convert only POJO with some characteristics (a String constructors or with some static methods) but then none of those methods is used as it invokes source.toString().
  • the exceptions says that it can't convert from List to String but it is not true as teh real cause is that it can't convert from POJO to String
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.util.Arrays$ArrayList<?>] to type [java.lang.String]
 at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:324)
 at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:206)
 at org.springframework.core.convert.support.CollectionToStringConverter.convert(CollectionToStringConverter.java:68)
 at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:36)
 ... 38 more

 

 

 


Affects: 4.2.8, 4.3.4

Reference URL: spring-projects/spring-framework-issues#142

Referenced from: commits 442d8a6, bcdda91, aef1460

Backported to: 4.2.9

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Dec 12, 2016

Jaro Kuruc commented

Hi Juergen, we have also observed a behaviour with possible room for an improvement. Let me describe our use case.

With our custom converter converting String to FooId (POJO value object representing integer based ID value), we can create @RequestMapping("/foos/{ids}") and require @PathVariable("ids") Collection<FooId> method param. Actual URI /foos/1,2 will then be correctly mapped to Collection<FooId>.

But then with the same converter in place, when we try to use UriTemplate and expand "/foos/{ids}" with Collection<FooId>, our converter is simply ignored.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Dec 12, 2016

Juergen Hoeller commented

As for the original report, a canConvert(List.class, String.class) call (or the like) will unfortunately return true simply because it cannot introspect the list contents and must leniently expect conversion to be possible, whereas a concrete convert call will have a look at the element type as well.

In general, there are no guarantees for a successful conversion attempt after a positive canConvert result. This is only designed as a precondition: If canConvert returns false, conversion is definitely not supported. And on the inverse, canConvert will never return false for a conversion that can be successful. It is therefore a way to rule out a convertible pair upfront but not a guarantee for a successful convert call. The only way to find out about actual success is to try the convert call and catch ConversionFailedException.

That said, there is definitely an issue here with our element type descriptor: Its ResolvableType refers to the collection still, which is the reason why the nested exception message mentions the collection type there. We're properly narrowing to the element type there now, fixing that part of the issue; to be backported to 4.3.5 and 4.2.9.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Dec 12, 2016

Juergen Hoeller commented

Jaro Kuruc, how specifically do you expand a Collection value with UriTemplate? Are you manually invoking the ConversionService there? The difference might be caused by MVC handler methods using a WebDataBinder (with a ConversionService inside but also BeanWrapper conversion rules on top). In any case, please create a separate JIRA issue for that part.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Dec 13, 2016

Luca Burgazzoli commented

I agree that canConvert may be lazy but then there is another issue while converting objects to string which is not clear to me: FallbackObjectToStringConverter will be invoked if no converters are found for the given collection element and it has a match condition which includes ObjectToObjectConverter.hasConversionMethodOrConstructor so it requires that an object to be convertible to a string needs to support the opposite operation (string --> object), is that correct ?

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Dec 13, 2016

Juergen Hoeller commented

Indeed, in trying to identify classes with proper conversion-like toString() output, we make assumptions about them being convertible from a String, e.g. having a String constructor or factory method, with toString() assumed to implement the inverse operation in such a scenario. Otherwise it's unclear whether we'd just get a non-overridden Object.toString() hash, which we do not consider a valid String "conversion" of the underlying value. In fact, without such checks, canConvert(X.class, String.class would always have to return true.

Of course, if you just need the output for logging purposes of the like, you can simply bypass the ConversionService completely and call List.toString() directly. Or if you'd like to find out about convertible elements upfront, you can call canConvert(MyElementType.class, String.class) (instead of or in addition to canConvert(List.class, String.class)) before trying to convert the list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.