-
Notifications
You must be signed in to change notification settings - Fork 169
Add support for parameterized and generic types in DataConverter (#2413) #2605
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d7915e1
b75d234
57dba0d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,9 @@ | |
import io.temporal.failure.DefaultFailureConverter; | ||
import io.temporal.payload.codec.PayloadCodec; | ||
import io.temporal.payload.context.SerializationContext; | ||
import java.lang.reflect.Array; | ||
import java.lang.reflect.GenericArrayType; | ||
import java.lang.reflect.ParameterizedType; | ||
import java.lang.reflect.Type; | ||
import java.util.Arrays; | ||
import java.util.Optional; | ||
|
@@ -132,7 +135,7 @@ default Object[] fromPayloads( | |
if (!content.isPresent()) { | ||
// Return defaults for all the parameters | ||
for (int i = 0; i < parameterTypes.length; i++) { | ||
result[i] = Defaults.defaultValue((Class<?>) genericParameterTypes[i]); | ||
result[i] = Defaults.defaultValue(getRawClass(genericParameterTypes[i])); | ||
} | ||
return result; | ||
} | ||
|
@@ -142,7 +145,7 @@ default Object[] fromPayloads( | |
Class<?> pt = parameterTypes[i]; | ||
Type gt = genericParameterTypes[i]; | ||
if (i >= count) { | ||
result[i] = Defaults.defaultValue((Class<?>) gt); | ||
result[i] = Defaults.defaultValue(getRawClass(gt)); | ||
} else { | ||
result[i] = this.fromPayload(payloads.getPayloads(i), pt, gt); | ||
} | ||
|
@@ -214,4 +217,25 @@ static Object[] arrayFromPayloads( | |
throws DataConverterException { | ||
return converter.fromPayloads(content, parameterTypes, genericParameterTypes); | ||
} | ||
|
||
/** | ||
* Extract the raw Class from a Type; handles regular classes, parameterized types, and generic | ||
* array types. | ||
* | ||
* @param type the Type to extract from (could be Class, ParameterizedType, or GenericArrayType) | ||
* @return the raw Class for the type | ||
*/ | ||
static Class<?> getRawClass(Type type) { | ||
if (type instanceof Class) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to handle any other There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch regarding |
||
return (Class<?>) type; | ||
} else if (type instanceof ParameterizedType) { | ||
return (Class<?>) ((ParameterizedType) type).getRawType(); | ||
} else if (type instanceof GenericArrayType) { | ||
Type componentType = ((GenericArrayType) type).getGenericComponentType(); | ||
Class<?> componentClass = getRawClass(componentType); | ||
return Array.newInstance(componentClass, 0).getClass(); | ||
} else { | ||
return Object.class; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package io.temporal.common.converter; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertNull; | ||
import static org.junit.Assert.assertTrue; | ||
|
||
import io.temporal.api.common.v1.Payloads; | ||
import java.lang.reflect.GenericArrayType; | ||
import java.lang.reflect.Method; | ||
import java.lang.reflect.ParameterizedType; | ||
import java.lang.reflect.Type; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import org.junit.Test; | ||
|
||
public class DataConverterGenericTypeTest { | ||
|
||
@Test | ||
public void testFromPayloadsWithGenericListParameter() throws Exception { | ||
DataConverter dataConverter = DefaultDataConverter.newDefaultInstance(); | ||
Method method = TestInterface.class.getMethod("processData", String.class, List.class); | ||
Optional<Payloads> payloads = dataConverter.toPayloads("test-data"); | ||
|
||
Object[] args = | ||
dataConverter.fromPayloads( | ||
payloads, method.getParameterTypes(), method.getGenericParameterTypes()); | ||
|
||
assertEquals(2, args.length); | ||
assertEquals("test-data", args[0]); | ||
assertNull(args[1]); | ||
} | ||
|
||
@Test | ||
public void testFromPayloadsWithEmptyPayloads() throws Exception { | ||
DataConverter dataConverter = DefaultDataConverter.newDefaultInstance(); | ||
Method method = TestInterface.class.getMethod("processData", String.class, List.class); | ||
Object[] args = | ||
dataConverter.fromPayloads( | ||
Optional.empty(), method.getParameterTypes(), method.getGenericParameterTypes()); | ||
|
||
assertEquals(2, args.length); | ||
assertNull(args[0]); | ||
assertNull(args[1]); | ||
} | ||
|
||
@Test | ||
public void testGetRawClassWithGenericArrayType() throws Exception { | ||
Method method = TestInterface.class.getMethod("processGenericArray", Object[].class); | ||
Type[] genericParameterTypes = method.getGenericParameterTypes(); | ||
Type genericArrayType = genericParameterTypes[0]; | ||
|
||
assertTrue("Expected GenericArrayType instance", genericArrayType instanceof GenericArrayType); | ||
|
||
Class<?> rawClass = DataConverter.getRawClass(genericArrayType); | ||
assertEquals(Object[].class, rawClass); | ||
} | ||
|
||
@Test | ||
public void testGetRawClassWithParameterizedType() throws Exception { | ||
Method method = TestInterface.class.getMethod("processData", String.class, List.class); | ||
Type[] genericParameterTypes = method.getGenericParameterTypes(); | ||
Type parameterizedType = genericParameterTypes[1]; | ||
|
||
assertTrue( | ||
"Expected ParameterizedType instance", parameterizedType instanceof ParameterizedType); | ||
|
||
Class<?> rawClass = DataConverter.getRawClass(parameterizedType); | ||
assertEquals(List.class, rawClass); | ||
} | ||
|
||
@Test | ||
public void testGetRawClassWithRegularClass() { | ||
Class<?> rawClass = DataConverter.getRawClass(String.class); | ||
assertEquals(String.class, rawClass); | ||
} | ||
|
||
@Test | ||
public void testGetRawClassWithUnsupportedType() { | ||
Type unsupportedType = new Type() {}; | ||
Class<?> rawClass = DataConverter.getRawClass(unsupportedType); | ||
assertEquals(Object.class, rawClass); | ||
} | ||
|
||
public interface TestInterface { | ||
void processData(String data, List<String> items); | ||
|
||
<T> void processGenericArray(T[] items); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also don't shouldn't expose this on the data converter interface, this is an implementation detail and should not be part of the public API