Skip to content

Commit 19c701d

Browse files
authored
Renamed EncodedValue to EncodedValues to support multiple details (#164)
1 parent 8b460ac commit 19c701d

26 files changed

+220
-187
lines changed

src/main/java/io/temporal/common/converter/DataConverter.java

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919

2020
package io.temporal.common.converter;
2121

22+
import com.google.common.base.Defaults;
2223
import io.temporal.api.common.v1.Payload;
2324
import io.temporal.api.common.v1.Payloads;
2425
import java.lang.reflect.Type;
26+
import java.util.Arrays;
2527
import java.util.Optional;
2628

2729
/**
@@ -51,30 +53,57 @@ static DataConverter getDefaultInstance() {
5153
Optional<Payloads> toPayloads(Object... values) throws DataConverterException;
5254

5355
/**
54-
* Implements conversion of a single value.
56+
* Implements conversion of an array of values of different types. Useful for deserializing
57+
* arguments of function invocations.
5558
*
56-
* @param content Serialized value to convert to a Java object.
59+
* @param index index of the value in the payloads
60+
* @param content serialized value to convert to Java objects.
5761
* @param parameterType type of the parameter stored in the content
5862
* @param genericParameterType generic type of the parameter stored in the content
5963
* @return converted Java object
6064
* @throws DataConverterException if conversion of the data passed as parameter failed for any
6165
* reason.
6266
*/
63-
<T> T fromPayloads(Optional<Payloads> content, Class<T> parameterType, Type genericParameterType)
67+
<T> T fromPayloads(
68+
int index, Optional<Payloads> content, Class<T> parameterType, Type genericParameterType)
6469
throws DataConverterException;
6570

66-
/**
67-
* Implements conversion of an array of values of different types. Useful for deserializing
68-
* arguments of function invocations.
69-
*
70-
* @param content serialized value to convert to Java objects.
71-
* @param parameterTypes types of the parameters stored in the content
72-
* @param genericParameterTypes generic types of the parameters stored in the content
73-
* @return array of converted Java objects
74-
* @throws DataConverterException if conversion of the data passed as parameter failed for any
75-
* reason.
76-
*/
77-
Object[] arrayFromPayloads(
78-
Optional<Payloads> content, Class<?>[] parameterTypes, Type[] genericParameterTypes)
79-
throws DataConverterException;
71+
static Object[] arrayFromPayloads(
72+
DataConverter converter,
73+
Optional<Payloads> content,
74+
Class<?>[] parameterTypes,
75+
Type[] genericParameterTypes)
76+
throws DataConverterException {
77+
if (parameterTypes != null
78+
&& (genericParameterTypes == null
79+
|| parameterTypes.length != genericParameterTypes.length)) {
80+
throw new IllegalArgumentException(
81+
"parameterTypes don't match length of valueTypes: "
82+
+ Arrays.toString(parameterTypes)
83+
+ "<>"
84+
+ Arrays.toString(genericParameterTypes));
85+
}
86+
87+
int length = parameterTypes.length;
88+
Object[] result = new Object[length];
89+
if (!content.isPresent()) {
90+
// Return defaults for all the parameters
91+
for (int i = 0; i < parameterTypes.length; i++) {
92+
result[i] = Defaults.defaultValue((Class<?>) genericParameterTypes[i]);
93+
}
94+
return result;
95+
}
96+
Payloads payloads = content.get();
97+
int count = payloads.getPayloadsCount();
98+
for (int i = 0; i < parameterTypes.length; i++) {
99+
Class<?> pt = parameterTypes[i];
100+
Type gt = genericParameterTypes[i];
101+
if (i >= count) {
102+
result[i] = Defaults.defaultValue((Class<?>) gt);
103+
} else {
104+
result[i] = converter.fromPayload(payloads.getPayloads(i), pt, gt);
105+
}
106+
}
107+
return result;
108+
}
80109
}

src/main/java/io/temporal/common/converter/DefaultDataConverter.java

Lines changed: 8 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import io.temporal.api.common.v1.Payloads;
2727
import java.lang.reflect.Type;
2828
import java.util.ArrayList;
29-
import java.util.Arrays;
3029
import java.util.List;
3130
import java.util.Map;
3231
import java.util.Optional;
@@ -142,60 +141,17 @@ public Optional<Payloads> toPayloads(Object... values) throws DataConverterExcep
142141
}
143142

144143
@Override
145-
public <T> T fromPayloads(Optional<Payloads> content, Class<T> valueClass, Type valueType)
144+
public <T> T fromPayloads(
145+
int index, Optional<Payloads> content, Class<T> parameterType, Type genericParameterType)
146146
throws DataConverterException {
147147
if (!content.isPresent()) {
148-
return null;
148+
return (T) Defaults.defaultValue((Class<?>) parameterType);
149149
}
150-
Payloads c = content.get();
151-
if (c.getPayloadsCount() == 0) {
152-
return null;
153-
}
154-
if (c.getPayloadsCount() != 1) {
155-
throw new DataConverterException(
156-
"Found multiple payloads while a single one expected", content, valueType);
157-
}
158-
return fromPayload(c.getPayloads(0), valueClass, valueType);
159-
}
160-
161-
@Override
162-
public Object[] arrayFromPayloads(
163-
Optional<Payloads> content, Class<?>[] parameterTypes, Type[] valueTypes)
164-
throws DataConverterException {
165-
try {
166-
if (parameterTypes != null
167-
&& (valueTypes == null || parameterTypes.length != valueTypes.length)) {
168-
throw new IllegalArgumentException(
169-
"parameterTypes don't match length of valueTypes: "
170-
+ Arrays.toString(parameterTypes)
171-
+ "<>"
172-
+ Arrays.toString(valueTypes));
173-
}
174-
if (!content.isPresent()) {
175-
if (valueTypes.length == 0) {
176-
return EMPTY_OBJECT_ARRAY;
177-
} else {
178-
throw new DataConverterException("Empty content", content, valueTypes);
179-
}
180-
}
181-
Payloads c = content.get();
182-
int count = c.getPayloadsCount();
183-
int length = valueTypes.length;
184-
Object[] result = new Object[length];
185-
for (int i = 0; i < length; i++) {
186-
Type vt = valueTypes[i];
187-
Class<?> pt = parameterTypes[i];
188-
if (i >= count) {
189-
result[i] = Defaults.defaultValue((Class<?>) vt);
190-
} else {
191-
result[i] = fromPayload(c.getPayloads(i), pt, vt);
192-
}
193-
}
194-
return result;
195-
} catch (DataConverterException e) {
196-
throw e;
197-
} catch (Throwable e) {
198-
throw new DataConverterException(e);
150+
int count = content.get().getPayloadsCount();
151+
// To make adding arguments a backwards compatible change
152+
if (index >= count) {
153+
return (T) Defaults.defaultValue((Class<?>) parameterType);
199154
}
155+
return fromPayload(content.get().getPayloads(index), parameterType, genericParameterType);
200156
}
201157
}

src/main/java/io/temporal/common/converter/EncodedValue.java renamed to src/main/java/io/temporal/common/converter/EncodedValues.java

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,30 @@
2424
import java.util.Objects;
2525
import java.util.Optional;
2626

