@@ -39,6 +39,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @author Jürgen Diez
|
||||
*/
|
||||
class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T> {
|
||||
|
||||
@@ -63,7 +64,7 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
|
||||
@Nullable
|
||||
protected TypeInformation<?> doGetMapValueType() {
|
||||
|
||||
if (Map.class.isAssignableFrom(getType())) {
|
||||
if (isMap()) {
|
||||
|
||||
var arguments = type.getActualTypeArguments();
|
||||
|
||||
@@ -141,13 +142,13 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
|
||||
@Nullable
|
||||
protected TypeInformation<?> doGetComponentType() {
|
||||
|
||||
var isCustomMapImplementation = isMap() && !getType().equals(Map.class);
|
||||
var 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]);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -45,7 +45,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
|
||||
private static final Class<?>[] MAP_TYPES;
|
||||
protected static final Class<?>[] MAP_TYPES;
|
||||
private static final Class<?>[] COLLECTION_TYPES;
|
||||
|
||||
static {
|
||||
@@ -328,7 +328,7 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
|
||||
@Nullable
|
||||
protected TypeInformation<?> doGetMapValueType() {
|
||||
return isMap() ? getTypeArgument(getBaseType(MAP_TYPES), 1)
|
||||
return isMap() ? getTypeArgument(getMapBaseType(), 1)
|
||||
: getTypeArguments().stream().skip(1).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
@@ -357,7 +357,7 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
}
|
||||
|
||||
if (isMap()) {
|
||||
return getTypeArgument(getBaseType(MAP_TYPES), 0);
|
||||
return getTypeArgument(getMapBaseType(), 0);
|
||||
}
|
||||
|
||||
if (Iterable.class.isAssignableFrom(rawType)) {
|
||||
@@ -469,6 +469,27 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
: 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) {
|
||||
|
||||
var type = getType();
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.mockito.quality.Strictness;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
* @author Jürgen Diez
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
@@ -76,22 +77,39 @@ class ParameterizedTypeInformationUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATACMNS-88
|
||||
void resolvesMapValueTypeCorrectly() {
|
||||
void resolvesMapTypesCorrectly() {
|
||||
|
||||
TypeInformation<Foo> type = ClassTypeInformation.from(Foo.class);
|
||||
var propertyType = type.getProperty("param");
|
||||
var 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() {
|
||||
|
||||
@@ -170,6 +188,11 @@ class ParameterizedTypeInformationUnitTests {
|
||||
Localized2<String> param2;
|
||||
}
|
||||
|
||||
class VavrFoo {
|
||||
io.vavr.collection.HashMap<Locale, String> param;
|
||||
io.vavr.collection.HashMap<String, Locale> param2;
|
||||
}
|
||||
|
||||
class Bar {
|
||||
List<String> param;
|
||||
}
|
||||
|
||||
@@ -187,6 +187,15 @@ public class TypeDiscovererUnitTests {
|
||||
assertThat(type.isMap()).isTrue();
|
||||
}
|
||||
|
||||
@Test // #2517
|
||||
void returnsComponentAndValueTypesForVavrMapExtensions() {
|
||||
|
||||
var discoverer = new TypeDiscoverer<>(CustomVavrMap.class, EMPTY_MAP);
|
||||
|
||||
assertThat(discoverer.getMapValueType().getType()).isEqualTo(Locale.class);
|
||||
assertThat(discoverer.getComponentType().getType()).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
@Test // #2511
|
||||
void considerVavrSetToBeCollectionLike() {
|
||||
|
||||
@@ -260,4 +269,6 @@ public class TypeDiscovererUnitTests {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
}
|
||||
|
||||
interface CustomVavrMap extends io.vavr.collection.Map<String, Locale> {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user