From 982cbbaa453f98b7acdcec10046ea7947faba314 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Fri, 18 Mar 2022 18:16:59 +0000 Subject: [PATCH] Extract GraphQlResponseField in the top-level package GraphQlResponseField is now extracted as a super type at the top-level package and is exposed from GraphQlResponse. ClientGraphQlResponseField extends this to provide decoding options. The change ensures consistency with both GraphQlResponseField and GraphQlResponseError accessible through GraphQlResponse, also making both available for client and server side handling. See gh-10 --- .../graphql/DefaultGraphQlResponseField.java | 182 ++++++++++++++++++ .../graphql/GraphQlResponse.java | 20 ++ .../{client => }/GraphQlResponseField.java | 44 +---- .../graphql/client/ClientGraphQlResponse.java | 17 +- .../client/ClientGraphQlResponseField.java | 61 ++++++ .../client/DefaultClientGraphQlResponse.java | 92 +-------- ...=> DefaultClientGraphQlResponseField.java} | 80 ++------ .../graphql/client/DefaultGraphQlClient.java | 12 +- .../graphql/client/FieldAccessException.java | 11 +- .../graphql/client/GraphQlClient.java | 8 +- .../DefaultGraphQlClientResponseTests.java | 6 +- .../graphql/client/GraphQlClientTests.java | 6 +- 12 files changed, 307 insertions(+), 232 deletions(-) create mode 100644 spring-graphql/src/main/java/org/springframework/graphql/DefaultGraphQlResponseField.java rename spring-graphql/src/main/java/org/springframework/graphql/{client => }/GraphQlResponseField.java (70%) create mode 100644 spring-graphql/src/main/java/org/springframework/graphql/client/ClientGraphQlResponseField.java rename spring-graphql/src/main/java/org/springframework/graphql/client/{DefaultGraphQlResponseField.java => DefaultClientGraphQlResponseField.java} (55%) 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");