Skip to content

Commit 61494f9

Browse files
committed
Introduce TypeDescriptor
1 parent d3675e2 commit 61494f9

File tree

9 files changed

+150
-62
lines changed

9 files changed

+150
-62
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.apiguardian.api.API;
2222
import org.junit.jupiter.api.extension.ExtensionContext;
2323
import org.junit.jupiter.params.converter.DefaultArgumentConverter;
24+
import org.junit.platform.commons.support.conversion.TypeDescriptor;
2425
import org.junit.platform.commons.util.ClassUtils;
2526
import org.junit.platform.commons.util.Preconditions;
2627

@@ -46,7 +47,7 @@ public static DefaultArgumentsAccessor create(ExtensionContext context, int invo
4647
Preconditions.notNull(classLoader, "ClassLoader must not be null");
4748

4849
BiFunction<Object, Class<?>, Object> converter = (source, targetType) -> new DefaultArgumentConverter(context) //
49-
.convert(source, targetType, classLoader);
50+
.convert(source, TypeDescriptor.forType(targetType), classLoader);
5051
return new DefaultArgumentsAccessor(converter, invocationIndex, arguments);
5152
}
5253

junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/DefaultArgumentConverter.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.junit.jupiter.params.support.FieldContext;
3030
import org.junit.platform.commons.support.conversion.ConversionException;
3131
import org.junit.platform.commons.support.conversion.ConversionSupport;
32+
import org.junit.platform.commons.support.conversion.TypeDescriptor;
3233
import org.junit.platform.commons.util.ReflectionUtils;
3334

3435
/**
@@ -81,33 +82,31 @@ public DefaultArgumentConverter(ExtensionContext context) {
8182

8283
@Override
8384
public final Object convert(Object source, ParameterContext context) {
84-
Class<?> targetType = context.getParameter().getType();
8585
ClassLoader classLoader = getClassLoader(context.getDeclaringExecutable().getDeclaringClass());
86-
return convert(source, targetType, classLoader);
86+
return convert(source, TypeDescriptor.forParameter(context.getParameter()), classLoader);
8787
}
8888

8989
@Override
9090
public final Object convert(Object source, FieldContext context) throws ArgumentConversionException {
91-
Class<?> targetType = context.getField().getType();
9291
ClassLoader classLoader = getClassLoader(context.getField().getDeclaringClass());
93-
return convert(source, targetType, classLoader);
92+
return convert(source, TypeDescriptor.forField(context.getField()), classLoader);
9493
}
9594

96-
public final Object convert(Object source, Class<?> targetType, ClassLoader classLoader) {
95+
public final Object convert(Object source, TypeDescriptor targetType, ClassLoader classLoader) {
9796
if (source == null) {
9897
if (targetType.isPrimitive()) {
9998
throw new ArgumentConversionException(
100-
"Cannot convert null to primitive value of type " + targetType.getTypeName());
99+
"Cannot convert null to primitive value of type " + targetType.getType().getTypeName());
101100
}
102101
return null;
103102
}
104103

105-
if (ReflectionUtils.isAssignableTo(source, targetType)) {
104+
if (ReflectionUtils.isAssignableTo(source, targetType.getType())) {
106105
return source;
107106
}
108107

109108
if (source instanceof String //
110-
&& targetType == Locale.class //
109+
&& targetType.getType() == Locale.class //
111110
&& getLocaleConversionFormat() == LocaleConversionFormat.BCP_47) {
112111
return Locale.forLanguageTag((String) source);
113112
}
@@ -125,7 +124,7 @@ private LocaleConversionFormat getLocaleConversionFormat() {
125124
.orElse(LocaleConversionFormat.BCP_47);
126125
}
127126

128-
Object delegateConversion(Object source, Class<?> targetType, ClassLoader classLoader) {
127+
Object delegateConversion(Object source, TypeDescriptor targetType, ClassLoader classLoader) {
129128
return ConversionSupport.convert(source, targetType, classLoader);
130129
}
131130

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,12 @@ private ConversionSupport() {
4949
*
5050
* @since 1.11
5151
* @see DefaultConverter
52-
* @deprecated Use {@link #convert(Object, Class, ClassLoader)} instead.
52+
* @deprecated Use {@link #convert(Object, TypeDescriptor, ClassLoader)} instead.
5353
*/
54-
@SuppressWarnings("unchecked")
5554
@Deprecated
5655
@API(status = DEPRECATED, since = "5.13")
5756
public static <T> T convert(String source, Class<T> targetType, ClassLoader classLoader) {
58-
return (T) DefaultConverter.INSTANCE.convert(source, targetType, getClassLoader(classLoader));
57+
return convert(source, TypeDescriptor.forType(targetType), getClassLoader(classLoader));
5958
}
6059

