From 90423a98b075a613b22bcb8e9ce7c61cb10e75a9 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 21 Jan 2025 19:15:20 +0100 Subject: [PATCH] Enforce match for resolved part of unresolvable target type Closes gh-34298 --- .../support/GenericConversionService.java | 5 +- .../GenericConversionServiceTests.java | 48 ++++++++++++++++++- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java b/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java index a662918b641..1fdd9f286e1 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java +++ b/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -341,8 +341,7 @@ public class GenericConversionService implements ConfigurableConversionService { } // Full check for complex generic type match required? ResolvableType rt = targetType.getResolvableType(); - if (!(rt.getType() instanceof Class) && !rt.isAssignableFrom(this.targetType) && - !this.targetType.hasUnresolvableGenerics()) { + if (!(rt.getType() instanceof Class) && !rt.isAssignableFromResolvedPart(this.targetType)) { return false; } return !(this.converter instanceof ConditionalConverter conditionalConverter) || diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java index 3faacdbfeb7..818bd021b9d 100644 --- a/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java +++ b/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -565,6 +565,22 @@ class GenericConversionServiceTests { assertThat(conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("integerCollection")))).isEqualTo(Collections.singleton("testX")); } + @Test + void stringListToListOfSubclassOfUnboundGenericClass() { + conversionService.addConverter(new StringListToAListConverter()); + conversionService.addConverter(new StringListToBListConverter()); + + List aList = (List) conversionService.convert(List.of("foo"), + TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)), + TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(ARaw.class))); + assertThat(aList).allMatch(e -> e instanceof ARaw); + + List bList = (List) conversionService.convert(List.of("foo"), + TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)), + TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(BRaw.class))); + assertThat(bList).allMatch(e -> e instanceof BRaw); + } + @ExampleAnnotation(active = true) public String annotatedString; @@ -742,6 +758,7 @@ class GenericConversionServiceTests { } } + private interface MyEnumBaseInterface { String getBaseCode(); } @@ -923,4 +940,33 @@ class GenericConversionServiceTests { return Color.decode(source.substring(0, 6)); } } + + + private static class GenericBaseClass { + } + + private static class ARaw extends GenericBaseClass { + } + + private static class BRaw extends GenericBaseClass { + } + + + private static class StringListToAListConverter implements Converter, List> { + + @Override + public List convert(List source) { + return List.of(new ARaw()); + } + } + + + private static class StringListToBListConverter implements Converter, List> { + + @Override + public List convert(List source) { + return List.of(new BRaw()); + } + } + }