For the record, {{java.util.Map}} does *not* extend {{java.util.Collection}}.
The root of the problem is that {{TypeUtils.getCollectionClass}} declares it returns a {{Class<? extends Collection>}}, but this the returned object may in fact be a {{Class<Map>}} that has been casted brutally, because{{TypeUtils.isCollectionClass}} returns true for {{Map.class}}:
{code} public static Class<? extends Collection> getCollectionClass(Type type) { return new TypeSwitch<Class<? extends Collection>>() { @Override @SuppressWarnings("unchecked") public Class<? extends Collection> caseClass(Class clazz) { // Here the condition is true for Map.class, which means the cast is abusive return isCollectionClass( clazz ) ? (Class<? extends Collection>) clazz : null; }
// ... redacted some code that is not relevant ...
}.doSwitch( type ); }
private static boolean isCollectionClass(Class<?> clazz) { return clazz == Collection.class || clazz == java.util.List.class || clazz == java.util.Set.class || clazz == java.util.Map.class || clazz == java.util.SortedSet.class // extension to the specs || clazz == java.util.SortedMap.class; // extension to the specs } {code}
From what I can see, the issue spread to those methods:
* {{org.hibernate.annotations.common.reflection.java.JavaXCollectionType.getCollectionClass()}} * {{org.hibernate.annotations.common.reflection.java.JavaXMember.getCollectionClass()}}
At runtime, this probably has little impact, especially because the weirdness is taken into account in all Hibernate code, but potentially this could lead to really strange behavior.
And, obviously, this makes client code harder to understand (why take Map.class into account when one is manipulating a {{Class<? extends Collection>}}?)
A trivial solution would be to remove the bound (use {{Class<?>}} instead of {{Class<? extends Collection>}}), but this would break client code. Maybe 6.0 would be a good time for that?
Also, using a different term than "Collection" (like "Container" or "MultiValued") may help to avoid that kind of issue in the future. But that would require an even bigger API break. |
|