6160
/**
@@ -76,7 +75,7 @@ public static <T> T convert(String source, Class<T> targetType, ClassLoader clas
7675
*/
7776
@API(status = EXPERIMENTAL, since = "1.13")
7877
@SuppressWarnings("unchecked")
79-
public static <T> T convert(Object source, Class<T> targetType, ClassLoader classLoader) {
78+
public static <T> T convert(Object source, TypeDescriptor targetType, ClassLoader classLoader) {
8079
ClassLoader classLoaderToUse = getClassLoader(classLoader);
8180
ServiceLoader<Converter> serviceLoader = ServiceLoader.load(Converter.class, classLoaderToUse);
8281

@@ -86,7 +85,7 @@ public static <T> T convert(Object source, Class<T> targetType, ClassLoader clas
8685
.filter(candidate -> candidate.canConvert(source, targetType, classLoader)) //
8786
.findFirst() //
8887
.orElseThrow(() -> new ConversionException("No registered or built-in converter for source '" + source
89-
+ "' and target type " + targetType.getTypeName()));
88+
+ "' and target type " + targetType.getType().getTypeName()));
9089

9190
return (T) converter.convert(source, targetType, classLoaderToUse);
9291
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,26 +41,26 @@ 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 targetType the target type the source should be converted into;
44+
* @param targetType the descriptor of the type the source should be converted into;
4545
* never {@code null}
4646
* @param classLoader the {@code ClassLoader} to use; never {@code null}
4747
* @return {@code true} if the supplied source can be converted
4848
*/
49-
boolean canConvert(Object source, Class<?> targetType, ClassLoader classLoader);
49+
boolean canConvert(Object source, TypeDescriptor targetType, ClassLoader classLoader);
5050

5151
/**
5252
* Convert the supplied source object into an instance of the specified
5353
* target type.
5454
*
5555
* @param source the source object to convert; may be {@code null} but only
5656
* if the target type is a reference type
57-
* @param targetType the target type the source should be converted into;
57+
* @param targetType the descriptor of the type the source should be converted into;
5858
* never {@code null}
5959
* @param classLoader the {@code ClassLoader} to use; never {@code null}
6060
* @return the converted object; may be {@code null} but only if the target
6161
* type is a reference type
6262
* @throws ConversionException if an error occurs during the conversion
6363
*/
64-
Object convert(Object source, Class<?> targetType, ClassLoader classLoader) throws ConversionException;
64+
Object convert(Object source, TypeDescriptor targetType, ClassLoader classLoader) throws ConversionException;
6565

6666
}

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ private DefaultConverter() {
7777
* @return {@code true} if the supplied source can be converted
7878
*/
7979
@Override
80-
public boolean canConvert(Object source, Class<?> targetType, ClassLoader classLoader) {
80+
public boolean canConvert(Object source, TypeDescriptor targetType, ClassLoader classLoader) {
8181
if (source == null) {
8282
return !targetType.isPrimitive();
8383
}
@@ -86,12 +86,12 @@ public boolean canConvert(Object source, Class<?> targetType, ClassLoader classL
8686
return false;
8787
}
8888

89-
if (String.class.equals(targetType)) {
89+
if (String.class.equals(targetType.getType())) {
9090
return true;
9191
}
9292

9393
return stringToObjectConverters.stream().anyMatch(
94-
candidate -> candidate.canConvertTo(toWrapperType(targetType)));
94+
candidate -> candidate.canConvertTo(toWrapperType(targetType.getType())));
9595
}
9696

9797
/**
@@ -145,20 +145,20 @@ public boolean canConvert(Object source, Class<?> targetType, ClassLoader classL
145145
* @throws ConversionException if an error occurs during the conversion
146146
*/
147147
@Override
148-
public Object convert(Object source, Class<?> targetType, ClassLoader classLoader) {
148+
public Object convert(Object source, TypeDescriptor targetType, ClassLoader classLoader) {
149149
if (source == null) {
150150
if (targetType.isPrimitive()) {
151151
throw new ConversionException(
152-
"Cannot convert null to primitive value of type " + targetType.getTypeName());
152+
"Cannot convert null to primitive value of type " + targetType.getType().getTypeName());
153153
}
154154
return null;
155155
}
156156

157-
if (String.class.equals(targetType)) {
157+
if (String.class.equals(targetType.getType())) {
158158
return source;
159159
}
160160

161-
Class<?> targetTypeToUse = toWrapperType(targetType);
161+
Class<?> targetTypeToUse = toWrapperType(targetType.getType());
162162
Optional<StringToObjectConverter> converter = stringToObjectConverters.stream().filter(
163163
candidate -> candidate.canConvertTo(targetTypeToUse)).findFirst();
164164
if (converter.isPresent()) {
@@ -171,13 +171,13 @@ public Object convert(Object source, Class<?> targetType, ClassLoader classLoade
171171
throw (ConversionException) ex;
172172
}
173173
// else
174-
throw new ConversionException(
175-
String.format("Failed to convert String \"%s\" to type %s", source, targetType.getTypeName()), ex);
174+
throw new ConversionException(String.format("Failed to convert String \"%s\" to type %s", source,
175+
targetType.getType().getTypeName()), ex);
176176
}
177177
}
178178

179-
throw new ConversionException(
180-
"No built-in converter for source type java.lang.String and target type " + targetType.getTypeName());
179+
throw new ConversionException("No built-in converter for source type java.lang.String and target type "
180+
+ targetType.getType().getTypeName());
181181
}
182182

183183
private static Class<?> toWrapperType(Class<?> targetType) {
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2015-2025 the original author or authors.
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License v2.0 which
6+
* accompanies this distribution and is available at
7+
*
8+
* https://www.eclipse.org/legal/epl-v20.html
9+
*/
10+
11+
package org.junit.platform.commons.support.conversion;
12+
13+
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
14+
15+
import java.lang.reflect.Field;
16+
import java.lang.reflect.Parameter;
17+
18+
import org.apiguardian.api.API;
19+
20+
/**
21+
*
22+
*
23+
* @since 1.13
24+
*/
25+
@API(status = EXPERIMENTAL, since = "1.13")
26+
public final class TypeDescriptor {
27+
28+
private final Class<?> type;
29+
30+
public static TypeDescriptor forType(Class<?> type) {
31+
return new TypeDescriptor(type);
32+
}
33+
34+
public static TypeDescriptor forField(Field field) {
35+
return new TypeDescriptor(field.getType());
36+
}
37+
38+
public static TypeDescriptor forParameter(Parameter parameter) {
39+
return new TypeDescriptor(parameter.getType());
40+
}
41+
42+
private TypeDescriptor(Class<?> type) {
43+
this.type = type;
44+
}
45+
46+
public Class<?> getType() {
47+
return type;
48+
}
49+
50+
public boolean isPrimitive() {
51+
return getType().isPrimitive();
52+
}
53+
54+
@Override
55+
public boolean equals(Object o) {
56+
if (this == o) {
57+
return true;
58+
}
59+
if (o == null || getClass() != o.getClass()) {
60+
return false;
61+
}
62+
TypeDescriptor that = (TypeDescriptor) o;
63+
return this.type.equals(that.type);
64+
}
65+
66+
@Override
67+
public int hashCode() {
68+
return this.type.hashCode();
69+
}
70+
71+
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@ protected TypedConverter(Class<S> sourceType, Class<T> targetType) {
4444
}
4545

4646
@Override
47-
public final boolean canConvert(Object source, Class<?> targetType, ClassLoader classLoader) {
48-
return sourceType.isInstance(source) && ReflectionUtils.isAssignableTo(this.targetType, targetType);
47+
public final boolean canConvert(Object source, TypeDescriptor targetType, ClassLoader classLoader) {
48+
return this.sourceType.isInstance(source)
49+
&& ReflectionUtils.isAssignableTo(this.targetType, targetType.getType());
4950
}
5051

5152
@Override
52-
public final Object convert(Object source, Class<?> targetType, ClassLoader classLoader) {
53+
public final Object convert(Object source, TypeDescriptor targetType, ClassLoader classLoader) {
5354
return source == null ? convert(null) : convert(this.sourceType.cast(source));
5455
}
5556

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.junit.jupiter.params.provider.ValueSource;
3636
import org.junit.platform.commons.support.ReflectionSupport;
3737
import org.junit.platform.commons.support.conversion.ConversionException;
38+
import org.junit.platform.commons.support.conversion.TypeDescriptor;
3839
import org.junit.platform.commons.test.TestClassLoader;
3940
import org.junit.platform.commons.util.ClassLoaderUtils;
4041

@@ -98,7 +99,8 @@ void delegatesStringsConversion() {
9899

99100
convert("value", int.class);
100101

101-
verify(underTest).delegateConversion("value", int.class, getClassLoader(DefaultArgumentConverterTests.class));
102+
verify(underTest).delegateConversion("value", TypeDescriptor.forType(int.class),
103+
getClassLoader(DefaultArgumentConverterTests.class));
102104
}
103105

104106
@Test
@@ -128,7 +130,8 @@ void delegatesLocaleConversionWithExplicitIso639Format() {
128130

129131
convert("en", Locale.class);
130132

131-
verify(underTest).convert("en", Locale.class, getClassLoader(DefaultArgumentConverterTests.class));
133+
verify(underTest).convert("en", TypeDescriptor.forType(Locale.class),
134+
getClassLoader(DefaultArgumentConverterTests.class));
132135
}
133136

134137
@Test
@@ -141,7 +144,8 @@ void throwsExceptionForDelegatedConversionFailure() {
141144
.withCause(exception) //
142145
.withMessage(exception.getMessage());
143146

144-
verify(underTest).delegateConversion("value", int.class, getClassLoader(DefaultArgumentConverterTests.class));
147+
verify(underTest).delegateConversion("value", TypeDescriptor.forType(int.class),
148+
getClassLoader(DefaultArgumentConverterTests.class));
145149
}
146150

147151
@Test
@@ -161,7 +165,7 @@ void delegatesStringToClassWithCustomTypeFromDifferentClassLoaderConversion() th
161165
assertThat(clazz).isEqualTo(customType);
162166
assertThat(clazz.getClassLoader()).isSameAs(testClassLoader);
163167

164-
verify(underTest).delegateConversion(customTypeName, Class.class, testClassLoader);
168+
verify(underTest).delegateConversion(customTypeName, TypeDescriptor.forType(Class.class), testClassLoader);
165169
}
166170
}
167171

@@ -182,7 +186,7 @@ private Object convert(Object input, Class<?> targetClass) {
182186
}
183187

184188
private Object convert(Object input, Class<?> targetClass, ClassLoader classLoader) {
185-
return underTest.convert(input, targetClass, classLoader);
189+
return underTest.convert(input, TypeDescriptor.forType(targetClass), classLoader);
186190
}
187191

188192
@SuppressWarnings("unused")

0 commit comments

Comments
 (0)