Skip to content

Fixed resolving generic types for vavr maps. #2517

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

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
* @author Oliver Gierke
* @author Mark Paluch
* @author Christoph Strobl
* @author Jürgen Diez
*/
class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T> {

Expand Down Expand Up @@ -67,7 +68,7 @@ public ParameterizedTypeInformation(ParameterizedType type, TypeDiscoverer<?> pa
@Nullable
protected TypeInformation<?> doGetMapValueType() {

if (Map.class.isAssignableFrom(getType())) {
if (isMap()) {

Type[] arguments = type.getActualTypeArguments();

Expand Down Expand Up @@ -157,13 +158,13 @@ public boolean isAssignableFrom(TypeInformation<?> target) {
@Nullable
protected TypeInformation<?> doGetComponentType() {

boolean isCustomMapImplementation = isMap() && !getType().equals(Map.class);
boolean isCustomMapImplementation = isMap() && !isMapBaseType();

if (isCustomMapImplementation) {
return getRequiredSuperTypeInformation(Map.class).getComponentType();
return getRequiredSuperTypeInformation(getMapBaseType()).getComponentType();
}

return createInfo(type.getActualTypeArguments()[0]);
return createInfo(this.type.getActualTypeArguments()[0]);
}

/*
Expand Down
28 changes: 25 additions & 3 deletions src/main/java/org/springframework/data/util/TypeDiscoverer.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,11 @@
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
* @author Jürgen Diez
*/
class TypeDiscoverer<S> implements TypeInformation<S> {

private static final Class<?>[] MAP_TYPES;
protected static final Class<?>[] MAP_TYPES;

static {

Expand Down Expand Up @@ -355,7 +356,7 @@ public TypeInformation<?> getMapValueType() {

@Nullable
protected TypeInformation<?> doGetMapValueType() {
return isMap() ? getTypeArgument(getBaseType(MAP_TYPES), 1)
return isMap() ? getTypeArgument(getMapBaseType(), 1)
: getTypeArguments().stream().skip(1).findFirst().orElse(null);
}

Expand Down Expand Up @@ -392,7 +393,7 @@ protected TypeInformation<?> doGetComponentType() {
}

if (isMap()) {
return getTypeArgument(getBaseType(MAP_TYPES), 0);
return getTypeArgument(getMapBaseType(), 0);
}

if (Iterable.class.isAssignableFrom(rawType)) {
Expand Down Expand Up @@ -527,6 +528,27 @@ private TypeInformation<?> getTypeArgument(Class<?> bound, int index) {
: null;
}

protected boolean isMapBaseType() {
return isBaseType(MAP_TYPES);
}

private boolean isBaseType(Class<?>[] candidates) {

Class<S> type = getType();

for (Class<?> candidate: candidates) {
if (candidate.equals(type)) {
return true;
}
}

return false;
}

protected Class<?> getMapBaseType() {
return getBaseType(MAP_TYPES);
}

private Class<?> getBaseType(Class<?>[] candidates) {

Class<S> type = getType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
*
* @author Oliver Gierke
* @author Mark Paluch
* @author Jürgen Diez
*/
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
Expand Down Expand Up @@ -76,22 +77,39 @@ void considersTypeInformationsWithSameParentsNotEqual() {
}

@Test // DATACMNS-88
void resolvesMapValueTypeCorrectly() {
void resolvesMapTypesCorrectly() {

TypeInformation<Foo> type = ClassTypeInformation.from(Foo.class);
TypeInformation<?> propertyType = type.getProperty("param");
TypeInformation<?> value = propertyType.getProperty("value");

assertThat(propertyType.getComponentType().getType()).isEqualTo(Locale.class);
assertThat(value.getType()).isEqualTo(String.class);
assertThat(propertyType.getMapValueType().getType()).isEqualTo(String.class);

propertyType = type.getProperty("param2");
value = propertyType.getProperty("value");

assertThat(propertyType.getComponentType().getType()).isEqualTo(String.class);
assertThat(value.getType()).isEqualTo(String.class);
assertThat(propertyType.getMapValueType().getType()).isEqualTo(Locale.class);
}

@Test
void resolvesVavrMapTypesCorrectly() {

TypeInformation<VavrFoo> type = ClassTypeInformation.from(VavrFoo.class);
TypeInformation<?> propertyType = type.getProperty("param");

assertThat(propertyType.getComponentType().getType()).isEqualTo(Locale.class);
assertThat(propertyType.getMapValueType().getType()).isEqualTo(String.class);

propertyType = type.getProperty("param2");

assertThat(propertyType.getComponentType().getType()).isEqualTo(String.class);
assertThat(propertyType.getMapValueType().getType()).isEqualTo(Locale.class);
}

@Test // DATACMNS-446
void createsToStringRepresentation() {

Expand Down Expand Up @@ -170,6 +188,11 @@ class Foo {
Localized2<String> param2;
}

class VavrFoo {
io.vavr.collection.HashMap<Locale, String> param;
io.vavr.collection.HashMap<String, Locale> param2;
}

class Bar {
List<String> param;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
* Unit tests for {@link TypeDiscoverer}.
*
* @author Oliver Gierke
* @author Jürgen Diez
*/
@ExtendWith(MockitoExtension.class)
public class TypeDiscovererUnitTests {
Expand Down Expand Up @@ -179,6 +180,23 @@ void detectsSubTypes() {
assertThat(type.isSubTypeOf(String.class)).isFalse();
}

@Test
void considerVavrMapToBeAMap() {

TypeInformation<io.vavr.collection.Map> type = from(io.vavr.collection.Map.class);

assertThat(type.isMap()).isTrue();
}

@Test
void returnsComponentAndValueTypesForVavrMapExtensions() {

TypeInformation<?> discoverer = new TypeDiscoverer<>(CustomVavrMap.class, EMPTY_MAP);

assertThat(discoverer.getMapValueType().getType()).isEqualTo(Locale.class);
assertThat(discoverer.getComponentType().getType()).isEqualTo(String.class);
}

class Person {

Addresses addresses;
Expand Down Expand Up @@ -228,4 +246,7 @@ public Iterator<String> iterator() {
return Collections.emptyIterator();
}
}

interface CustomVavrMap extends io.vavr.collection.Map<String, Locale> {
}
}