@@ -49,17 +49,30 @@ public boolean canConvert(final Object src, final Class<?> dest) {
4949
5050 @ Override
5151 public boolean canConvert (final Class <?> src , final Type dest ) {
52- // OK if the existing object can be casted
53- return dest != null && Types .isAssignable (src , dest );
52+ // NB: You might think we want to use Types.isAssignable(src, dest)
53+ // directly here. And you might be right. However, assignment involving
54+ // generic types gets very tricky. If dest is e.g. a wildcard type such as
55+ // "? extends Object", or a type variable such as "C extends Object", then
56+ // no specific class will be assignable to it, because for that ? or C we
57+ // do not know anything about the bound type other than that it's something
58+ // that extends Object, so it could be anything, including things that
59+ // aren't assignable from whatever src is.
60+ //
61+ // Unfortunately, when this casting conversion code was originally written,
62+ // it did not have generics in mind, and calling code will pass in capture
63+ // types (e.g. Type objects gleaned via ModuleItem#getGenericType())
64+ // expecting them to be convertible as long as dest's raw type(s) are
65+ // compatible targets for src.
66+ //
67+ // And so for backwards compatibility, we continue to behave that way here.
68+
69+ return dest != null && //
70+ Types .raws (dest ).stream ().allMatch (c -> c .isAssignableFrom (src ));
5471 }
5572
5673 @ Override
5774 public boolean canConvert (final Class <?> src , final Class <?> dest ) {
58- // NB: Invert functional flow from Converter interface:
59- // Converter: canConvert(Class, Type) -> canConvert(Class, Class)
60- // becomes: canConvert(Class, Class) -> canConvert(Class, Type)
61- final Type destType = dest ;
62- return canConvert (src , destType );
75+ return dest != null && dest .isAssignableFrom (src );
6376 }
6477
6578 @ Override
0 commit comments