diff --git a/spring-graphql/src/main/java/org/springframework/graphql/DefaultGraphQlResponseField.java b/spring-graphql/src/main/java/org/springframework/graphql/DefaultGraphQlResponseField.java new file mode 100644 index 000000000..9f922e295 --- /dev/null +++ b/spring-graphql/src/main/java/org/springframework/graphql/DefaultGraphQlResponseField.java @@ -0,0 +1,182 @@ +/* + * Copyright 2002-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.graphql; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + + +/** + * Default implementation of {@link GraphQlResponseField}. + * + * @author Rossen Stoyanchev + * @since 1.0.0 + */ +public class DefaultGraphQlResponseField implements GraphQlResponseField { + + private final GraphQlResponse response; + + private final String path; + + private final List parsedPath; + + @Nullable + private final Object value; + + private final List fieldErrors; + + + protected DefaultGraphQlResponseField(GraphQlResponse response, String path) { + + this.response = response; + this.path = path; + this.parsedPath = parsePath(path); + this.value = initFieldValue(this.parsedPath, response); + this.fieldErrors = initFieldErrors(path, response); + } + + private static List parsePath(String path) { + if (!StringUtils.hasText(path)) { + return Collections.emptyList(); + } + + String invalidPathMessage = "Invalid path: '" + path + "'"; + List dataPath = new ArrayList<>(); + + StringBuilder sb = new StringBuilder(); + boolean readingIndex = false; + + for (int i = 0; i < path.length(); i++) { + char c = path.charAt(i); + switch (c) { + case '.': + case '[': + Assert.isTrue(!readingIndex, invalidPathMessage); + break; + case ']': + i++; + Assert.isTrue(readingIndex, invalidPathMessage); + Assert.isTrue(i == path.length() || path.charAt(i) == '.', invalidPathMessage); + break; + default: + sb.append(c); + if (i < path.length() - 1) { + continue; + } + } + String token = sb.toString(); + Assert.hasText(token, invalidPathMessage); + dataPath.add(readingIndex ? Integer.parseInt(token) : token); + sb.delete(0, sb.length()); + + readingIndex = (c == '['); + } + + return dataPath; + } + + @Nullable + private static Object initFieldValue(List path, GraphQlResponse response) { + Object value = (response.isValid() ? response.getData() : null); + for (Object segment : path) { + if (value == null) { + return null; + } + if (segment instanceof String) { + Assert.isTrue(value instanceof Map, () -> "Invalid path " + path + ", data: " + response.getData()); + value = ((Map) value).getOrDefault(segment, null); + } + else { + Assert.isTrue(value instanceof List, () -> "Invalid path " + path + ", data: " + response.getData()); + int index = (int) segment; + value = (index < ((List) value).size() ? ((List) value).get(index) : null); + } + } + return value; + } + + /** + * Return field errors whose path starts with the given field path. + * @param path the field path to match + * @return errors whose path starts with the dataPath + */ + private static List initFieldErrors(String path, GraphQlResponse response) { + if (path.isEmpty() || response.getErrors().isEmpty()) { + return Collections.emptyList(); + } + return response.getErrors().stream() + .filter(error -> { + String errorPath = error.getPath(); + return !errorPath.isEmpty() && (errorPath.startsWith(path) || path.startsWith(errorPath)); + }) + .collect(Collectors.toList()); + } + + + @SuppressWarnings("unchecked") + protected R getResponse() { + return (R) this.response; + } + + @Override + public String getPath() { + return this.path; + } + + @Override + public List getParsedPath() { + return this.parsedPath; + } + + @Override + public boolean hasValue() { + return (this.value != null); + } + + @SuppressWarnings("unchecked") + @Override + public T getValue() { + return (T) this.value; + } + + @Override + public GraphQlResponseError getError() { + if (!hasValue()) { + if (!this.fieldErrors.isEmpty()) { + return this.fieldErrors.get(0); + } + if (!this.response.getErrors().isEmpty()) { + return this.response.getErrors().get(0); + } + // No errors, set to null by DataFetcher + } + return null; + } + + @Override + public List getErrors() { + return this.fieldErrors; + } + +} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/GraphQlResponse.java b/spring-graphql/src/main/java/org/springframework/graphql/GraphQlResponse.java index 12de54dc2..636e9e458 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/GraphQlResponse.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/GraphQlResponse.java @@ -65,6 +65,26 @@ public interface GraphQlResponse { */ List getErrors(); + /** + * Navigate to the given path under the "data" key of the response map where + * the path is a dot-separated string with optional array indexes. + *

Example paths: + *

+	 * "hero"
+	 * "hero.name"
+	 * "hero.friends"
+	 * "hero.friends[2]"
+	 * "hero.friends[2].name"
+	 * 
+ * @param path relative to the "data" key + * @return representation for the field with further options to inspect or + * decode its value; use {@link GraphQlResponseField#hasValue()} to check if + * the field actually exists and has a value. + */ + default GraphQlResponseField field(String path) { + return new DefaultGraphQlResponseField(this, path); + } + /** * Return implementor specific, protocol extensions, if any. */ diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlResponseField.java b/spring-graphql/src/main/java/org/springframework/graphql/GraphQlResponseField.java similarity index 70% rename from spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlResponseField.java rename to spring-graphql/src/main/java/org/springframework/graphql/GraphQlResponseField.java index d3d9ca44c..f830cd1f3 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlResponseField.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/GraphQlResponseField.java @@ -14,19 +14,17 @@ * limitations under the License. */ -package org.springframework.graphql.client; - +package org.springframework.graphql; import java.util.List; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.graphql.GraphQlResponse; -import org.springframework.graphql.GraphQlResponseError; +import org.springframework.graphql.client.ClientGraphQlResponse; import org.springframework.lang.Nullable; + /** - * Representation for a field in a GraphQL response, with options to examine its - * value and errors, and to decode it. + * Representation for a field in a GraphQL response, with options to examine + * the field value and errors. * * @author Rossen Stoyanchev * @since 1.0.0 @@ -58,8 +56,8 @@ public interface GraphQlResponseField { List getParsedPath(); /** - * Return the field value without any decoding. - * @param the expected value type, e.g. Map, List, or a scalar type. + * Return the raw field value, e.g. Map, List, or a scalar type. + * @param the expected value type to cast to * @return the value */ @Nullable @@ -98,32 +96,4 @@ public interface GraphQlResponseField { */ List getErrors(); - /** - * Decode the field to an entity of the given type. - * @param entityType the type to convert to - * @return the decoded entity, never {@code null} - * @throws FieldAccessException if the target field is not present or - * has no value, checked via {@link #hasValue()}. - */ - D toEntity(Class entityType); - - /** - * Variant of {@link #toEntity(Class)} with a {@link ParameterizedTypeReference}. - */ - D toEntity(ParameterizedTypeReference entityType); - - /** - * Decode the field to a list of entities with the given type. - * @param elementType the type of elements in the list - * @return the decoded list of entities, possibly empty - * @throws FieldAccessException if the target field is not present or - * has no value, checked via {@link #hasValue()}. - */ - List toEntityList(Class elementType); - - /** - * Variant of {@link #toEntityList(Class)} with {@link ParameterizedTypeReference}. - */ - List toEntityList(ParameterizedTypeReference elementType); - } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/ClientGraphQlResponse.java b/spring-graphql/src/main/java/org/springframework/graphql/client/ClientGraphQlResponse.java index ffdaca983..962c011c7 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/ClientGraphQlResponse.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/ClientGraphQlResponse.java @@ -36,22 +36,9 @@ public interface ClientGraphQlResponse extends GraphQlResponse { GraphQlRequest getRequest(); /** - * Navigate to the given path under the "data" key of the response map where - * the path is a dot-separated string with optional array indexes. - *

Example paths: - *

-	 * "hero"
-	 * "hero.name"
-	 * "hero.friends"
-	 * "hero.friends[2]"
-	 * "hero.friends[2].name"
-	 * 
- * @param path relative to the "data" key - * @return representation for the field with further options to inspect or - * decode its value; use {@link GraphQlResponseField#hasValue()} to check if - * the field actually exists and has a value. + * {@inheritDoc} */ - GraphQlResponseField field(String path); + ClientGraphQlResponseField field(String path); /** * Decode the full response map to the given target type. diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/ClientGraphQlResponseField.java b/spring-graphql/src/main/java/org/springframework/graphql/client/ClientGraphQlResponseField.java new file mode 100644 index 000000000..fb9ba227a --- /dev/null +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/ClientGraphQlResponseField.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.graphql.client; + + +import java.util.List; + +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.graphql.GraphQlResponseField; + +/** + * Extends {@link GraphQlResponseField} to add options for decoding the field value. + * + * @author Rossen Stoyanchev + * @since 1.0.0 + */ +public interface ClientGraphQlResponseField extends GraphQlResponseField { + + /** + * Decode the field to an entity of the given type. + * @param entityType the type to convert to + * @return the decoded entity, never {@code null} + * @throws FieldAccessException if the target field is not present or + * has no value, checked via {@link #hasValue()}. + */ + D toEntity(Class entityType); + + /** + * Variant of {@link #toEntity(Class)} with a {@link ParameterizedTypeReference}. + */ + D toEntity(ParameterizedTypeReference entityType); + + /** + * Decode the field to a list of entities with the given type. + * @param elementType the type of elements in the list + * @return the decoded list of entities, possibly empty + * @throws FieldAccessException if the target field is not present or + * has no value, checked via {@link #hasValue()}. + */ + List toEntityList(Class elementType); + + /** + * Variant of {@link #toEntityList(Class)} with {@link ParameterizedTypeReference}. + */ + List toEntityList(ParameterizedTypeReference elementType); + +} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientGraphQlResponse.java b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientGraphQlResponse.java index 8bbec4cd2..e6e88df96 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientGraphQlResponse.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientGraphQlResponse.java @@ -16,21 +16,11 @@ package org.springframework.graphql.client; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.codec.Decoder; import org.springframework.core.codec.Encoder; import org.springframework.graphql.GraphQlRequest; import org.springframework.graphql.GraphQlResponse; -import org.springframework.graphql.GraphQlResponseError; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; /** @@ -74,86 +64,8 @@ Decoder getDecoder() { @Override - public GraphQlResponseField field(String path) { - List parsedPath = parsePath(path); - return new DefaultGraphQlResponseField(this, path, parsedPath, getValue(parsedPath), getFieldErrors(path)); - } - - private static List parsePath(String path) { - if (!StringUtils.hasText(path)) { - return Collections.emptyList(); - } - - String invalidPathMessage = "Invalid path: '" + path + "'"; - List dataPath = new ArrayList<>(); - - StringBuilder sb = new StringBuilder(); - boolean readingIndex = false; - - for (int i = 0; i < path.length(); i++) { - char c = path.charAt(i); - switch (c) { - case '.': - case '[': - Assert.isTrue(!readingIndex, invalidPathMessage); - break; - case ']': - i++; - Assert.isTrue(readingIndex, invalidPathMessage); - Assert.isTrue(i == path.length() || path.charAt(i) == '.', invalidPathMessage); - break; - default: - sb.append(c); - if (i < path.length() - 1) { - continue; - } - } - String token = sb.toString(); - Assert.hasText(token, invalidPathMessage); - dataPath.add(readingIndex ? Integer.parseInt(token) : token); - sb.delete(0, sb.length()); - - readingIndex = (c == '['); - } - - return dataPath; - } - - @Nullable - private Object getValue(List path) { - Object value = (isValid() ? getData() : null); - for (Object segment : path) { - if (value == null) { - return null; - } - if (segment instanceof String) { - Assert.isTrue(value instanceof Map, () -> "Invalid path " + path + ", data: " + getData()); - value = ((Map) value).getOrDefault(segment, null); - } - else { - Assert.isTrue(value instanceof List, () -> "Invalid path " + path + ", data: " + getData()); - int index = (int) segment; - value = (index < ((List) value).size() ? ((List) value).get(index) : null); - } - } - return value; - } - - /** - * Return field errors whose path starts with the given field path. - * @param path the field path to match - * @return errors whose path starts with the dataPath - */ - private List getFieldErrors(String path) { - if (path.isEmpty()) { - return Collections.emptyList(); - } - return getErrors().stream() - .filter(error -> { - String errorPath = error.getPath(); - return !errorPath.isEmpty() && (errorPath.startsWith(path) || path.startsWith(errorPath)); - }) - .collect(Collectors.toList()); + public ClientGraphQlResponseField field(String path) { + return new DefaultClientGraphQlResponseField(this, path); } @Override diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlResponseField.java b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientGraphQlResponseField.java similarity index 55% rename from spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlResponseField.java rename to spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientGraphQlResponseField.java index 5f6dba02f..61fdc4ac2 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlResponseField.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientGraphQlResponseField.java @@ -27,83 +27,24 @@ import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DefaultDataBufferFactory; -import org.springframework.graphql.GraphQlResponseError; -import org.springframework.lang.Nullable; +import org.springframework.graphql.DefaultGraphQlResponseField; import org.springframework.util.MimeType; import org.springframework.util.MimeTypeUtils; /** - * Default implementation of {@link GraphQlResponseField}. + * Default implementation of {@link ClientGraphQlResponseField}. * * @author Rossen Stoyanchev * @since 1.0.0 */ -final class DefaultGraphQlResponseField implements GraphQlResponseField { +final class DefaultClientGraphQlResponseField extends DefaultGraphQlResponseField implements ClientGraphQlResponseField { - private final DefaultClientGraphQlResponse response; - private final String path; - - private final List parsedPath; - - @Nullable - private final Object value; - - private final List fieldErrors; - - - DefaultGraphQlResponseField( - DefaultClientGraphQlResponse response, String path, List parsedPath, - @Nullable Object value, List errors) { - - this.response = response; - this.path = path; - this.parsedPath = parsedPath; - this.value = value; - this.fieldErrors = errors; - } - - - @Override - public String getPath() { - return this.path; + DefaultClientGraphQlResponseField(DefaultClientGraphQlResponse response, String path) { + super(response, path); } - @Override - public List getParsedPath() { - return this.parsedPath; - } - - @Override - public boolean hasValue() { - return (this.value != null); - } - - @SuppressWarnings("unchecked") - @Override - public T getValue() { - return (T) this.value; - } - - @Override - public GraphQlResponseError getError() { - if (!hasValue()) { - if (!this.fieldErrors.isEmpty()) { - return this.fieldErrors.get(0); - } - if (!this.response.getErrors().isEmpty()) { - return this.response.getErrors().get(0); - } - // No errors, set to null by DataFetcher - } - return null; - } - - @Override - public List getErrors() { - return this.fieldErrors; - } @Override public D toEntity(Class entityType) { @@ -127,18 +68,19 @@ public List toEntityList(ParameterizedTypeReference elementType) { @SuppressWarnings({"unchecked", "ConstantConditions"}) private T toEntity(ResolvableType targetType) { - if (this.value == null) { - throw new FieldAccessException(this.response, this); + DefaultClientGraphQlResponse response = getResponse(); + if (!hasValue()) { + throw new FieldAccessException(response, this); } DataBufferFactory bufferFactory = DefaultDataBufferFactory.sharedInstance; MimeType mimeType = MimeTypeUtils.APPLICATION_JSON; Map hints = Collections.emptyMap(); - DataBuffer buffer = ((Encoder) this.response.getEncoder()).encodeValue( - (T) this.value, bufferFactory, ResolvableType.forInstance(this.value), mimeType, hints); + DataBuffer buffer = ((Encoder) response.getEncoder()).encodeValue( + (T) getValue(), bufferFactory, ResolvableType.forInstance(getValue()), mimeType, hints); - return ((Decoder) this.response.getDecoder()).decode(buffer, targetType, mimeType, hints); + return ((Decoder) response.getDecoder()).decode(buffer, targetType, mimeType, hints); } } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlClient.java b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlClient.java index f411c0f8b..59255e01a 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlClient.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlClient.java @@ -203,8 +203,8 @@ protected RetrieveSpecSupport(String path) { * @throws FieldAccessException for invalid response or failed field */ @Nullable - protected GraphQlResponseField getValidField(ClientGraphQlResponse response) { - GraphQlResponseField field = response.field(this.path); + protected ClientGraphQlResponseField getValidField(ClientGraphQlResponse response) { + ClientGraphQlResponseField field = response.field(this.path); if (!response.isValid() || field.getError() != null) { throw new FieldAccessException(response, field); } @@ -236,7 +236,7 @@ public Mono toEntity(ParameterizedTypeReference entityType) { @Override public Mono> toEntityList(Class elementType) { return this.responseMono.map(response -> { - GraphQlResponseField field = getValidField(response); + ClientGraphQlResponseField field = getValidField(response); return (field != null ? field.toEntityList(elementType) : Collections.emptyList()); }); } @@ -244,7 +244,7 @@ public Mono> toEntityList(Class elementType) { @Override public Mono> toEntityList(ParameterizedTypeReference elementType) { return this.responseMono.map(response -> { - GraphQlResponseField field = getValidField(response); + ClientGraphQlResponseField field = getValidField(response); return (field != null ? field.toEntityList(elementType) : Collections.emptyList()); }); } @@ -274,7 +274,7 @@ public Flux toEntity(ParameterizedTypeReference entityType) { @Override public Flux> toEntityList(Class elementType) { return this.responseFlux.map(response -> { - GraphQlResponseField field = getValidField(response); + ClientGraphQlResponseField field = getValidField(response); return (field != null ? field.toEntityList(elementType) : Collections.emptyList()); }); } @@ -282,7 +282,7 @@ public Flux> toEntityList(Class elementType) { @Override public Flux> toEntityList(ParameterizedTypeReference elementType) { return this.responseFlux.map(response -> { - GraphQlResponseField field = getValidField(response); + ClientGraphQlResponseField field = getValidField(response); return (field != null ? field.toEntityList(elementType) : Collections.emptyList()); }); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/FieldAccessException.java b/spring-graphql/src/main/java/org/springframework/graphql/client/FieldAccessException.java index 95390b3e8..9f695f63f 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/FieldAccessException.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/FieldAccessException.java @@ -22,7 +22,8 @@ /** * An exception raised on an attempt to decode data from a * {@link GraphQlResponse#isValid() failed response} or a field is not present, - * or has no value, checked via {@link GraphQlResponseField#hasValue()}. + * or has no value, checked via + * {@link org.springframework.graphql.GraphQlResponseField#hasValue()}. * * @author Rossen Stoyanchev * @since 1.0.0 @@ -32,19 +33,19 @@ public class FieldAccessException extends GraphQlClientException { private final ClientGraphQlResponse response; - private final GraphQlResponseField field; + private final ClientGraphQlResponseField field; /** * Constructor with the request and response, and the accessed field. */ - public FieldAccessException(ClientGraphQlResponse response, GraphQlResponseField field) { + public FieldAccessException(ClientGraphQlResponse response, ClientGraphQlResponseField field) { super(initDefaultMessage(field), null, response.getRequest()); this.response = response; this.field = field; } - private static String initDefaultMessage(GraphQlResponseField field) { + private static String initDefaultMessage(ClientGraphQlResponseField field) { return "Invalid field '" + field.getPath() + "', errors: " + field.getErrors(); } @@ -59,7 +60,7 @@ public ClientGraphQlResponse getResponse() { /** * Return the field that needed to be accessed. */ - public GraphQlResponseField getField() { + public ClientGraphQlResponseField getField() { return this.field; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClient.java b/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClient.java index b55c62dab..a453180aa 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClient.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClient.java @@ -185,7 +185,7 @@ interface RetrieveSpec { * the field is {@code null} without errors, or ends with * {@link FieldAccessException} for an invalid response or a failed field * @see GraphQlResponse#isValid() - * @see GraphQlResponseField#getError() + * @see org.springframework.graphql.GraphQlResponseField#getError() */ Mono toEntity(Class entityType); @@ -201,7 +201,7 @@ interface RetrieveSpec { * empty list, or ends with {@link FieldAccessException} if the target * field is not present or has no value. * @see GraphQlResponse#isValid() - * @see GraphQlResponseField#getError() + * @see org.springframework.graphql.GraphQlResponseField#getError() */ Mono> toEntityList(Class elementType); @@ -226,7 +226,7 @@ interface RetrieveSubscriptionSpec { * {@link FieldAccessException} for an invalid response or a failed field. * May also end with a {@link GraphQlTransportException}. * @see GraphQlResponse#isValid() - * @see GraphQlResponseField#getError() + * @see org.springframework.graphql.GraphQlResponseField#getError() */ Flux toEntity(Class entityType); @@ -243,7 +243,7 @@ interface RetrieveSubscriptionSpec { * {@link FieldAccessException} for an invalid response or a failed field. * May also end with a {@link GraphQlTransportException}. * @see GraphQlResponse#isValid() - * @see GraphQlResponseField#getError() + * @see org.springframework.graphql.GraphQlResponseField#getError() */ Flux> toEntityList(Class elementType); diff --git a/spring-graphql/src/test/java/org/springframework/graphql/client/DefaultGraphQlClientResponseTests.java b/spring-graphql/src/test/java/org/springframework/graphql/client/DefaultGraphQlClientResponseTests.java index dcd0c3c6e..1f0fe2ed7 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/client/DefaultGraphQlClientResponseTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/client/DefaultGraphQlClientResponseTests.java @@ -127,7 +127,7 @@ void fieldErrors() { GraphQLError error2 = createError("/me/friends", "fail-me-friends"); GraphQLError error3 = createError("/me/friends[0]/name", "fail-me-friends-name"); - GraphQlResponseField field = getField(path, error0, error1, error2, error3); + ClientGraphQlResponseField field = getField(path, error0, error1, error2, error3); List errors = field.getErrors(); assertThat(errors).hasSize(3); @@ -144,13 +144,13 @@ private GraphQLError createError(@Nullable String errorPath, String message) { return builder.build(); } - private GraphQlResponseField getField(String path, String dataJson) throws Exception { + private ClientGraphQlResponseField getField(String path, String dataJson) throws Exception { Map dataMap = mapper.readValue(dataJson, Map.class); ClientGraphQlResponse response = creatResponse(Collections.singletonMap("data", dataMap)); return response.field(path); } - private GraphQlResponseField getField(String path, GraphQLError... errors) { + private ClientGraphQlResponseField getField(String path, GraphQLError... errors) { List list = Arrays.stream(errors).map(GraphQLError::toSpecification).collect(Collectors.toList()); ClientGraphQlResponse response = creatResponse(Collections.singletonMap("errors", list)); return response.field(path); diff --git a/spring-graphql/src/test/java/org/springframework/graphql/client/GraphQlClientTests.java b/spring-graphql/src/test/java/org/springframework/graphql/client/GraphQlClientTests.java index 49324699d..71a65075b 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/client/GraphQlClientTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/client/GraphQlClientTests.java @@ -188,7 +188,7 @@ void executePartialResponse() { .as("Partial response with field errors should be considered valid") .isTrue(); - GraphQlResponseField field = response.field("me"); + ClientGraphQlResponseField field = response.field("me"); assertThat(field.hasValue()).isTrue(); assertThat(field.getErrors()).hasSize(1); assertThat(field.getErrors().get(0).getParsedPath()).containsExactly("me", "name"); @@ -196,7 +196,7 @@ void executePartialResponse() { .as("Decoding with nested field error should not be precluded") .isNotNull(); - GraphQlResponseField nameField = response.field("me.name"); + ClientGraphQlResponseField nameField = response.field("me.name"); assertThat(nameField.hasValue()).isFalse(); assertThat(nameField.getError()).isNotNull(); assertThat(nameField.getError().getParsedPath()).containsExactly("me", "name"); @@ -204,7 +204,7 @@ void executePartialResponse() { .as("Decoding field null with direct field error should be rejected") .isInstanceOf(FieldAccessException.class); - GraphQlResponseField nonExistingField = response.field("me.name.other"); + ClientGraphQlResponseField nonExistingField = response.field("me.name.other"); assertThat(nonExistingField.hasValue()).isFalse(); assertThat(nameField.getError()).isNotNull(); assertThat(nameField.getError().getParsedPath()).containsExactly("me", "name");