From 85e257fc82d7368facc76df0d84698a2f60a8e46 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Wed, 28 Aug 2019 10:04:29 +0200 Subject: [PATCH] DATACMNS-1571 - Fixed specialization in ParameterizedTypeInformation. DATACMNS-783 introduced code to specialize a raw type containing generics with the type information from it's context so that it can be established if only the raw type has been e.g. stored as type hint in a store (SomeType stored as SomeType and T needing to be reestablished from the context). That application of the context unfortunately did not consider that the raw type might carry generics information itself, like `SomeType extends Foo`. We've now changed the specialization algorithm so that the the target type is being looked at in the context of the type used for the assignment (e.g. `Foo foo`). If that assignment fully resolves the declared type, we just outright use the given type as it by definition carries all generics information plus better type information in the first place. If the type to specialize on is only partially expanding the generics we now create a synthetic type to merge the generics information. I.e. a `SomeType extends Foo` stored as SomeType would still resolve ID to Integer but capture T from the context including all potentially declared bounds. Related tickets: DATACMNS-783, DATACMNS-1138. --- .../data/util/ParameterizedTypeInformation.java | 15 ++++++++++++++- .../springframework/data/util/TypeDiscoverer.java | 10 ++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/springframework/data/util/ParameterizedTypeInformation.java b/src/main/java/org/springframework/data/util/ParameterizedTypeInformation.java index 762d567ef..8c6f62908 100644 --- a/src/main/java/org/springframework/data/util/ParameterizedTypeInformation.java +++ b/src/main/java/org/springframework/data/util/ParameterizedTypeInformation.java @@ -166,7 +166,20 @@ class ParameterizedTypeInformation extends ParentTypeAwareTypeInformation @Override @SuppressWarnings("unchecked") public TypeInformation specialize(ClassTypeInformation type) { - return isResolvedCompletely() ? (TypeInformation) type : super.specialize(type); + + if (isResolvedCompletely()) { + return (TypeInformation) type; + } + + TypeInformation asSupertype = type.getSuperTypeInformation(getType()); + + if (asSupertype == null || !ParameterizedTypeInformation.class.isInstance(asSupertype)) { + return super.specialize(type); + } + + return ((ParameterizedTypeInformation) asSupertype).isResolvedCompletely() // + ? (TypeInformation) type // + : super.specialize(type); } /* diff --git a/src/main/java/org/springframework/data/util/TypeDiscoverer.java b/src/main/java/org/springframework/data/util/TypeDiscoverer.java index aad143b30..8ef54480a 100644 --- a/src/main/java/org/springframework/data/util/TypeDiscoverer.java +++ b/src/main/java/org/springframework/data/util/TypeDiscoverer.java @@ -485,13 +485,15 @@ class TypeDiscoverer implements TypeInformation { @SuppressWarnings("unchecked") public TypeInformation specialize(ClassTypeInformation type) { + Assert.notNull(type, "Type must not be null!"); Assert.isTrue(getType().isAssignableFrom(type.getType()), - String.format("%s must be assignable from %s", getType(), type.getType())); + () -> String.format("%s must be assignable from %s", getType(), type.getType())); - List> arguments = getTypeArguments(); + List> typeArguments = getTypeArguments(); - return (TypeInformation) (arguments.isEmpty() ? type - : createInfo(new SyntheticParamterizedType(type, arguments))); + return (TypeInformation) (typeArguments.isEmpty() // + ? type // + : type.createInfo(new SyntheticParamterizedType(type, getTypeArguments()))); } @Nullable