Skip to content

Commit 8b78923

Browse files
committed
Add type parameters to Converter
1 parent d5bb2ae commit 8b78923

File tree

8 files changed

+56
-58
lines changed

8 files changed

+56
-58
lines changed

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

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ private ConversionSupport() {
5656
@API(status = DEPRECATED, since = "6.0")
5757
public static <T> @Nullable T convert(@Nullable String source, Class<T> targetType,
5858
@Nullable ClassLoader classLoader) {
59-
return convert(source, TypeDescriptor.forClass(targetType), getClassLoader(classLoader));
59+
return convert(source, TypeDescriptor.forClass(targetType), classLoader);
6060
}
6161

6262
/**
@@ -76,17 +76,17 @@ private ConversionSupport() {
7676
* @since 6.0
7777
*/
7878
@API(status = EXPERIMENTAL, since = "6.0")
79-
@SuppressWarnings("unchecked")
79+
@SuppressWarnings({ "unchecked", "rawtypes" })
8080
public static <T> @Nullable T convert(@Nullable Object source, TypeDescriptor targetType,
8181
@Nullable ClassLoader classLoader) {
8282
TypeDescriptor sourceType = TypeDescriptor.forInstance(source);
83-
ClassLoader classLoaderToUse = getClassLoader(classLoader);
83+
ClassLoader classLoaderToUse = classLoader != null ? classLoader : ClassLoaderUtils.getDefaultClassLoader();
8484
ServiceLoader<Converter> serviceLoader = ServiceLoader.load(Converter.class, classLoaderToUse);
8585

8686
Converter converter = Stream.concat( //
8787
StreamSupport.stream(serviceLoader.spliterator(), false), //
8888
Stream.of(DefaultConverter.INSTANCE)) //
89-
.filter(candidate -> candidate.canConvert(source, sourceType, targetType)) //
89+
.filter(candidate -> candidate.canConvert(sourceType, targetType)) //
9090
.findFirst() //
9191
.orElseThrow(() -> new ConversionException(
9292
"No registered or built-in converter for source '%s' and target type %s".formatted( //
@@ -95,8 +95,4 @@ private ConversionSupport() {
9595
return (T) converter.convert(source, sourceType, targetType, classLoaderToUse);
9696
}
9797

98-
private static ClassLoader getClassLoader(@Nullable ClassLoader classLoader) {
99-
return classLoader != null ? classLoader : ClassLoaderUtils.getDefaultClassLoader();
100-
}
101-
10298
}

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,26 +34,24 @@
3434
* @see TypedConverter
3535
*/
3636
@API(status = EXPERIMENTAL, since = "6.0")
37-
public interface Converter {
37+
public interface Converter<S, T> {
3838

3939
/**
40-
* Determine if the supplied source object can be converted into an instance
40+
* Determine if the supplied source type can be converted into an instance
4141
* of the specified target type.
4242
*
43-
* @param source the source object to convert; may be {@code null} but only
44-
* if the target type is a reference type
4543
* @param sourceType the descriptor of the source type; never {@code null}
4644
* @param targetType the descriptor of the type the source should be converted into;
4745
* never {@code null}
48-
* @return {@code true} if the supplied source can be converted
46+
* @return {@code true} if the supplied source type can be converted
4947
*/
50-
boolean canConvert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
48+
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
5149

5250
/**
5351
* Convert the supplied source object into an instance of the specified
5452
* target type.
55-
* <p>This method will only be invoked if {@link #canConvert(Object, TypeDescriptor, TypeDescriptor)}
56-
* returned {@code true} for the same target type.
53+
* <p>This method will only be invoked if {@link #canConvert(TypeDescriptor, TypeDescriptor)}
54+
* returned {@code true} for the same type descriptors.
5755
*
5856
* @param source the source object to convert; may be {@code null} but only
5957
* if the target type is a reference type
@@ -66,7 +64,7 @@ public interface Converter {
6664
* @throws ConversionException if an error occurs during the conversion
6765
*/
6866
@Nullable
69-
Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType,
70-
ClassLoader classLoader) throws ConversionException;
67+
T convert(@Nullable S source, TypeDescriptor sourceType, TypeDescriptor targetType, ClassLoader classLoader)
68+
throws ConversionException;
7169

7270
}

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

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
* @since 6.0
4545
*/
4646
@API(status = INTERNAL, since = "6.0")
47-
public class DefaultConverter implements Converter {
47+
public class DefaultConverter implements Converter<String, Object> {
4848

4949
static final DefaultConverter INSTANCE = new DefaultConverter();
5050

@@ -64,23 +64,21 @@ private DefaultConverter() {
6464
}
6565

6666
/**
67-
* Determine if the supplied source object can be converted into an instance
67+
* Determine if the supplied source type can be converted into an instance
6868
* of the specified target type.
6969
*
70-
* @param source the source object to convert; may be {@code null} but only
71-
* if the target type is a reference type
7270
* @param sourceType the descriptor of the source type; never {@code null}
7371
* @param targetType the target type the source should be converted into;
7472
* never {@code null}
7573
* @return {@code true} if the supplied source can be converted
7674
*/
7775
@Override
78-
public boolean canConvert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
79-
if (source == null) {
76+
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
77+
if (sourceType == TypeDescriptor.NONE) {
8078
return !targetType.isPrimitive();
8179
}
8280

83-
if (!(source instanceof String)) {
81+
if (!(String.class.equals(sourceType.getType()))) {
8482
return false;
8583
}
8684

@@ -93,7 +91,7 @@ public boolean canConvert(@Nullable Object source, TypeDescriptor sourceType, Ty
9391
}
9492

9593
/**
96-
* Convert the supplied source object into an instance of the specified
94+
* Convert the supplied source {@link String} into an instance of the specified
9795
* target type.
9896
* <p>If the target type is {@code String}, the source {@code String} will not
9997
* be modified.
@@ -126,19 +124,19 @@ public boolean canConvert(@Nullable Object source, TypeDescriptor sourceType, Ty
126124
* If neither a single factory method nor a single constructor is found, the
127125
* convention-based conversion strategy will not apply.
128126
*
129-
* @param source the source object to convert; may be {@code null} but only
127+
* @param source the source {@link String} to convert; may be {@code null} but only
130128
* if the target type is a reference type
131129
* @param sourceType the descriptor of the source type; never {@code null}
132-
* @param targetType the target type the source should be converted into;
130+
* @param targetType the descriptor of the type the source should be converted into;
133131
* never {@code null}
134132
* @param classLoader the {@code ClassLoader} to use; never {@code null}
135133
* @return the converted object; may be {@code null} but only if the target
136134
* type is a reference type
137135
* @throws ConversionException if an error occurs during the conversion
138136
*/
139137
@Override
140-
public @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType,
141-
ClassLoader classLoader) {
138+
public @Nullable Object convert(@Nullable String source, TypeDescriptor sourceType, TypeDescriptor targetType,
139+
ClassLoader classLoader) throws ConversionException {
142140
if (source == null) {
143141
if (targetType.isPrimitive()) {
144142
throw new ConversionException(
@@ -156,7 +154,7 @@ public boolean canConvert(@Nullable Object source, TypeDescriptor sourceType, Ty
156154
candidate -> candidate.canConvert(targetTypeToUse)).findFirst();
157155
if (converter.isPresent()) {
158156
try {
159-
return converter.get().convert((String) source, targetTypeToUse, classLoader);
157+
return converter.get().convert(source, targetTypeToUse, classLoader);
160158
}
161159
catch (Exception ex) {
162160
if (ex instanceof ConversionException) {

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
* Internal API for converting arguments of type {@link String} to a specified
1717
* target type.
1818
*/
19-
abstract class StringToObjectConverter implements Converter {
19+
abstract class StringToObjectConverter implements Converter<String, Object> {
2020

2121
@Override
22-
public final boolean canConvert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
22+
public final boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
2323
return canConvert(targetType.getType());
2424
}
2525

@@ -31,9 +31,9 @@ public final boolean canConvert(@Nullable Object source, TypeDescriptor sourceTy
3131
abstract boolean canConvert(@Nullable Class<?> targetType);
3232

3333
@Override
34-
public final Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType,
34+
public final Object convert(@Nullable String source, TypeDescriptor sourceType, TypeDescriptor targetType,
3535
ClassLoader classLoader) {
36-
return convert((String) source, targetType.getType(), classLoader);
36+
return convert(source, targetType.getType(), classLoader);
3737
}
3838

3939
/**

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,15 @@
3030
public final class TypeDescriptor {
3131

3232
/**
33-
* Internal marker for type descriptors created from a {@code null} value.
33+
* Internal marker for descriptors created from a {@code null} value.
3434
*/
3535
private static final Class<?> NULL_TYPE = Void.class;
3636

37+
/**
38+
* {@code TypeDescriptor} returned when no value is available.
39+
*/
40+
public static final TypeDescriptor NONE = new TypeDescriptor(NULL_TYPE);
41+
3742
private final Class<?> type;
3843

3944
public static TypeDescriptor forClass(Class<?> clazz) {
@@ -42,25 +47,25 @@ public static TypeDescriptor forClass(Class<?> clazz) {
4247
}
4348

4449
public static TypeDescriptor forInstance(@Nullable Object instance) {
45-
return new TypeDescriptor(instance != null ? instance.getClass() : NULL_TYPE);
50+
return instance != null ? forClass(instance.getClass()) : NONE;
4651
}
4752

4853
public static TypeDescriptor forField(Field field) {
4954
Preconditions.notNull(field, "field must not be null");
50-
return new TypeDescriptor(field.getType());
55+
return forClass(field.getType());
5156
}
5257

5358
public static TypeDescriptor forParameter(Parameter parameter) {
5459
Preconditions.notNull(parameter, "parameter must not be null");
55-
return new TypeDescriptor(parameter.getType());
60+
return forClass(parameter.getType());
5661
}
5762

5863
private TypeDescriptor(Class<?> type) {
5964
this.type = type;
6065
}
6166

6267
public @Nullable Class<?> getType() {
63-
return type != NULL_TYPE ? type : null;
68+
return this != NONE ? type : null;
6469
}
6570

6671
public @Nullable Class<?> getWrapperType() {
@@ -69,11 +74,11 @@ private TypeDescriptor(Class<?> type) {
6974
}
7075

7176
public boolean isPrimitive() {
72-
return type != NULL_TYPE && type.isPrimitive();
77+
return type.isPrimitive();
7378
}
7479

7580
public String getTypeName() {
76-
return type != NULL_TYPE ? type.getName() : "null";
81+
return type.getName();
7782
}
7883

7984
@Override

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
1414

1515
import org.apiguardian.api.API;
16+
import org.jspecify.annotations.Nullable;
1617
import org.junit.platform.commons.util.Preconditions;
17-
import org.junit.platform.commons.util.ReflectionUtils;
1818

1919
/**
2020
* {@code TypedConversionService} is an abstract base class for
@@ -26,7 +26,7 @@
2626
* @since 6.0
2727
*/
2828
@API(status = EXPERIMENTAL, since = "6.0")
29-
public abstract class TypedConverter<S, T> implements Converter {
29+
public abstract class TypedConverter<S, T> implements Converter<S, T> {
3030

3131
private final Class<S> sourceType;
3232
private final Class<T> targetType;
@@ -44,15 +44,15 @@ protected TypedConverter(Class<S> sourceType, Class<T> targetType) {
4444
}
4545

4646
@Override
47-
public final boolean canConvert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
48-
return this.sourceType.isInstance(source)
49-
&& ReflectionUtils.isAssignableTo(this.targetType, targetType.getType());
47+
public final boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
48+
// FIXME add test cases with subtypes
49+
return this.sourceType == sourceType.getType() && this.targetType == targetType.getType();
5050
}
5151

5252
@Override
53-
public final Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType,
53+
public final @Nullable T convert(@Nullable S source, TypeDescriptor sourceType, TypeDescriptor targetType,
5454
ClassLoader classLoader) {
55-
return source == null ? convert(null) : convert(this.sourceType.cast(source));
55+
return convert(source);
5656
}
5757

5858
/**
@@ -64,6 +64,6 @@ public final Object convert(Object source, TypeDescriptor sourceType, TypeDescri
6464
* type is a reference type
6565
* @throws ConversionException if an error occurs during the conversion
6666
*/
67-
protected abstract T convert(S source) throws ConversionException;
67+
protected abstract @Nullable T convert(@Nullable S source) throws ConversionException;
6868

6969
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,19 @@
1212

1313
import java.util.Locale;
1414

15+
import org.jspecify.annotations.Nullable;
1516
import org.junit.platform.commons.support.conversion.TypedConverter;
1617

17-
// FIXME delete
18+
// FIXME move to ConversionSupportIntegrationTests
1819
public class LocaleConverter extends TypedConverter<String, Locale> {
1920

2021
public LocaleConverter() {
2122
super(String.class, Locale.class);
2223
}
2324

2425
@Override
25-
protected Locale convert(String source) {
26-
return Locale.forLanguageTag(source);
26+
protected @Nullable Locale convert(@Nullable String source) {
27+
return source != null ? Locale.forLanguageTag(source) : null;
2728
}
2829

2930
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ void convertsStringToUUID() {
330330

331331
// -------------------------------------------------------------------------
332332

333-
private void assertConverts(@Nullable Object input, Class<?> targetClass, @Nullable Object expectedOutput) {
333+
private void assertConverts(@Nullable String input, Class<?> targetClass, @Nullable Object expectedOutput) {
334334
TypeDescriptor typeDescriptor = TypeDescriptor.forClass(targetClass);
335335

336336
assertThat(canConvert(input, typeDescriptor)).isTrue();
@@ -342,15 +342,15 @@ private void assertConverts(@Nullable Object input, Class<?> targetClass, @Nulla
342342
.isEqualTo(expectedOutput);
343343
}
344344

345-
private boolean canConvert(@Nullable Object input, TypeDescriptor targetClass) {
346-
return DefaultConverter.INSTANCE.canConvert(input, TypeDescriptor.forInstance(input), targetClass);
345+
private boolean canConvert(@Nullable String input, TypeDescriptor targetClass) {
346+
return DefaultConverter.INSTANCE.canConvert(TypeDescriptor.forInstance(input), targetClass);
347347
}
348348

349-
private @Nullable Object convert(@Nullable Object input, TypeDescriptor targetClass) {
349+
private @Nullable Object convert(@Nullable String input, TypeDescriptor targetClass) {
350350
return convert(input, targetClass, classLoader());
351351
}
352352

353-
private @Nullable Object convert(@Nullable Object input, TypeDescriptor targetClass, ClassLoader classLoader) {
353+
private @Nullable Object convert(@Nullable String input, TypeDescriptor targetClass, ClassLoader classLoader) {
354354
return DefaultConverter.INSTANCE.convert(input, TypeDescriptor.forInstance(input), targetClass, classLoader);
355355
}
356356

0 commit comments

Comments
 (0)