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
TypeAs.UNWRAP_MAP_VALUE_OF and UNWRAP_MAP_KEY_OF return wrong results for multimaps #341
Comments
xRodney
added a commit
to xRodney/sundrio
that referenced
this issue
Oct 7, 2022
…ong results for multimaps (& other more complicated generic references) Fixes sundrio#341 This PR adds a new reusable routine `TypeCast`, which is used to investigate type relations with respect to generic arguments (like improved `isInstanceOf`). `TypeCast` is then used by three new utility methods to `Collections`: `getCollectionElementType`, `getMapKeyType` and `getMapValueType`. These are similar to `TypeAs.UNWRAP_MAP_VALUE_OF` & friends, but return `Optional.empty()` when the supplied type is not a Collection / Map (as opposed to the supplied type itself). In fact, the `UNWRAP_*` functions now delegate to `Collections` and therefore now return more accurate results. Last but not least, I have identified a new public routine `TypeArguments.getGenericArgumentsMappings(ClassRef ref, TypeDef definition)`. This creates a mapping from generic types on a TypeDef to their instantiation on ClassRef. This code has been used at multiple places both in sundrio, but also in kubernetes-client. So I think it deserves a common implementation.
xRodney
added a commit
to xRodney/sundrio
that referenced
this issue
Oct 8, 2022
…ong results for multimaps (& other more complicated generic references) Fixes sundrio#341 This PR adds a new reusable routine `TypeCast`, which is used to investigate type relations with respect to generic arguments (like improved `isInstanceOf`). `TypeCast` is then used by three new utility methods to `Collections`: `getCollectionElementType`, `getMapKeyType` and `getMapValueType`. These are similar to `TypeAs.UNWRAP_MAP_VALUE_OF` & friends, but return `Optional.empty()` when the supplied type is not a Collection / Map (as opposed to the supplied type itself). In fact, the `UNWRAP_*` functions now delegate to `Collections` and therefore now return more accurate results. Last but not least, I have identified a new public routine `TypeArguments.getGenericArgumentsMappings(ClassRef ref, TypeDef definition)`. This creates a mapping from generic types on a TypeDef to their instantiation on ClassRef. This code has been used at multiple places both in sundrio, but also in kubernetes-client. So I think it deserves a common implementation.
iocanel
pushed a commit
to xRodney/sundrio
that referenced
this issue
Oct 8, 2022
…ong results for multimaps (& other more complicated generic references) Fixes sundrio#341 This PR adds a new reusable routine `TypeCast`, which is used to investigate type relations with respect to generic arguments (like improved `isInstanceOf`). `TypeCast` is then used by three new utility methods to `Collections`: `getCollectionElementType`, `getMapKeyType` and `getMapValueType`. These are similar to `TypeAs.UNWRAP_MAP_VALUE_OF` & friends, but return `Optional.empty()` when the supplied type is not a Collection / Map (as opposed to the supplied type itself). In fact, the `UNWRAP_*` functions now delegate to `Collections` and therefore now return more accurate results. Last but not least, I have identified a new public routine `TypeArguments.getGenericArgumentsMappings(ClassRef ref, TypeDef definition)`. This creates a mapping from generic types on a TypeDef to their instantiation on ClassRef. This code has been used at multiple places both in sundrio, but also in kubernetes-client. So I think it deserves a common implementation.
iocanel
pushed a commit
that referenced
this issue
Oct 14, 2022
…ong results for multimaps (& other more complicated generic references) Fixes #341 This PR adds a new reusable routine `TypeCast`, which is used to investigate type relations with respect to generic arguments (like improved `isInstanceOf`). `TypeCast` is then used by three new utility methods to `Collections`: `getCollectionElementType`, `getMapKeyType` and `getMapValueType`. These are similar to `TypeAs.UNWRAP_MAP_VALUE_OF` & friends, but return `Optional.empty()` when the supplied type is not a Collection / Map (as opposed to the supplied type itself). In fact, the `UNWRAP_*` functions now delegate to `Collections` and therefore now return more accurate results. Last but not least, I have identified a new public routine `TypeArguments.getGenericArgumentsMappings(ClassRef ref, TypeDef definition)`. This creates a mapping from generic types on a TypeDef to their instantiation on ClassRef. This code has been used at multiple places both in sundrio, but also in kubernetes-client. So I think it deserves a common implementation.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello again,
as a follow up to #333, I would like to address the issue that generic arguments on non-trivial Maps and Collections are not resolved correctly.
I come across this issue while working on kubernetes-client/crd-generator, using keycloak-operator as a sample operator.
In Keycloak, they have a class similar to the following:
(ref https://github.com/keycloak/keycloak/blob/main/common/src/main/java/org/keycloak/common/util/MultivaluedHashMap.java)
The class is then used like this:
(ref https://github.com/keycloak/keycloak/blob/main/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java#L189)
The reference
MultivaluedHashMap<String, ComponentExportRepresentation>
is correctly recognized as a Map by sundrio, but then it is investivated for its key and value parameters.For this, two routines from
io.sundr.builder.internal.functions.TypeAs
are used:UNWRAP_MAP_KEY_OF
andUNWRAP_MAP_VALUE_OF
.The key is correctly recognized as
String
, but the value isComponentExportRepresentation
. In other words, the reference is treated asMap<String, ComponentExportRepresentation>
. But the correct type should beMap<String, List<ComponentExportRepresentation>>
.If we look closer into the routines in
TypeAs
, we can see that they both delegate to a common implementation:(ref https://github.com/sundrio/sundrio/blob/main/annotations/builder/src/main/java/io/sundr/builder/internal/functions/TypeAs.java#L225)
We can see that this implementation is really basic (although, I believe, it is correct in 99% real world scenarios :D ).
The
typeCheckFn
returns true if the type id or subclassesMap
. So forMultivaluedHashMap
it returns true.It then assumes that either we are investigating the map directly (or a subclass that has exactly the same type arguments), or we reference a subclass that has all arguments specified (like
class StringMap implements Map<String,String>
).Our
MultivaluedHashMap
falls into the first category, as it has enough arguments. The actual relation of these arguments to theMap
interface is never investigated.Other examples that for which the implementation would also yield bad results:
interface StringKeyedMap<V> extends Map<String,V>
interface SwappedArguments<V,K> extends Map<K,V>
interface MoreArguments<X,K,V> extends Map<K,V>
interface OptionalMap<K,V> extends Map<K, Optional<V>>
Yes, most of these are corner cases, which should never appear in a production code, and righfully so.
But as I wrote earlier, I stubled across that 1% of legitimate cases for which the algorithm should work.
This has been tested on the latest main, which is 0.93-SNAPSHOT.
I believe I may have a fix for that, I will be opening a PR shortly.
The text was updated successfully, but these errors were encountered: