Skip to content

Commit 0034d7d

Browse files
committed
Add sourceType to canConvert and convert
1 parent b560cff commit 0034d7d

File tree

9 files changed

+45
-37
lines changed

9 files changed

+45
-37
lines changed

junit-jupiter-params/src/main/java/org/junit/jupiter/params/aggregator/DefaultArgumentsAccessor.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public static DefaultArgumentsAccessor create(ExtensionContext context, int invo
4747
Preconditions.notNull(classLoader, "ClassLoader must not be null");
4848

4949
BiFunction<Object, Class<?>, Object> converter = (source, targetType) -> new DefaultArgumentConverter(context) //
50-
.convert(source, TypeDescriptor.forType(targetType), classLoader);
50+
.convert(source, TypeDescriptor.forClass(targetType), classLoader);
5151
return new DefaultArgumentsAccessor(converter, invocationIndex, arguments);
5252
}
5353

junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionSupport.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ private ConversionSupport() {
5454
@Deprecated
5555
@API(status = DEPRECATED, since = "5.13")
5656
public static <T> T convert(String source, Class<T> targetType, ClassLoader classLoader) {
57-
return convert(source, TypeDescriptor.forType(targetType), getClassLoader(classLoader));
57+
return convert(source, TypeDescriptor.forClass(targetType), getClassLoader(classLoader));
5858
}
5959

6060
/**
@@ -76,18 +76,19 @@ public static <T> T convert(String source, Class<T> targetType, ClassLoader clas
7676
@API(status = EXPERIMENTAL, since = "1.13")
7777
@SuppressWarnings("unchecked")
7878
public static <T> T convert(Object source, TypeDescriptor targetType, ClassLoader classLoader) {
79+
TypeDescriptor sourceType = TypeDescriptor.forInstance(source);
7980
ClassLoader classLoaderToUse = getClassLoader(classLoader);
8081
ServiceLoader<Converter> serviceLoader = ServiceLoader.load(Converter.class, classLoaderToUse);
8182

8283
Converter converter = Stream.concat( //
8384
StreamSupport.stream(serviceLoader.spliterator(), false), //
8485
Stream.of(DefaultConverter.INSTANCE)) //
85-
.filter(candidate -> candidate.canConvert(source, targetType)) //
86+
.filter(candidate -> candidate.canConvert(source, sourceType, targetType)) //
8687
.findFirst() //
8788
.orElseThrow(() -> new ConversionException("No registered or built-in converter for source '" + source
8889
+ "' and target type " + targetType.getType().getTypeName()));
8990

90-
return (T) converter.convert(source, targetType, classLoaderToUse);
91+
return (T) converter.convert(source, sourceType, targetType, classLoaderToUse);
9192
}
9293

9394
private static ClassLoader getClassLoader(ClassLoader classLoader) {

junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/Converter.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -41,28 +41,30 @@ public interface Converter {
4141
*
4242
* @param source the source object to convert; may be {@code null} but only
4343
* if the target type is a reference type
44+
* @param sourceType the descriptor of the source type; never {@code null}
4445
* @param targetType the descriptor of the type the source should be converted into;
4546
* never {@code null}
4647
* @return {@code true} if the supplied source can be converted
4748
*/
48-
boolean canConvert(Object source, TypeDescriptor targetType);
49+
boolean canConvert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
4950

5051
/**
5152
* Convert the supplied source object into an instance of the specified
5253
* target type.
53-
*
54-
* <p>This method will only be invoked if {@link #canConvert(Object, TypeDescriptor)}
54+
* <p>This method will only be invoked if {@link #canConvert(Object, TypeDescriptor, TypeDescriptor)}
5555
* returned {@code true} for the same target type.
5656
*
5757
* @param source the source object to convert; may be {@code null} but only
5858
* if the target type is a reference type
59+
* @param sourceType the descriptor of the source type; never {@code null}
5960
* @param targetType the descriptor of the type the source should be converted into;
6061
* never {@code null}
6162
* @param classLoader the {@code ClassLoader} to use; never {@code null}
6263
* @return the converted object; may be {@code null} but only if the target
6364
* type is a reference type
6465
* @throws ConversionException if an error occurs during the conversion
6566
*/
66-
Object convert(Object source, TypeDescriptor targetType, ClassLoader classLoader) throws ConversionException;
67+
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType, ClassLoader classLoader)
68+
throws ConversionException;
6769

6870
}

junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/DefaultConverter.java

