Browse Source

Avoid warn logging for custom converters using Collection.

If the collection type is not a store-native type, we no longer issue a warn log. Converters can be registered for List or Collection types and convert into a different, non-collection type while being a support converter instead of forcing a specific write type.

This is e.g. the case for MongoDB where a List of numbers is converted to the Vector type.

Closes #3306
pull/3307/head
Mark Paluch 8 months ago
parent
commit
3d08c10158
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 8
      src/main/java/org/springframework/data/convert/CustomConversions.java
  2. 39
      src/test/java/org/springframework/data/convert/CustomConversionsUnitTests.java

8
src/main/java/org/springframework/data/convert/CustomConversions.java

@ -70,7 +70,7 @@ import org.springframework.util.ObjectUtils; @@ -70,7 +70,7 @@ import org.springframework.util.ObjectUtils;
*/
public class CustomConversions {
private static final Log logger = LogFactory.getLog(CustomConversions.class);
private static Log logger = LogFactory.getLog(CustomConversions.class);
private static final String READ_CONVERTER_NOT_SIMPLE = "Registering converter from %s to %s as reading converter although it doesn't convert from a store-supported type; You might want to check your annotation setup at the converter implementation";
private static final String WRITE_CONVERTER_NOT_SIMPLE = "Registering converter from %s to %s as writing converter although it doesn't convert to a store-supported type; You might want to check your annotation setup at the converter implementation";
private static final String NOT_A_CONVERTER = "Converter %s is neither a Spring Converter, GenericConverter or ConverterFactory";
@ -324,7 +324,8 @@ public class CustomConversions { @@ -324,7 +324,8 @@ public class CustomConversions {
readingPairs.add(pair);
if (logger.isWarnEnabled() && !converterRegistration.isSimpleSourceType()) {
if (logger.isWarnEnabled() && !converterRegistration.isSimpleSourceType()
&& !Collection.class.isAssignableFrom(pair.getSourceType())) {
logger.warn(String.format(READ_CONVERTER_NOT_SIMPLE, pair.getSourceType(), pair.getTargetType()));
}
}
@ -334,7 +335,8 @@ public class CustomConversions { @@ -334,7 +335,8 @@ public class CustomConversions {
writingPairs.add(pair);
customSimpleTypes.add(pair.getSourceType());
if (logger.isWarnEnabled() && !converterRegistration.isSimpleTargetType()) {
if (logger.isWarnEnabled() && !converterRegistration.isSimpleTargetType()
&& !Collection.class.isAssignableFrom(pair.getTargetType())) {
logger.warn(String.format(WRITE_CONVERTER_NOT_SIMPLE, pair.getSourceType(), pair.getTargetType()));
}
}

39
src/test/java/org/springframework/data/convert/CustomConversionsUnitTests.java

@ -27,9 +27,11 @@ import java.util.Locale; @@ -27,9 +27,11 @@ import java.util.Locale;
import java.util.Map;
import java.util.function.Predicate;
import org.apache.commons.logging.Log;
import org.jmolecules.ddd.types.Association;
import org.jmolecules.ddd.types.Identifier;
import org.junit.jupiter.api.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
@ -44,6 +46,7 @@ import org.springframework.data.convert.Jsr310Converters.LocalDateTimeToDateConv @@ -44,6 +46,7 @@ import org.springframework.data.convert.Jsr310Converters.LocalDateTimeToDateConv
import org.springframework.data.geo.Point;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.test.util.ReflectionTestUtils;
/**
* Unit tests for {@link CustomConversions}.
@ -156,8 +159,7 @@ class CustomConversionsUnitTests { @@ -156,8 +159,7 @@ class CustomConversionsUnitTests {
var conversions = StoreConversions.of(new SimpleTypeHolder(Collections.singleton(Format.class), true));
var customConversions = new CustomConversions(conversions,
Collections.singletonList(new FormatConverterFactory()));
var customConversions = new CustomConversions(conversions, Collections.singletonList(new FormatConverterFactory()));
assertThat(customConversions.getCustomWriteTarget(String.class, SimpleDateFormat.class)).isPresent();
}
@ -214,7 +216,7 @@ class CustomConversionsUnitTests { @@ -214,7 +216,7 @@ class CustomConversionsUnitTests {
new CustomConversions(StoreConversions.of(DATE_EXCLUDING_SIMPLE_TYPE_HOLDER),
Collections.singletonList(Jsr310Converters.LocalDateTimeToInstantConverter.INSTANCE))
.registerConvertersIn(registry);
.registerConvertersIn(registry);
verify(registry).addConverter(any(Jsr310Converters.LocalDateTimeToInstantConverter.class));
}
@ -293,8 +295,8 @@ class CustomConversionsUnitTests { @@ -293,8 +295,8 @@ class CustomConversionsUnitTests {
@Test
void hasValueConverterReturnsFalseWhenNoPropertyValueConversionsAreConfigured() {
ConverterConfiguration configuration = new ConverterConfiguration(StoreConversions.NONE,
Collections.emptyList(), it -> true, null);
ConverterConfiguration configuration = new ConverterConfiguration(StoreConversions.NONE, Collections.emptyList(),
it -> true, null);
CustomConversions conversions = new CustomConversions(configuration);
@ -315,8 +317,8 @@ class CustomConversionsUnitTests { @@ -315,8 +317,8 @@ class CustomConversionsUnitTests {
doReturn(true).when(mockPropertyValueConversions).hasValueConverter(eq(mockProperty));
ConverterConfiguration configuration = new ConverterConfiguration(StoreConversions.NONE,
Collections.emptyList(), it -> true, mockPropertyValueConversions);
ConverterConfiguration configuration = new ConverterConfiguration(StoreConversions.NONE, Collections.emptyList(),
it -> true, mockPropertyValueConversions);
CustomConversions conversions = new CustomConversions(configuration);
@ -328,6 +330,19 @@ class CustomConversionsUnitTests { @@ -328,6 +330,19 @@ class CustomConversionsUnitTests {
verifyNoInteractions(mockProperty);
}
@Test // GH-3306
void doesNotWarnForAsymmetricListConverter() {
Log actualLogger = (Log) ReflectionTestUtils.getField(CustomConversions.class, "logger");
Log actualLoggerSpy = spy(actualLogger);
ReflectionTestUtils.setField(CustomConversions.class, "logger", actualLoggerSpy, Log.class);
new CustomConversions(StoreConversions.NONE, List.of(ListOfNumberToStringConverter.INSTANCE));
verify(actualLoggerSpy, never()).warn(anyString());
verify(actualLoggerSpy, never()).warn(anyString(), any());
}
private static Class<?> createProxyTypeFor(Class<?> type) {
var factory = new ProxyFactory();
@ -337,6 +352,16 @@ class CustomConversionsUnitTests { @@ -337,6 +352,16 @@ class CustomConversionsUnitTests {
return factory.getProxy().getClass();
}
@ReadingConverter
enum ListOfNumberToStringConverter implements Converter<List<Number>, String> {
INSTANCE;
public String convert(List<Number> source) {
return source.toString();
}
}
enum FormatToStringConverter implements Converter<Format, String> {
INSTANCE;

Loading…
Cancel
Save