-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Fix LinkedTreeMap being used for non-Comparable keys #2152
base: main
Are you sure you want to change the base?
Changes from 6 commits
8e9f94e
0496128
3a308a9
ec3fc11
881d3cc
aaa1283
ebc4511
be5a780
f6fc354
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -257,6 +257,20 @@ public T construct() { | |
}; | ||
} | ||
|
||
private static boolean hasStringKeyType(Type mapType) { | ||
// If mapType is not parameterized, cannot assume that key is String, because if it | ||
// is not String and does not implement Comparable it would lead to a ClassCastException | ||
if (!(mapType instanceof ParameterizedType)) { | ||
return false; | ||
} | ||
Comment on lines
+280
to
+284
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would prevent There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is kind of a big change, isn't it? It seems to me that I see some other options. I think the whole situation is a bit of a mess to be honest, but here are some ways we might be able to clean it up a bit:
I suppose my underlying question is why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Below where this method I think the intended logic here is: The check below was previously (roughly): if (type instanceof ParameterizedType && !(String.class.isAssignableFrom(
TypeToken.get(((ParameterizedType) type).getActualTypeArguments()[0]).getRawType()))) {
...
} else {
return new LinkedTreeMap<>();
} For raw Therefore the changes by this PR actually reduce the cases where |
||
|
||
Type[] typeArguments = ((ParameterizedType) mapType).getActualTypeArguments(); | ||
if (typeArguments.length == 0) { | ||
return false; | ||
} | ||
return TypeToken.get(typeArguments[0]).getRawType() == String.class; | ||
} | ||
|
||
/** | ||
* Constructors for common interface types like Map and List and their | ||
* subtypes. | ||
|
@@ -320,17 +334,16 @@ private static <T> ObjectConstructor<T> newDefaultImplementationConstructor( | |
return (T) new TreeMap<>(); | ||
} | ||
}; | ||
} else if (type instanceof ParameterizedType && !(String.class.isAssignableFrom( | ||
TypeToken.get(((ParameterizedType) type).getActualTypeArguments()[0]).getRawType()))) { | ||
} else if (hasStringKeyType(type)) { | ||
return new ObjectConstructor<T>() { | ||
@Override public T construct() { | ||
return (T) new LinkedHashMap<>(); | ||
return (T) new LinkedTreeMap<>(); | ||
} | ||
}; | ||
} else { | ||
return new ObjectConstructor<T>() { | ||
@Override public T construct() { | ||
return (T) new LinkedTreeMap<>(); | ||
return (T) new LinkedHashMap<>(); | ||
} | ||
}; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this corresponds to what the logic did before, but I don't think it's correct in general. For example:
Could we maybe use
TypeToken
to tell whetherMap<String, ?>
is assignable frommapType
? It might need some adjustment to the logic for wildcards.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is what I mean with #2152 (comment) (unfortunately GitHub showed it as "outdated").
hasStringKeyType
is really only intended forMap
and not any subclasses, to determine whether aLinkedTreeMap
should be used. The issue that it is also called forMap
subtypes (as shown in your examples) is basically #1708, therefore I am not so keen to add any special logic here.