+5-9
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,13 @@ private DefaultConverter() {
7070
*
7171
* @param source the source object to convert; may be {@code null} but only
7272
* if the target type is a reference type
73+
* @param sourceType the descriptor of the source type; never {@code null}
7374
* @param targetType the target type the source should be converted into;
7475
* never {@code null}
7576
* @return {@code true} if the supplied source can be converted
7677
*/
7778
@Override
78-
public boolean canConvert(Object source, TypeDescriptor targetType) {
79+
public boolean canConvert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
7980
if (source == null) {
8081
return !targetType.isPrimitive();
8182
}
@@ -95,14 +96,11 @@ public boolean canConvert(Object source, TypeDescriptor targetType) {
9596
/**
9697
* Convert the supplied source object into an instance of the specified
9798
* target type.
98-
*
9999
* <p>If the target type is {@code String}, the source {@code String} will not
100100
* be modified.
101-
*
102101
* <p>Some forms of conversion require a {@link ClassLoader}. If none is
103102
* provided, the {@linkplain ClassLoaderUtils#getDefaultClassLoader() default
104103
* ClassLoader} will be used.
105-
*
106104
* <p>This method is able to convert strings into primitive types and their
107105
* corresponding wrapper types ({@link Boolean}, {@link Character}, {@link Byte},
108106
* {@link Short}, {@link Integer}, {@link Long}, {@link Float}, and
@@ -112,29 +110,26 @@ public boolean canConvert(Object source, TypeDescriptor targetType) {
112110
* {@link java.math.BigDecimal}, {@link java.math.BigInteger},
113111
* {@link java.util.Currency}, {@link java.util.Locale}, {@link java.util.UUID},
114112
* {@link java.net.URI}, and {@link java.net.URL}.
115-
*
116113
* <p>If the target type is not covered by any of the above, a convention-based
117114
* conversion strategy will be used to convert the source {@code String} into the
118115
* given target type by invoking a static factory method or factory constructor
119116
* defined in the target type. The search algorithm used in this strategy is
120117
* outlined below.
121-
*
122118
* <h4>Search Algorithm</h4>
123-
*
124119
* <ol>
125120
* <li>Search for a single, non-private static factory method in the target
126121
* type that converts from a String to the target type. Use the factory method
127122
* if present.</li>
128123
* <li>Search for a single, non-private constructor in the target type that
129124
* accepts a String. Use the constructor if present.</li>
130125
* </ol>
131-
*
132126
* <p>If multiple suitable factory methods are discovered, they will be ignored.
133127
* If neither a single factory method nor a single constructor is found, the
134128
* convention-based conversion strategy will not apply.
135129
*
136130
* @param source the source object to convert; may be {@code null} but only
137131
* if the target type is a reference type
132+
* @param sourceType the descriptor of the source type; never {@code null}
138133
* @param targetType the target type the source should be converted into;
139134
* never {@code null}
140135
* @param classLoader the {@code ClassLoader} to use; never {@code null}
@@ -143,7 +138,8 @@ public boolean canConvert(Object source, TypeDescriptor targetType) {
143138
* @throws ConversionException if an error occurs during the conversion
144139
*/
145140
@Override
146-
public Object convert(Object source, TypeDescriptor targetType, ClassLoader classLoader) {
141+
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType,
142+
ClassLoader classLoader) {
147143
if (source == null) {
148144
if (targetType.isPrimitive()) {
149145
throw new ConversionException(

junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToObjectConverter.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
abstract class StringToObjectConverter implements Converter {
1818

1919
@Override
20-
public final boolean canConvert(Object source, TypeDescriptor targetType) {
20+
public final boolean canConvert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
2121
return canConvert(targetType.getType());
2222
}
2323

@@ -29,7 +29,8 @@ public final boolean canConvert(Object source, TypeDescriptor targetType) {
2929
abstract boolean canConvert(Class<?> targetType);
3030

3131
@Override
32-
public final Object convert(Object source, TypeDescriptor targetType, ClassLoader classLoader) {
32+
public final Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType,
33+
ClassLoader classLoader) {
3334
return convert((String) source, targetType.getType(), classLoader);
3435
}
3536

junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/TypeDescriptor.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.lang.reflect.Parameter;
1717

1818
import org.apiguardian.api.API;
19+
import org.junit.platform.commons.util.Preconditions;
1920
import org.junit.platform.commons.util.ReflectionUtils;
2021

2122
/**
@@ -28,15 +29,21 @@ public final class TypeDescriptor {
2829

2930
private final Class<?> type;
3031

31-
public static TypeDescriptor forType(Class<?> type) {
32-
return new TypeDescriptor(type);
32+
public static TypeDescriptor forClass(Class<?> clazz) {
33+
return new TypeDescriptor(clazz);
34+
}
35+
36+
public static TypeDescriptor forInstance(Object instance) {
37+
return new TypeDescriptor(instance != null ? instance.getClass() : null);
3338
}
3439

3540
public static TypeDescriptor forField(Field field) {
41+
Preconditions.notNull(field, "field must not be null");
3642
return new TypeDescriptor(field.getType());
3743
}
3844

3945
public static TypeDescriptor forParameter(Parameter parameter) {
46+
Preconditions.notNull(parameter, "parameter must not be null");
4047
return new TypeDescriptor(parameter.getType());
4148
}
4249

junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/TypedConverter.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,14 @@ protected TypedConverter(Class<S> sourceType, Class<T> targetType) {
4444
}
4545

4646
@Override
47-
public final boolean canConvert(Object source, TypeDescriptor targetType) {
47+
public final boolean canConvert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
4848
return this.sourceType.isInstance(source)
4949
&& ReflectionUtils.isAssignableTo(this.targetType, targetType.getType());
5050
}
5151

5252
@Override
53-
public final Object convert(Object source, TypeDescriptor targetType, ClassLoader classLoader) {
53+
public final Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType,
54+
ClassLoader classLoader) {
5455
return source == null ? convert(null) : convert(this.sourceType.cast(source));
5556
}
5657

jupiter-tests/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ void delegatesStringsConversion() {
9999

100100
convert("value", int.class);
101101

102-
verify(underTest).delegateConversion("value", TypeDescriptor.forType(int.class),
102+
verify(underTest).delegateConversion("value", TypeDescriptor.forClass(int.class),
103103
getClassLoader(DefaultArgumentConverterTests.class));
104104
}
105105

@@ -130,7 +130,7 @@ void delegatesLocaleConversionWithExplicitIso639Format() {
130130

131131
convert("en", Locale.class);
132132

133-
verify(underTest).convert("en", TypeDescriptor.forType(Locale.class),
133+
verify(underTest).convert("en", TypeDescriptor.forClass(Locale.class),
134134
getClassLoader(DefaultArgumentConverterTests.class));
135135
}
136136

@@ -144,7 +144,7 @@ void throwsExceptionForDelegatedConversionFailure() {
144144
.withCause(exception) //
145145
.withMessage(exception.getMessage());
146146

147-
verify(underTest).delegateConversion("value", TypeDescriptor.forType(int.class),
147+
verify(underTest).delegateConversion("value", TypeDescriptor.forClass(int.class),
148148
getClassLoader(DefaultArgumentConverterTests.class));
149149
}
150150

@@ -165,7 +165,7 @@ void delegatesStringToClassWithCustomTypeFromDifferentClassLoaderConversion() th
165165
assertThat(clazz).isEqualTo(customType);
166166
assertThat(clazz.getClassLoader()).isSameAs(testClassLoader);
167167

168-
verify(underTest).delegateConversion(customTypeName, TypeDescriptor.forType(Class.class), testClassLoader);
168+
verify(underTest).delegateConversion(customTypeName, TypeDescriptor.forClass(Class.class), testClassLoader);
169169
}
170170
}
171171

@@ -186,7 +186,7 @@ private Object convert(Object input, Class<?> targetClass) {
186186
}
187187

188188
private Object convert(Object input, Class<?> targetClass, ClassLoader classLoader) {
189-
return underTest.convert(input, TypeDescriptor.forType(targetClass), classLoader);
189+
return underTest.convert(input, TypeDescriptor.forClass(targetClass), classLoader);
190190
}
191191

192192
@SuppressWarnings("unused")

platform-tests/src/test/java/org/junit/platform/commons/support/conversion/DefaultConverterTests.java

+9-9
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ void convertsStringsToPrimitiveWrapperTypes() {
105105
@ValueSource(classes = { char.class, boolean.class, short.class, byte.class, int.class, long.class, float.class,
106106
double.class, void.class })
107107
void throwsExceptionForNullToPrimitiveTypeConversion(Class<?> type) {
108-
TypeDescriptor typeDescriptor = TypeDescriptor.forType(type);
108+
TypeDescriptor typeDescriptor = TypeDescriptor.forClass(type);
109109

110110
assertThat(canConvert(null, typeDescriptor)).isFalse();
111111
assertThatExceptionOfType(ConversionException.class) //
@@ -117,7 +117,7 @@ void throwsExceptionForNullToPrimitiveTypeConversion(Class<?> type) {
117117
@ValueSource(classes = { Boolean.class, Character.class, Short.class, Byte.class, Integer.class, Long.class,
118118
Float.class, Double.class })
119119
void throwsExceptionWhenConvertingTheWordNullToPrimitiveWrapperType(Class<?> type) {
120-
TypeDescriptor typeDescriptor = TypeDescriptor.forType(type);
120+
TypeDescriptor typeDescriptor = TypeDescriptor.forClass(type);
121121

122122
assertThat(canConvert("null", typeDescriptor)).isTrue();
123123
assertThatExceptionOfType(ConversionException.class) //
@@ -132,7 +132,7 @@ void throwsExceptionWhenConvertingTheWordNullToPrimitiveWrapperType(Class<?> typ
132132

133133
@Test
134134
void throwsExceptionOnInvalidStringForPrimitiveTypes() {
135-
TypeDescriptor charDescriptor = TypeDescriptor.forType(char.class);
135+
TypeDescriptor charDescriptor = TypeDescriptor.forClass(char.class);
136136

137137
assertThat(canConvert("ab", charDescriptor)).isTrue();
138138
assertThatExceptionOfType(ConversionException.class) //
@@ -141,7 +141,7 @@ void throwsExceptionOnInvalidStringForPrimitiveTypes() {
141141
.havingCause() //
142142
.withMessage("String must have length of 1: ab");
143143

144-
TypeDescriptor booleanDescriptor = TypeDescriptor.forType(boolean.class);
144+
TypeDescriptor booleanDescriptor = TypeDescriptor.forClass(boolean.class);
145145

146146
assertThat(canConvert("tru", booleanDescriptor)).isTrue();
147147
assertThatExceptionOfType(ConversionException.class) //
@@ -167,7 +167,7 @@ void throwsExceptionOnInvalidStringForPrimitiveTypes() {
167167

168168
@Test
169169
void throwsExceptionWhenImplicitConversionIsUnsupported() {
170-
TypeDescriptor typeDescriptor = TypeDescriptor.forType(Enigma.class);
170+
TypeDescriptor typeDescriptor = TypeDescriptor.forClass(Enigma.class);
171171

172172
assertThat(canConvert("foo", typeDescriptor)).isFalse();
173173
assertThatExceptionOfType(ConversionException.class) //
@@ -251,7 +251,7 @@ void convertsStringToClassWithCustomTypeFromDifferentClassLoader() throws Except
251251
var declaringExecutable = ReflectionSupport.findMethod(customType, "foo").get();
252252
assertThat(declaringExecutable.getDeclaringClass().getClassLoader()).isSameAs(testClassLoader);
253253

254-
var typeDescriptor = TypeDescriptor.forType(Class.class);
254+
var typeDescriptor = TypeDescriptor.forClass(Class.class);
255255
assertThat(canConvert(customTypeName, typeDescriptor)).isTrue();
256256

257257
var clazz = (Class<?>) convert(customTypeName, typeDescriptor, classLoader(declaringExecutable));
@@ -332,7 +332,7 @@ void convertsStringToUUID() {
332332
// -------------------------------------------------------------------------
333333

334334
private void assertConverts(Object input, Class<?> targetClass, Object expectedOutput) {
335-
TypeDescriptor typeDescriptor = TypeDescriptor.forType(targetClass);
335+
TypeDescriptor typeDescriptor = TypeDescriptor.forClass(targetClass);
336336

337337
assertThat(canConvert(input, typeDescriptor)).isTrue();
338338

@@ -344,15 +344,15 @@ private void assertConverts(Object input, Class<?> targetClass, Object expectedO
344344
}
345345

346346
private boolean canConvert(Object input, TypeDescriptor targetClass) {
347-
return DefaultConverter.INSTANCE.canConvert(input, targetClass);
347+
return DefaultConverter.INSTANCE.canConvert(input, TypeDescriptor.forInstance(input), targetClass);
348348
}
349349

350350
private Object convert(Object input, TypeDescriptor targetClass) {
351351
return convert(input, targetClass, classLoader());
352352
}
353353

354354
private Object convert(Object input, TypeDescriptor targetClass, ClassLoader classLoader) {
355-
return DefaultConverter.INSTANCE.convert(input, targetClass, classLoader);
355+
return DefaultConverter.INSTANCE.convert(input, TypeDescriptor.forInstance(input), targetClass, classLoader);
356356
}
357357

358358
private static ClassLoader classLoader() {

0 commit comments

Comments
 (0)