Skip to content
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

GenericConversionService selects incorrect converter for String to List<String> conversion #34685

Open
dmitrysulman opened this issue Mar 29, 2025 · 1 comment · May be fixed by #34697
Open
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: waiting-for-triage An issue we've not yet triaged or decided on

Comments

@dmitrysulman
Copy link
Contributor

dmitrysulman commented Mar 29, 2025

This issue is related to #34535 and #34298.

Converter<String, List<? extends Map<String, ?>>> is incorrectly selected when converting a String to a List<String>.

The following reproducer test fails on all 6.2.x versions except 6.2.3:

package com.example;

import org.junit.jupiter.api.Test;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.core.convert.support.StringToCollectionConverter;

import java.util.List;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

class GenericConversionServiceTests {

	private final GenericConversionService conversionService = new GenericConversionService();

	@Test
	@SuppressWarnings("unchecked")
	void stringToListOfString() {
		conversionService.addConverter(new StringToCollectionConverter(conversionService));
		conversionService.addConverter(new StringToListOfMapConverter());

		List<String> result = (List<String>) conversionService.convert("foo,bar",
				TypeDescriptor.valueOf(String.class),
				TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class))
		);

		assertThat(result.get(0)).isEqualTo("foo");
	}

	private static class StringToListOfMapConverter implements Converter<String, List<? extends Map<String, ?>>> {

		@Override
		public List<? extends Map<String, ?>> convert(String source) {
			return List.of(Map.of("bar", source));
		}
	}

	// Using this version of the converter also results in a failure
	private static class StringToListOfMapConverterWithoutWildcard implements Converter<String, List<Map<String, ?>>> {

		@Override
		public List<Map<String, ?>> convert(String source) {
			return List.of(Map.of("bar", source));
		}
	}
}

The exception shows that the StringToListOfMapConverter converter was chosen instead of expected StringToCollectionConverter:

class java.util.ImmutableCollections$Map1 cannot be cast to class java.lang.String (java.util.ImmutableCollections$Map1 and java.lang.String are in module java.base of loader 'bootstrap')
java.lang.ClassCastException: class java.util.ImmutableCollections$Map1 cannot be cast to class java.lang.String (java.util.ImmutableCollections$Map1 and java.lang.String are in module java.base of loader 'bootstrap')
	at org.springframework.core.convert.support.GenericConversionServiceTests.stringToListOfString(GenericConversionServiceTests.java:28)
	at java.base/java.lang.reflect.Method.invoke(Method.java:565)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Mar 29, 2025
@belljun3395
Copy link

belljun3395 commented Mar 30, 2025

I think adding a few more conditions in GenericConversionService#getRegisteredConverter ConverterAdapter#matchesFallback could fix the issue.

If this is something that needs to be fixed, do you mind if I try to fix it?

@jhoeller jhoeller added the in: core Issues in core modules (aop, beans, core, context, expression) label Apr 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: waiting-for-triage An issue we've not yet triaged or decided on
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants