Skip to content

Commit b205cd8

Browse files
andimarekbbakerman
authored andcommitted
throw dedicated exceptions for serialize and parseValue
handle serialize exception in ExecutionStrategy
1 parent 7675da7 commit b205cd8

18 files changed

Lines changed: 548 additions & 208 deletions

src/main/java/graphql/Scalars.java

Lines changed: 194 additions & 53 deletions
Large diffs are not rendered by default.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package graphql;
2+
3+
4+
import graphql.language.SourceLocation;
5+
import graphql.schema.CoercingSerializeException;
6+
7+
import java.util.List;
8+
9+
@PublicApi
10+
public class SerializationError implements GraphQLError {
11+
12+
private final CoercingSerializeException exception;
13+
14+
public SerializationError(CoercingSerializeException exception) {
15+
this.exception = exception;
16+
}
17+
18+
public CoercingSerializeException getException() {
19+
return exception;
20+
}
21+
22+
23+
@Override
24+
public String getMessage() {
25+
return "Can't serialize value: " + exception.getMessage();
26+
}
27+
28+
@Override
29+
public List<SourceLocation> getLocations() {
30+
return null;
31+
}
32+
33+
@Override
34+
public ErrorType getErrorType() {
35+
return ErrorType.DataFetchingException;
36+
}
37+
38+
@Override
39+
public String toString() {
40+
return "ExceptionWhileDataFetching{" +
41+
"exception=" + exception +
42+
'}';
43+
}
44+
45+
@Override
46+
public boolean equals(Object o) {
47+
return Helper.equals(this, o);
48+
}
49+
50+
@Override
51+
public int hashCode() {
52+
return Helper.hashCode(this);
53+
}
54+
}

src/main/java/graphql/execution/ExecutionStrategy.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
import graphql.ExecutionResultImpl;
66
import graphql.GraphQLException;
77
import graphql.PublicSpi;
8+
import graphql.SerializationError;
89
import graphql.TypeResolutionEnvironment;
910
import graphql.execution.instrumentation.Instrumentation;
1011
import graphql.execution.instrumentation.InstrumentationContext;
1112
import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters;
1213
import graphql.execution.instrumentation.parameters.InstrumentationFieldParameters;
1314
import graphql.language.Field;
15+
import graphql.schema.CoercingSerializeException;
1416
import graphql.schema.DataFetcher;
1517
import graphql.schema.DataFetchingEnvironment;
1618
import graphql.schema.DataFetchingEnvironmentImpl;
@@ -141,7 +143,7 @@ protected ExecutionResult completeValue(ExecutionContext executionContext, Execu
141143
} else if (fieldType instanceof GraphQLList) {
142144
return completeValueForList(executionContext, parameters, fields, toIterable(result));
143145
} else if (fieldType instanceof GraphQLScalarType) {
144-
return completeValueForScalar((GraphQLScalarType) fieldType, parameters, result);
146+
return completeValueForScalar((GraphQLScalarType) fieldType, parameters, result, executionContext);
145147
} else if (fieldType instanceof GraphQLEnumType) {
146148
return completeValueForEnum((GraphQLEnumType) fieldType, parameters, result);
147149
}
@@ -225,8 +227,16 @@ protected ExecutionResult completeValueForEnum(GraphQLEnumType enumType, Executi
225227
return new ExecutionResultImpl(serialized, null);
226228
}
227229

228-
protected ExecutionResult completeValueForScalar(GraphQLScalarType scalarType, ExecutionStrategyParameters parameters, Object result) {
229-
Object serialized = scalarType.getCoercing().serialize(result);
230+
protected ExecutionResult completeValueForScalar(GraphQLScalarType scalarType, ExecutionStrategyParameters parameters, Object result, ExecutionContext context) {
231+
Object serialized;
232+
try {
233+
serialized = scalarType.getCoercing().serialize(result);
234+
} catch (CoercingSerializeException e) {
235+
serialized = null;
236+
context.addError(new SerializationError(e));
237+
}
238+
239+
// TODO: fix that: this should not be handled here
230240
//6.6.1 http://facebook.github.io/graphql/#sec-Field-entries
231241
if (serialized instanceof Double && ((Double) serialized).isNaN()) {
232242
serialized = null;

src/main/java/graphql/schema/Coercing.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,23 @@ public interface Coercing<I, O> {
1010
/**
1111
* Called to convert a result of a DataFetcher to a valid runtime value.
1212
*
13-
* @param input is never null
13+
* @param dataFetcherResult is never null
1414
* @return never null
15-
* @throws graphql.GraphQLException if value input can't be serialized
15+
* @throws graphql.schema.CoercingSerializeException if value input can't be serialized
1616
*/
17-
O serialize(Object input);
17+
O serialize(Object dataFetcherResult);
1818

1919
/**
2020
* Called to resolve a input from a variable.
21-
* Null if not possible.
2221
*
2322
* @param input is never null
2423
* @return never null
25-
* @throws graphql.GraphQLException if value input can't be serialized
24+
* @throws graphql.schema.CoercingParseValueException if value input can't be parsed
2625
*/
2726
I parseValue(Object input);
2827

2928
/**
30-
* Called to convert a AST node
29+
* Called to convert an input AST node
3130
*
3231
* @param input is never null
3332
* @return A null value indicates that the literal is not valid. See {@link graphql.validation.ValidationUtil#isValidLiteralValue}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package graphql.schema;
2+
3+
import graphql.GraphQLException;
4+
5+
public class CoercingParseValueException extends GraphQLException {
6+
7+
public CoercingParseValueException() {
8+
}
9+
10+
public CoercingParseValueException(String message) {
11+
super(message);
12+
}
13+
14+
public CoercingParseValueException(String message, Throwable cause) {
15+
super(message, cause);
16+
}
17+
18+
public CoercingParseValueException(Throwable cause) {
19+
super(cause);
20+
}
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package graphql.schema;
2+
3+
import graphql.GraphQLException;
4+
5+
public class CoercingSerializeException extends GraphQLException {
6+
7+
public CoercingSerializeException() {
8+
}
9+
10+
public CoercingSerializeException(String message) {
11+
super(message);
12+
}
13+
14+
public CoercingSerializeException(String message, Throwable cause) {
15+
super(message, cause);
16+
}
17+
18+
public CoercingSerializeException(Throwable cause) {
19+
super(cause);
20+
}
21+
}

src/test/groovy/graphql/ScalarsBigDecimalTest.groovy

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import graphql.language.BooleanValue
44
import graphql.language.FloatValue
55
import graphql.language.IntValue
66
import graphql.language.StringValue
7+
import graphql.schema.CoercingParseValueException
8+
import graphql.schema.CoercingSerializeException
79
import spock.lang.Specification
810
import spock.lang.Unroll
911

@@ -59,20 +61,11 @@ class ScalarsBigDecimalTest extends Specification {
5961
}
6062

6163
@Unroll
62-
def "serialize/parseValue throws exception for invalid input #value"() {
63-
expect:
64-
try {
65-
Scalars.GraphQLBigDecimal.getCoercing().serialize(value)
66-
assert false: "no exception thrown"
67-
} catch (GraphQLException e) {
68-
// expected
69-
}
70-
try {
71-
Scalars.GraphQLBigDecimal.getCoercing().parseValue(value)
72-
assert false: "no exception thrown"
73-
} catch (GraphQLException e) {
74-
// expected
75-
}
64+
def "serialize throws exception for invalid input #value"() {
65+
when:
66+
Scalars.GraphQLBigDecimal.getCoercing().serialize(value)
67+
then:
68+
thrown(CoercingSerializeException)
7669

7770
where:
7871
value | _
@@ -81,5 +74,18 @@ class ScalarsBigDecimalTest extends Specification {
8174
new Object() | _
8275
}
8376

77+
@Unroll
78+
def "parseValue throws exception for invalid input #value"() {
79+
when:
80+
Scalars.GraphQLBigDecimal.getCoercing().parseValue(value)
81+
then:
82+
thrown(CoercingParseValueException)
83+
84+
where:
85+
value | _
86+
"" | _
87+
"not a number " | _
88+
new Object() | _
89+
}
8490

8591
}

src/test/groovy/graphql/ScalarsBigIntegerTest.groovy

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import graphql.language.BooleanValue
44
import graphql.language.FloatValue
55
import graphql.language.IntValue
66
import graphql.language.StringValue
7+
import graphql.schema.CoercingParseValueException
8+
import graphql.schema.CoercingSerializeException
79
import spock.lang.Specification
810
import spock.lang.Unroll
911

@@ -56,20 +58,11 @@ class ScalarsBigIntegerTest extends Specification {
5658
}
5759

5860
@Unroll
59-
def "serialize/parseValue throws exception for invalid input #value"() {
60-
expect:
61-
try {
62-
Scalars.GraphQLBigInteger.getCoercing().serialize(value)
63-
assert false: "no exception thrown"
64-
} catch (GraphQLException e) {
65-
// expected
66-
}
67-
try {
68-
Scalars.GraphQLBigInteger.getCoercing().parseValue(value)
69-
assert false: "no exception thrown"
70-
} catch (GraphQLException e) {
71-
// expected
72-
}
61+
def "serialize throws exception for invalid input #value"() {
62+
when:
63+
Scalars.GraphQLBigInteger.getCoercing().serialize(value)
64+
then:
65+
thrown(CoercingSerializeException)
7366

7467
where:
7568
value | _
@@ -80,5 +73,20 @@ class ScalarsBigIntegerTest extends Specification {
8073
new Object() | _
8174
}
8275

76+
@Unroll
77+
def "parseValue throws exception for invalid input #value"() {
78+
when:
79+
Scalars.GraphQLBigInteger.getCoercing().parseValue(value)
80+
then:
81+
thrown(CoercingParseValueException)
82+
83+
where:
84+
value | _
85+
"" | _
86+
"not a number " | _
87+
new BigDecimal("12.12") | _
88+
"12.12" | _
89+
new Object() | _
90+
}
8391

8492
}

src/test/groovy/graphql/ScalarsBooleanTest.groovy

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import graphql.language.BooleanValue
44
import graphql.language.FloatValue
55
import graphql.language.IntValue
66
import graphql.language.StringValue
7+
import graphql.schema.CoercingParseValueException
8+
import graphql.schema.CoercingSerializeException
79
import spock.lang.Specification
810
import spock.lang.Unroll
911

@@ -58,25 +60,27 @@ class ScalarsBooleanTest extends Specification {
5860
}
5961

6062
@Unroll
61-
def "serialize/parseValue throws exception for invalid input #value"() {
62-
expect:
63-
try {
64-
Scalars.GraphQLBoolean.getCoercing().serialize(value)
65-
assert false: "no exception thrown"
66-
} catch (GraphQLException e) {
67-
// expected
68-
}
69-
try {
70-
Scalars.GraphQLBoolean.getCoercing().parseValue(value)
71-
assert false: "no exception thrown"
72-
} catch (GraphQLException e) {
73-
// expected
74-
}
63+
def "serialize throws exception for invalid input #value"() {
64+
when:
65+
Scalars.GraphQLBoolean.getCoercing().serialize(value)
66+
then:
67+
thrown(CoercingSerializeException)
7568

7669
where:
7770
value | _
7871
new Object() | _
7972
}
8073

74+
@Unroll
75+
def "parseValue throws exception for invalid input #value"() {
76+
when:
77+
Scalars.GraphQLBoolean.getCoercing().parseValue(value)
78+
then:
79+
thrown(CoercingParseValueException)
80+
81+
where:
82+
value | _
83+
new Object() | _
84+
}
8185

8286
}

src/test/groovy/graphql/ScalarsByteTest.groovy

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package graphql
33
import graphql.language.FloatValue
44
import graphql.language.IntValue
55
import graphql.language.StringValue
6+
import graphql.schema.CoercingParseValueException
7+
import graphql.schema.CoercingSerializeException
68
import spock.lang.Specification
79
import spock.lang.Unroll
810

@@ -66,20 +68,11 @@ class ScalarsByteTest extends Specification {
6668
}
6769

6870
@Unroll
69-
def "serialize/parseValue throws exception for invalid input #value"() {
70-
expect:
71-
try {
72-
Scalars.GraphQLByte.getCoercing().serialize(value)
73-
assert false: "no exception thrown"
74-
} catch (GraphQLException e) {
75-
// expected
76-
}
77-
try {
78-
Scalars.GraphQLByte.getCoercing().parseValue(value)
79-
assert false: "no exception thrown"
80-
} catch (GraphQLException e) {
81-
// expected
82-
}
71+
def "serialize throws exception for invalid input #value"() {
72+
when:
73+
Scalars.GraphQLByte.getCoercing().serialize(value)
74+
then:
75+
thrown(CoercingSerializeException)
8376

8477
where:
8578
value | _
@@ -95,5 +88,25 @@ class ScalarsByteTest extends Specification {
9588

9689
}
9790

91+
@Unroll
92+
def "parseValue throws exception for invalid input #value"() {
93+
when:
94+
Scalars.GraphQLByte.getCoercing().parseValue(value)
95+
then:
96+
thrown(CoercingParseValueException)
97+
98+
where:
99+
value | _
100+
"" | _
101+
"not a number " | _
102+
"42.3" | _
103+
new Long(42345784398534785l) | _
104+
new Double(42.3) | _
105+
new Float(42.3) | _
106+
Byte.MAX_VALUE + 1l | _
107+
Byte.MIN_VALUE - 1l | _
108+
new Object() | _
109+
110+
}
98111

99112
}

0 commit comments

Comments
 (0)