27-
public final class EncodedValue implements Value {
27+
public final class EncodedValues implements Values {
2828
private Optional<Payloads> payloads;
2929
private DataConverter converter;
30-
private final Optional<Object> value;
30+
private Object[] values;
3131

32-
public EncodedValue(Optional<Payloads> payloads, DataConverter converter) {
32+
public EncodedValues(Optional<Payloads> payloads, DataConverter converter) {
3333
this.payloads = Objects.requireNonNull(payloads);
3434
this.converter = converter;
35-
this.value = null;
35+
this.values = null;
3636
}
3737

38-
public <T> EncodedValue(T value) {
39-
this.value = Optional.ofNullable(value);
38+
public EncodedValues(Object... values) {
39+
this.values = values;
4040
this.payloads = null;
4141
}
4242

4343
public Optional<Payloads> toPayloads() {
4444
if (payloads == null) {
45-
if (!value.isPresent()) {
45+
if (values == null || values.length == 0) {
4646
payloads = Optional.empty();
4747
} else if (converter == null) {
4848
throw new IllegalStateException("converter not set");
4949
} else {
50-
payloads = converter.toPayloads(value.get());
50+
payloads = converter.toPayloads(values);
5151
}
5252
}
5353
return payloads;
@@ -58,22 +58,35 @@ public void setDataConverter(DataConverter converter) {
5858
}
5959

6060
@Override
61-
public <T> T get(Class<T> parameterType) throws DataConverterException {
62-
if (value != null) {
63-
@SuppressWarnings("unchecked")
64-
T result = (T) value.orElse(null);
65-
return result;
61+
public int getSize() {
62+
if (values != null) {
63+
return values.length;
6664
} else {
67-
if (converter == null) {
68-
throw new IllegalStateException("converter not set");
65+
if (payloads.isPresent()) {
66+
return payloads.get().getPayloadsCount();
67+
} else {
68+
return 0;
6969
}
70-
return converter.fromPayloads(payloads, parameterType, parameterType);
7170
}
7271
}
7372

7473
@Override
75-
public <T> T get(Class<T> parameterType, Type genericParameterType)
74+
public <T> T get(int index, Class<T> parameterType) throws DataConverterException {
75+
return get(index, parameterType, parameterType);
76+
}
77+
78+
@Override
79+
public <T> T get(int index, Class<T> parameterType, Type genericParameterType)
7680
throws DataConverterException {
77-
return converter.fromPayloads(payloads, parameterType, genericParameterType);
81+
if (values != null) {
82+
@SuppressWarnings("unchecked")
83+
T result = (T) values[index];
84+
return result;
85+
} else {
86+
if (converter == null) {
87+
throw new IllegalStateException("converter not set");
88+
}
89+
return converter.fromPayloads(index, payloads, parameterType, genericParameterType);
90+
}
7891
}
7992
}

src/main/java/io/temporal/common/converter/Value.java renamed to src/main/java/io/temporal/common/converter/Values.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,31 @@
2222
import java.lang.reflect.Type;
2323

2424
/** Value that can be extracted to an appropriate type. */
25-
public interface Value {
25+
public interface Values {
26+
27+
int getSize();
28+
29+
/** The same as {@link #get(int, Class)} with 0 index. */
30+
default <T> T get(Class<T> parameterType) throws DataConverterException {
31+
return get(0, parameterType);
32+
}
2633

2734
/**
2835
* Get value of the specified type.
2936
*
37+
* @param index index of the value in the list of values.
3038
* @param parameterType class of the value to get
3139
* @param <T> type of the value to get
3240
* @return value or null
3341
* @throws DataConverterException if value cannot be extracted to the given type
3442
*/
35-
<T> T get(Class<T> parameterType) throws DataConverterException;
43+
<T> T get(int index, Class<T> parameterType) throws DataConverterException;
44+
45+
/** The same as {@link #get(int, Class, Type)} with 0 index. */
46+
default <T> T get(Class<T> parameterType, Type genericParameterType)
47+
throws DataConverterException {
48+
return get(0, parameterType, genericParameterType);
49+
}
3650

3751
/**
3852
* Get value of the specified generic type. For example if value is of type List<MyClass> use the
@@ -43,11 +57,13 @@ public interface Value {
4357
* List&lt;MyClass&gt; result = value.get(List.class, typeToken.getType());
4458
* </code></pre>
4559
*
60+
* @param index index of the value in the list of values.
4661
* @param parameterType class of the value to get
4762
* @param genericParameterType the type of the value to get
4863
* @param <T> type of the value to get
4964
* @return value or null
5065
* @throws DataConverterException if value cannot be extracted to the given type
5166
*/
52-
<T> T get(Class<T> parameterType, Type genericParameterType) throws DataConverterException;
67+
<T> T get(int index, Class<T> parameterType, Type genericParameterType)
68+
throws DataConverterException;
5369
}

src/main/java/io/temporal/failure/ApplicationFailure.java

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121

2222
import com.google.common.base.Strings;
2323
import io.temporal.common.converter.DataConverter;
24-
import io.temporal.common.converter.EncodedValue;
25-
import io.temporal.common.converter.Value;
24+
import io.temporal.common.converter.EncodedValues;
25+
import io.temporal.common.converter.Values;
2626

2727
/**
2828
* Application failure is used to communicate application specific failures between workflows and
@@ -51,49 +51,47 @@
5151
*/
5252
public final class ApplicationFailure extends TemporalFailure {
5353
private final String type;
54-
private final Value details;
54+
private final Values details;
5555
private boolean nonRetryable;
5656

5757
/**
58+
* New ApplicationFailure with {@link #isNonRetryable()} flag set to false. Note that this
59+
* exception still can be not retried by the service if its type is included into doNotRetry
60+
* property of the correspondent retry policy.
61+
*
5862
* @param message optional error message
5963
* @param type optional error type that is used by {@link
6064
* io.temporal.common.RetryOptions#addDoNotRetry(String...)}.
6165
* @param details optional details about the failure. They are serialized using the same approach
62-
* as arguments and results and can be accessed through {@link #getDetails()}
63-
* @param cause failure cause. Each element of the cause chain is converted to ApplicationFailure
64-
* if it doesn't extend {@link TemporalFailure}.
66+
* as arguments and results.
6567
*/
66-
public ApplicationFailure(String message, String type, Object details, Exception cause) {
67-
this(message, type, new EncodedValue(details), false, cause);
68+
public static ApplicationFailure newFailure(String message, String type, Object... details) {
69+
return new ApplicationFailure(message, type, false, new EncodedValues(details), null);
6870
}
6971

7072
/**
73+
* New ApplicationFailure with {@link #isNonRetryable()} flag set to true.
74+
*
75+
* <p>It means that this exception is not going to be retried even if it is not included into
76+
* retry policy doNotRetry list.
77+
*
7178
* @param message optional error message
72-
* @param type optional error type that is used by {@link
73-
* io.temporal.common.RetryOptions#addDoNotRetry(String...)}.
79+
* @param type optional error type
7480
* @param details optional details about the failure. They are serialized using the same approach
7581
* as arguments and results.
7682
*/
77-
public ApplicationFailure(String message, String type, Object details) {
78-
this(message, type, new EncodedValue(details), false, null);
79-
}
80-
81-
/**
82-
* @param message optional error message
83-
* @param type optional error type that is used by {@link
84-
* io.temporal.common.RetryOptions#addDoNotRetry(String...)}.
85-
*/
86-
public ApplicationFailure(String message, String type) {
87-
this(message, type, new EncodedValue(null), false, null);
83+
public static ApplicationFailure newNonRetryableFailure(
84+
String message, String type, Object... details) {
85+
return new ApplicationFailure(message, type, true, new EncodedValues(details), null);
8886
}
8987

90-
/** * @param message optional error message */
91-
public ApplicationFailure(String message) {
92-
this(message, null);
88+
static ApplicationFailure newFromValues(
89+
String message, String type, boolean nonRetryable, Values details, Throwable cause) {
90+
return new ApplicationFailure(message, type, nonRetryable, details, cause);
9391
}
9492

9593
ApplicationFailure(
96-
String message, String type, Value details, boolean nonRetryable, Exception cause) {
94+
String message, String type, boolean nonRetryable, Values details, Throwable cause) {
9795
super(getMessage(message, type, nonRetryable), message, cause);
9896
this.type = type;
9997
this.details = details;
@@ -104,7 +102,7 @@ public String getType() {
104102
return type;
105103
}
106104

107-
public Value getDetails() {
105+
public Values getDetails() {
108106
return details;
109107
}
110108

@@ -118,7 +116,7 @@ public boolean isNonRetryable() {
118116

119117
@Override
120118
public void setDataConverter(DataConverter converter) {
121-
((EncodedValue) details).setDataConverter(converter);
119+
((EncodedValues) details).setDataConverter(converter);
122120
}
123121

124122
private static String getMessage(String message, String type, boolean nonRetryable) {

0 commit comments

Comments
 (0)