Skip to content

Commit b560cff

Browse files
committed
Rewrite StringToObjectConverter hierarchy as Converter subclasses
1 parent 3499da1 commit b560cff

12 files changed

+55
-61
lines changed

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

+3-9
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import static java.util.Arrays.asList;
1414
import static java.util.Collections.unmodifiableList;
1515
import static org.apiguardian.api.API.Status.INTERNAL;
16-
import static org.junit.platform.commons.util.ReflectionUtils.getWrapperType;
1716

1817
import java.io.File;
1918
import java.math.BigDecimal;
@@ -90,7 +89,7 @@ public boolean canConvert(Object source, TypeDescriptor targetType) {
9089
}
9190

9291
return stringToObjectConverters.stream().anyMatch(
93-
candidate -> candidate.canConvertTo(toWrapperType(targetType.getType())));
92+
candidate -> candidate.canConvert(targetType.getWrapperType()));
9493
}
9594

9695
/**
@@ -157,9 +156,9 @@ public Object convert(Object source, TypeDescriptor targetType, ClassLoader clas
157156
return source;
158157
}
159158

160-
Class<?> targetTypeToUse = toWrapperType(targetType.getType());
159+
Class<?> targetTypeToUse = targetType.getWrapperType();
161160
Optional<StringToObjectConverter> converter = stringToObjectConverters.stream().filter(
162-
candidate -> candidate.canConvertTo(targetTypeToUse)).findFirst();
161+
candidate -> candidate.canConvert(targetTypeToUse)).findFirst();
163162
if (converter.isPresent()) {
164163
try {
165164
return converter.get().convert((String) source, targetTypeToUse, classLoader);
@@ -179,9 +178,4 @@ public Object convert(Object source, TypeDescriptor targetType, ClassLoader clas
179178
+ targetType.getType().getTypeName());
180179
}
181180

182-
private static Class<?> toWrapperType(Class<?> targetType) {
183-
Class<?> wrapperType = getWrapperType(targetType);
184-
return wrapperType != null ? wrapperType : targetType;
185-
}
186-
187181
}

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
* @since 1.11
5252
* @see ConversionSupport
5353
*/
54-
class FallbackStringToObjectConverter implements StringToObjectConverter {
54+
class FallbackStringToObjectConverter extends StringToObjectConverter {
5555

5656
/**
5757
* Implementation of the NULL Object Pattern.
@@ -70,12 +70,12 @@ class FallbackStringToObjectConverter implements StringToObjectConverter {
7070
= new ConcurrentHashMap<>(64);
7171

7272
@Override
73-
public boolean canConvertTo(Class<?> targetType) {
73+
public boolean canConvert(Class<?> targetType) {
7474
return findFactoryExecutable(targetType) != NULL_EXECUTABLE;
7575
}
7676

7777
@Override
78-
public Object convert(String source, Class<?> targetType) throws Exception {
78+
public Object convert(String source, Class<?> targetType, ClassLoader classLoader) {
7979
Function<String, Object> executable = findFactoryExecutable(targetType);
8080
Preconditions.condition(executable != NULL_EXECUTABLE,
8181
"Illegal state: convert() must not be called if canConvert() returned false");

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@
1212

1313
import org.junit.platform.commons.util.Preconditions;
1414

15-
class StringToBooleanConverter implements StringToObjectConverter {
15+
class StringToBooleanConverter extends StringToObjectConverter {
1616

1717
@Override
18-
public boolean canConvertTo(Class<?> targetType) {
18+
public boolean canConvert(Class<?> targetType) {
1919
return targetType == Boolean.class;
2020
}
2121

2222
@Override
23-
public Object convert(String source, Class<?> targetType) {
23+
public Object convert(String source, Class<?> targetType, ClassLoader classLoader) {
2424
boolean isTrue = "true".equalsIgnoreCase(source);
2525
Preconditions.condition(isTrue || "false".equalsIgnoreCase(source),
2626
() -> "String must be 'true' or 'false' (ignoring case): " + source);

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@
1212

1313
import org.junit.platform.commons.util.Preconditions;
1414

15-
class StringToCharacterConverter implements StringToObjectConverter {
15+
class StringToCharacterConverter extends StringToObjectConverter {
1616

1717
@Override
18-
public boolean canConvertTo(Class<?> targetType) {
18+
public boolean canConvert(Class<?> targetType) {
1919
return targetType == Character.class;
2020
}
2121

2222
@Override
23-
public Object convert(String source, Class<?> targetType) {
23+
public Object convert(String source, Class<?> targetType, ClassLoader classLoader) {
2424
Preconditions.condition(source.length() == 1, () -> "String must have length of 1: " + source);
2525
return source.charAt(0);
2626
}

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

+3-8
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,15 @@
1212

1313
import org.junit.platform.commons.support.ReflectionSupport;
1414

15-
class StringToClassConverter implements StringToObjectConverter {
15+
class StringToClassConverter extends StringToObjectConverter {
1616

1717
@Override
18-
public boolean canConvertTo(Class<?> targetType) {
18+
public boolean canConvert(Class<?> targetType) {
1919
return targetType == Class.class;
2020
}
2121

2222
@Override
23-
public Object convert(String source, Class<?> targetType) throws Exception {
24-
throw new UnsupportedOperationException("Invoke convert(String, Class<?>, ClassLoader) instead");
25-
}
26-
27-
@Override
28-
public Object convert(String className, Class<?> targetType, ClassLoader classLoader) throws Exception {
23+
public Object convert(String className, Class<?> targetType, ClassLoader classLoader) {
2924
// @formatter:off
3025
return ReflectionSupport.tryToLoadClass(className, classLoader)
3126
.getOrThrow(cause -> new ConversionException(

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import java.util.UUID;
2727
import java.util.function.Function;
2828

29-
class StringToCommonJavaTypesConverter implements StringToObjectConverter {
29+
class StringToCommonJavaTypesConverter extends StringToObjectConverter {
3030

3131
private static final Map<Class<?>, Function<String, ?>> CONVERTERS;
3232

@@ -49,12 +49,12 @@ class StringToCommonJavaTypesConverter implements StringToObjectConverter {
4949
}
5050

5151
@Override
52-
public boolean canConvertTo(Class<?> targetType) {
52+
public boolean canConvert(Class<?> targetType) {
5353
return CONVERTERS.containsKey(targetType);
5454
}
5555

5656
@Override
57-
public Object convert(String source, Class<?> targetType) throws Exception {
57+
public Object convert(String source, Class<?> targetType, ClassLoader classLoader) {
5858
return CONVERTERS.get(targetType).apply(source);
5959
}
6060

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@
1010

1111
package org.junit.platform.commons.support.conversion;
1212

13-
class StringToEnumConverter implements StringToObjectConverter {
13+
class StringToEnumConverter extends StringToObjectConverter {
1414

1515
@Override
16-
public boolean canConvertTo(Class<?> targetType) {
16+
public boolean canConvert(Class<?> targetType) {
1717
return targetType.isEnum();
1818
}
1919

2020
@Override
2121
@SuppressWarnings({ "unchecked", "rawtypes" })
22-
public Object convert(String source, Class targetType) throws Exception {
22+
public Object convert(String source, Class targetType, ClassLoader classLoader) {
2323
return Enum.valueOf(targetType, source);
2424
}
2525

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import java.util.Map;
3131
import java.util.function.Function;
3232

33-
class StringToJavaTimeConverter implements StringToObjectConverter {
33+
class StringToJavaTimeConverter extends StringToObjectConverter {
3434

3535
private static final Map<Class<?>, Function<String, ?>> CONVERTERS;
3636
static {
@@ -53,12 +53,12 @@ class StringToJavaTimeConverter implements StringToObjectConverter {
5353
}
5454

5555
@Override
56-
public boolean canConvertTo(Class<?> targetType) {
56+
public boolean canConvert(Class<?> targetType) {
5757
return CONVERTERS.containsKey(targetType);
5858
}
5959

6060
@Override
61-
public Object convert(String source, Class<?> targetType) throws Exception {
61+
public Object convert(String source, Class<?> targetType, ClassLoader classLoader) {
6262
return CONVERTERS.get(targetType).apply(source);
6363
}
6464

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import java.util.Map;
1919
import java.util.function.Function;
2020

21-
class StringToNumberConverter implements StringToObjectConverter {
21+
class StringToNumberConverter extends StringToObjectConverter {
2222

2323
private static final Map<Class<?>, Function<String, ?>> CONVERTERS;
2424
static {
@@ -38,12 +38,12 @@ class StringToNumberConverter implements StringToObjectConverter {
3838
}
3939

4040
@Override
41-
public boolean canConvertTo(Class<?> targetType) {
41+
public boolean canConvert(Class<?> targetType) {
4242
return CONVERTERS.containsKey(targetType);
4343
}
4444

4545
@Override
46-
public Object convert(String source, Class<?> targetType) {
46+
public Object convert(String source, Class<?> targetType, ClassLoader classLoader) {
4747
return CONVERTERS.get(targetType).apply(source.replace("_", ""));
4848
}
4949

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

+13-19
Original file line numberDiff line numberDiff line change
@@ -14,39 +14,33 @@
1414
* Internal API for converting arguments of type {@link String} to a specified
1515
* target type.
1616
*/
17-
interface StringToObjectConverter {
17+
abstract class StringToObjectConverter implements Converter {
18+
19+
@Override
20+
public final boolean canConvert(Object source, TypeDescriptor targetType) {
21+
return canConvert(targetType.getType());
22+
}
1823

1924
/**
2025
* Determine if this converter can convert from a {@link String} to the
2126
* supplied target type (which is guaranteed to be a wrapper type for
2227
* primitives &mdash; for example, {@link Integer} instead of {@code int}).
2328
*/
24-
boolean canConvertTo(Class<?> targetType);
29+
abstract boolean canConvert(Class<?> targetType);
2530

26-
/**
27-
* Convert the supplied {@link String} to the supplied target type (which is
28-
* guaranteed to be a wrapper type for primitives &mdash; for example,
29-
* {@link Integer} instead of {@code int}).
30-
*
31-
* <p>This method will only be invoked in {@link #canConvertTo(Class)}
32-
* returned {@code true} for the same target type.
33-
*/
34-
Object convert(String source, Class<?> targetType) throws Exception;
31+
@Override
32+
public final Object convert(Object source, TypeDescriptor targetType, ClassLoader classLoader) {
33+
return convert((String) source, targetType.getType(), classLoader);
34+
}
3535

3636
/**
3737
* Convert the supplied {@link String} to the supplied target type (which is
3838
* guaranteed to be a wrapper type for primitives &mdash; for example,
3939
* {@link Integer} instead of {@code int}).
4040
*
41-
* <p>This method will only be invoked in {@link #canConvertTo(Class)}
41+
* <p>This method will only be invoked if {@link #canConvert(Class)}
4242
* returned {@code true} for the same target type.
43-
*
44-
* <p>The default implementation simply delegates to {@link #convert(String, Class)}.
45-
* Can be overridden by concrete implementations of this interface that need
46-
* access to the supplied {@link ClassLoader}.
4743
*/
48-
default Object convert(String source, Class<?> targetType, ClassLoader classLoader) throws Exception {
49-
return convert(source, targetType);
50-
}
44+
abstract Object convert(String source, Class<?> targetType, ClassLoader classLoader);
5145

5246
}

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

+6
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.ReflectionUtils;
1920

2021
/**
2122
*
@@ -47,6 +48,11 @@ public Class<?> getType() {
4748
return type;
4849
}
4950

51+
public Class<?> getWrapperType() {
52+
Class<?> wrapperType = ReflectionUtils.getWrapperType(type);
53+
return wrapperType != null ? wrapperType : type;
54+
}
55+
5056
public boolean isPrimitive() {
5157
return getType().isPrimitive();
5258
}

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

+9-4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.junit.jupiter.api.Test;
2222
import org.junit.platform.commons.support.conversion.FallbackStringToObjectConverter.IsFactoryConstructor;
2323
import org.junit.platform.commons.support.conversion.FallbackStringToObjectConverter.IsFactoryMethod;
24+
import org.junit.platform.commons.util.ClassLoaderUtils;
2425
import org.junit.platform.commons.util.ReflectionUtils;
2526

2627
/**
@@ -87,13 +88,13 @@ void convertsStringToNewspaperViaConstructorIgnoringMultipleFactoryMethods() thr
8788
@Test
8889
@DisplayName("Cannot convert String to Diary because Diary has neither a static factory method nor a factory constructor")
8990
void cannotConvertStringToDiary() {
90-
assertThat(converter.canConvertTo(Diary.class)).isFalse();
91+
assertThat(converter.canConvert(Diary.class)).isFalse();
9192
}
9293

9394
@Test
9495
@DisplayName("Cannot convert String to Magazine because Magazine has multiple static factory methods")
9596
void cannotConvertStringToMagazine() {
96-
assertThat(converter.canConvertTo(Magazine.class)).isFalse();
97+
assertThat(converter.canConvert(Magazine.class)).isFalse();
9798
}
9899

99100
// -------------------------------------------------------------------------
@@ -120,15 +121,19 @@ private static Method magazineMethod(String methodName) {
120121
}
121122

122123
private static void assertConverts(String input, Class<?> targetType, Object expectedOutput) throws Exception {
123-
assertThat(converter.canConvertTo(targetType)).isTrue();
124+
assertThat(converter.canConvert(targetType)).isTrue();
124125

125-
var result = converter.convert(input, targetType);
126+
var result = converter.convert(input, targetType, classLoader());
126127

127128
assertThat(result) //
128129
.describedAs(input + " --(" + targetType.getName() + ")--> " + expectedOutput) //
129130
.isEqualTo(expectedOutput);
130131
}
131132

133+
private static ClassLoader classLoader() {
134+
return ClassLoaderUtils.getClassLoader(FallbackStringToObjectConverterTests.class);
135+
}
136+
132137
static class Book {
133138

134139
private final String title;

0 commit comments

Comments
 (0)