From ac9616fd9f0a8960eccb8ee66f5125b38c37b190 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 15 Apr 2025 12:01:40 +0200 Subject: [PATCH] Revert ArgumentValue->FieldValue changes See gh-1187 See gh-1190 See gh-1174 --- .../modules/ROOT/pages/client.adoc | 41 ----- .../modules/ROOT/pages/controllers.adoc | 33 ++-- .../client/fieldvalue/FieldValueClient.java | 66 ------- .../docs/client/fieldvalue/ProjectInput.java | 23 --- .../springframework/graphql/FieldValue.java | 172 ------------------ .../client/AbstractGraphQlClientBuilder.java | 15 +- .../AbstractGraphQlClientSyncBuilder.java | 7 +- .../client/json/FieldValueDeserializer.java | 92 ---------- .../client/json/FieldValueSerializer.java | 89 --------- .../client/json/FieldValueTypeModifier.java | 48 ----- .../client/json/GraphQlDeserializers.java | 45 ----- .../graphql/client/json/GraphQlModule.java | 58 ------ .../client/json/GraphQlSerializers.java | 48 ----- .../graphql/client/json/package-info.java | 25 --- .../graphql/data/ArgumentValue.java | 25 ++- .../graphql/data/GraphQlArgumentBinder.java | 15 +- .../AnnotatedControllerConfigurer.java | 5 +- .../ArgumentMethodArgumentResolver.java | 21 +-- .../support/ArgumentValueValueExtractor.java | 1 - .../support/FieldValueValueExtractor.java | 42 ----- ...rojectedPayloadMethodArgumentResolver.java | 13 +- ...BeanFactoryInitializationAotProcessor.java | 5 +- ....validation.valueextraction.ValueExtractor | 1 - .../graphql/client/GraphQlClientTests.java | 40 ---- .../HttpGraphQlTransportIntegrationTests.java | 61 +------ .../graphql/client/Project.java | 23 --- .../client/json/FieldValueJsonTests.java | 103 ----------- .../ArgumentValueTests.java} | 24 +-- .../data/GraphQlArgumentBinderTests.java | 48 +---- .../ArgumentMethodArgumentResolverTests.java | 27 +-- .../ArgumentsMethodArgumentResolverTests.java | 8 +- ...tedPayloadMethodArgumentResolverTests.java | 30 +-- ...actoryInitializationAotProcessorTests.java | 16 +- .../support/ValidationHelperTests.java | 16 +- 34 files changed, 105 insertions(+), 1181 deletions(-) delete mode 100644 spring-graphql-docs/src/main/java/org/springframework/graphql/docs/client/fieldvalue/FieldValueClient.java delete mode 100644 spring-graphql-docs/src/main/java/org/springframework/graphql/docs/client/fieldvalue/ProjectInput.java delete mode 100644 spring-graphql/src/main/java/org/springframework/graphql/FieldValue.java delete mode 100644 spring-graphql/src/main/java/org/springframework/graphql/client/json/FieldValueDeserializer.java delete mode 100644 spring-graphql/src/main/java/org/springframework/graphql/client/json/FieldValueSerializer.java delete mode 100644 spring-graphql/src/main/java/org/springframework/graphql/client/json/FieldValueTypeModifier.java delete mode 100644 spring-graphql/src/main/java/org/springframework/graphql/client/json/GraphQlDeserializers.java delete mode 100644 spring-graphql/src/main/java/org/springframework/graphql/client/json/GraphQlModule.java delete mode 100644 spring-graphql/src/main/java/org/springframework/graphql/client/json/GraphQlSerializers.java delete mode 100644 spring-graphql/src/main/java/org/springframework/graphql/client/json/package-info.java delete mode 100644 spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/FieldValueValueExtractor.java delete mode 100644 spring-graphql/src/test/java/org/springframework/graphql/client/Project.java delete mode 100644 spring-graphql/src/test/java/org/springframework/graphql/client/json/FieldValueJsonTests.java rename spring-graphql/src/test/java/org/springframework/graphql/{FieldValueTests.java => data/ArgumentValueTests.java} (71%) diff --git a/spring-graphql-docs/modules/ROOT/pages/client.adoc b/spring-graphql-docs/modules/ROOT/pages/client.adoc index 4327b36d..21aee2b5 100644 --- a/spring-graphql-docs/modules/ROOT/pages/client.adoc +++ b/spring-graphql-docs/modules/ROOT/pages/client.adoc @@ -393,47 +393,6 @@ include-code::UseInterceptor[tag=register,indent=0] -[[client.fieldvalue]] -== `FieldValue` - -By default, input types in GraphQL are nullable and optional, an input value (or any of its fields) -can be set to the `null` literal, or not provided at all. This distinction is useful for -partial updates with a mutation where the underlying data may also be, either set to -`null` or not changed at all accordingly. - -Similar to the xref:controllers.adoc#controllers.schema-mapping.fieldvalue[`FieldValue support in controllers`], -we can wrap an Input type with `FieldValue` or use it at the level of class attributes on the client side. -Given a `ProjectInput` class like: - -include-code::ProjectInput[indent=0] - -We can use our client to send a mutation request: - -include-code::FieldValueClient[tag=fieldvalue,indent=0] - -For this to work, the client must use Jackson for JSON (de)serialization and must be configured -with the `org.springframework.graphql.client.json.GraphQlModule`. -This can be registered manually on the underlying HTTP client like so: - -include-code::FieldValueClient[tag=createclient,indent=0] - -This `GraphQlModule` can be globally registered in Spring Boot applications by contributing it as a bean: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @Configuration - public class GraphQlJsonConfiguration { - - @Bean - public GraphQLModule graphQLModule() { - return new GraphQLModule(); - } - - } ----- - - - [[client.dgsgraphqlclient]] == DGS Codegen diff --git a/spring-graphql-docs/modules/ROOT/pages/controllers.adoc b/spring-graphql-docs/modules/ROOT/pages/controllers.adoc index 6bba506b..dc3b5f75 100644 --- a/spring-graphql-docs/modules/ROOT/pages/controllers.adoc +++ b/spring-graphql-docs/modules/ROOT/pages/controllers.adoc @@ -143,11 +143,11 @@ See xref:controllers.adoc#controllers.schema-mapping.argument[`@Argument`]. See xref:controllers.adoc#controllers.schema-mapping.argument[`@Argument`]. -| `FieldValue` +| `ArgumentValue` | For access to a named field argument bound to a higher-level, typed Object along with a flag to indicate if the input argument was omitted vs set to `null`. -See xref:controllers.adoc#controllers.schema-mapping.field-value[`FieldValue`]. +See xref:controllers.adoc#controllers.schema-mapping.argument-value[`ArgumentValue`]. | `@Arguments` | For access to all field arguments bound to a higher-level, typed Object. @@ -403,8 +403,8 @@ specified in the annotation, or to the parameter name. For access to the full ar map, please use xref:controllers.adoc#controllers.schema-mapping.arguments[`@Arguments`] instead. -[[controllers.schema-mapping.fieldvalue]] -=== `FieldValue` +[[controllers.schema-mapping.argument-value]] +=== `ArgumentValue` By default, input arguments in GraphQL are nullable and optional, which means an argument can be set to the `null` literal, or not provided at all. This distinction is useful for @@ -414,7 +414,7 @@ there is no way to make such a distinction, because you would get `null` or an e `Optional` in both cases. If you want to know not whether a value was not provided at all, you can declare an -`FieldValue` method parameter, which is a simple container for the resulting value, +`ArgumentValue` method parameter, which is a simple container for the resulting value, along with a flag to indicate whether the input argument was omitted altogether. You can use this instead of `@Argument`, in which case the argument name is determined from the method parameter name, or together with `@Argument` to specify the argument name. @@ -426,31 +426,20 @@ For example: @Controller public class BookController { - @QueryMapping - public List searchBook(@Argument String search, FieldValue genre) { - if (!genre.isOmitted()) { - // genre has been set but might hold a "null" value - Genre genreValue = genre.value(); - } - } - @MutationMapping - public void addBook(@Argument BookInput bookInput) { - FieldValue genre = bookInput.genre(); - genre.ifPresent(genre -> { - //... - }); + public void addBook(ArgumentValue bookInput) { + if (!bookInput.isOmitted()) { + BookInput value = bookInput.value(); + // ... + } } } ---- -`FieldValue` is also supported as a field within the object structure of an `@Argument` +`ArgumentValue` is also supported as a field within the object structure of an `@Argument` method parameter, either initialized via a constructor argument or via a setter, including as a field of an object nested at any level below the top level object. -This is also supported on the client side with a dedicated Jackson Module, -see the xref:client.adoc#client.fieldvalue[`FieldValue` support for clients] section. - [[controllers.schema-mapping.arguments]] === `@Arguments` diff --git a/spring-graphql-docs/src/main/java/org/springframework/graphql/docs/client/fieldvalue/FieldValueClient.java b/spring-graphql-docs/src/main/java/org/springframework/graphql/docs/client/fieldvalue/FieldValueClient.java deleted file mode 100644 index ccfa274e..00000000 --- a/spring-graphql-docs/src/main/java/org/springframework/graphql/docs/client/fieldvalue/FieldValueClient.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2020-2025 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.docs.client.fieldvalue; - -import java.util.Map; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.springframework.graphql.FieldValue; -import org.springframework.graphql.client.ClientGraphQlResponse; -import org.springframework.graphql.client.HttpGraphQlClient; -import org.springframework.graphql.client.json.GraphQlModule; -import org.springframework.http.MediaType; -import org.springframework.http.codec.json.Jackson2JsonEncoder; -import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; -import org.springframework.web.reactive.function.client.WebClient; - -public class FieldValueClient { - - private final HttpGraphQlClient graphQlClient; - - // tag::createclient[] - public FieldValueClient(HttpGraphQlClient graphQlClient) { - ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json() - .modulesToInstall(new GraphQlModule()) - .build(); - Jackson2JsonEncoder jsonEncoder = new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON); - WebClient webClient = WebClient.builder() - .baseUrl("https://example.com/graphql") - .codecs((codecs) -> codecs.defaultCodecs().jackson2JsonEncoder(jsonEncoder)) - .build(); - this.graphQlClient = HttpGraphQlClient.create(webClient); - } - // end::createclient[] - - // tag::fieldvalue[] - public void updateProject() { - ProjectInput projectInput = new ProjectInput("spring-graphql", - FieldValue.ofNullable("Spring for GraphQL")); - ClientGraphQlResponse response = this.graphQlClient.document(""" - mutation updateProject($project: ProjectInput!) { - updateProject($project: $project) { - id - name - } - } - """) - .variables(Map.of("project", projectInput)) - .executeSync(); - } - // end::fieldvalue[] -} diff --git a/spring-graphql-docs/src/main/java/org/springframework/graphql/docs/client/fieldvalue/ProjectInput.java b/spring-graphql-docs/src/main/java/org/springframework/graphql/docs/client/fieldvalue/ProjectInput.java deleted file mode 100644 index 9476df7e..00000000 --- a/spring-graphql-docs/src/main/java/org/springframework/graphql/docs/client/fieldvalue/ProjectInput.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2020-2025 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.docs.client.fieldvalue; - -import org.springframework.graphql.FieldValue; - -public record ProjectInput(String id, FieldValue name) { - -} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/FieldValue.java b/spring-graphql/src/main/java/org/springframework/graphql/FieldValue.java deleted file mode 100644 index 7fd830a6..00000000 --- a/spring-graphql/src/main/java/org/springframework/graphql/FieldValue.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2020-2025 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.Optional; -import java.util.function.Consumer; - -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; - -/** - * Simple container for GraphQL field values that indicates if the field - * value is present, provided but set to {@literal "null"} or omitted altogether. - * - *

In the case of GraphQL mutations, clients send an Input Object with several fields; - * the server must understand the difference between a field being absent - * (the existing value should be left as-is) and a field set to {@literal "null"} - * (the existing value must be set to {@literal "null"}). {@code FieldValue} - * helps to make this distinction. - * - *

Supported in one of the following places: - *

    - *
  • On a controller method parameter, either instead of - * {@link org.springframework.graphql.data.method.annotation.Argument @Argument} - * in which case the argument name is determined from the method parameter name, - * or together with {@code @Argument} to specify the argument name. - *
  • As a field within the object structure of an {@code @Argument} method - * parameter, either initialized via a constructor argument or a setter, - * including as a field of an object nested at any level below the top level - * object. - *
- * - * @param the type of value contained - * @author Rossen Stoyanchev - * @author Brian Clozel - * @since 1.4.0 - * @see Input Object - * @see Nullable vs Optional - */ -public final class FieldValue { - - private static final FieldValue EMPTY = new FieldValue<>(null, false); - - private static final FieldValue OMITTED = new FieldValue<>(null, true); - - - @Nullable - private final T value; - - private final boolean omitted; - - - private FieldValue(@Nullable T value, boolean omitted) { - this.value = value; - this.omitted = omitted; - } - - - /** - * Return {@code true} if a non-null value is present, and {@code false} otherwise. - */ - public boolean isPresent() { - return (this.value != null); - } - - /** - * Return {@code true} if the input value was present in the input but the value was {@code null}, - * and {@code false} otherwise. - */ - public boolean isEmpty() { - return !this.omitted && this.value == null; - } - - /** - * Return {@code true} if the input value was omitted altogether from the - * input, and {@code false} if it was provided, but possibly set to the - * {@literal "null"} literal. - */ - public boolean isOmitted() { - return this.omitted; - } - - /** - * Return the contained value, or {@code null}. - */ - @Nullable - public T value() { - return this.value; - } - - /** - * Return the contained value as a nullable {@link Optional}. - */ - public Optional asOptional() { - return Optional.ofNullable(this.value); - } - - /** - * If a value is present, performs the given action with the value, otherwise does nothing. - * @param action the action to be performed, if a value is present - */ - public void ifPresent(Consumer action) { - Assert.notNull(action, "Action is required"); - if (this.value != null) { - action.accept(this.value); - } - } - - @Override - public boolean equals(Object other) { - // This covers EMPTY and OMITTED constant - if (this == other) { - return true; - } - if (!(other instanceof FieldValue otherValue)) { - return false; - } - return ObjectUtils.nullSafeEquals(this.value, otherValue.value); - } - - @Override - public int hashCode() { - int result = ObjectUtils.nullSafeHashCode(this.value); - result = 31 * result + Boolean.hashCode(this.omitted); - return result; - } - - @Override - public String toString() { - if (this.isOmitted()) { - return "FieldValue{omitted}"; - } - return "FieldValue{value=" + this.value + "'}'"; - } - - /** - * Static factory method for an argument value that was provided, even if - * it was set to {@literal "null}. - * @param the type of value - * @param value the value to hold in the instance - */ - @SuppressWarnings("unchecked") - public static FieldValue ofNullable(@Nullable T value) { - return (value != null) ? new FieldValue<>(value, false) : (FieldValue) EMPTY; - } - - /** - * Static factory method for an argument value that was omitted. - * @param the type of value - */ - @SuppressWarnings("unchecked") - public static FieldValue omitted() { - return (FieldValue) OMITTED; - } - -} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientBuilder.java b/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientBuilder.java index 9adb8bec..9f414dea 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientBuilder.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2025 the original author or authors. + * Copyright 2002-2024 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. @@ -23,22 +23,16 @@ import java.util.Collections; import java.util.List; import java.util.function.Consumer; -import com.fasterxml.jackson.databind.ObjectMapper; - import org.springframework.core.codec.Decoder; import org.springframework.core.codec.Encoder; import org.springframework.core.io.ClassPathResource; -import org.springframework.graphql.MediaTypes; import org.springframework.graphql.client.GraphQlClientInterceptor.Chain; import org.springframework.graphql.client.GraphQlClientInterceptor.SubscriptionChain; -import org.springframework.graphql.client.json.GraphQlModule; import org.springframework.graphql.support.CachingDocumentSource; import org.springframework.graphql.support.DocumentSource; import org.springframework.graphql.support.ResourceDocumentSource; -import org.springframework.http.MediaType; import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; -import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -241,15 +235,12 @@ public abstract class AbstractGraphQlClientBuilder encoder() { - return new Jackson2JsonEncoder(JSON_MAPPER, MediaType.APPLICATION_JSON); + return new Jackson2JsonEncoder(); } static Decoder decoder() { - return new Jackson2JsonDecoder(JSON_MAPPER, MediaType.APPLICATION_JSON, MediaTypes.APPLICATION_GRAPHQL_RESPONSE); + return new Jackson2JsonDecoder(); } } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientSyncBuilder.java b/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientSyncBuilder.java index 01f6c847..dd13692a 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientSyncBuilder.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractGraphQlClientSyncBuilder.java @@ -22,7 +22,6 @@ import java.util.Collections; import java.util.List; import java.util.function.Consumer; -import com.fasterxml.jackson.databind.ObjectMapper; import reactor.core.scheduler.Scheduler; import reactor.core.scheduler.Schedulers; @@ -31,12 +30,10 @@ import org.springframework.core.codec.Encoder; import org.springframework.core.io.ClassPathResource; import org.springframework.graphql.GraphQlResponse; import org.springframework.graphql.client.SyncGraphQlClientInterceptor.Chain; -import org.springframework.graphql.client.json.GraphQlModule; import org.springframework.graphql.support.CachingDocumentSource; import org.springframework.graphql.support.DocumentSource; import org.springframework.graphql.support.ResourceDocumentSource; import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -194,9 +191,7 @@ public abstract class AbstractGraphQlClientSyncBuilder initialize() { - ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json() - .modulesToInstall(new GraphQlModule()).build(); - return new MappingJackson2HttpMessageConverter(objectMapper); + return new MappingJackson2HttpMessageConverter(); } } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/json/FieldValueDeserializer.java b/spring-graphql/src/main/java/org/springframework/graphql/client/json/FieldValueDeserializer.java deleted file mode 100644 index 9e540ee6..00000000 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/json/FieldValueDeserializer.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2020-2025 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.json; - -import java.io.Serial; -import java.io.Serializable; - -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.deser.ValueInstantiator; -import com.fasterxml.jackson.databind.deser.std.ReferenceTypeDeserializer; -import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; -import com.fasterxml.jackson.databind.ser.std.ReferenceTypeSerializer; - -import org.springframework.graphql.FieldValue; -import org.springframework.lang.Nullable; - -/** - * {@link ReferenceTypeSerializer} that deserializes JSON values as {@link FieldValue}: - *
    - *
  • a {@link FieldValue#isEmpty() non empty FieldValue} when the JSON key is present and its value is not {@literal null}. - *
  • an {@link FieldValue#isEmpty() empty FieldValue} when the JSON key is present and its value is {@literal null}. - *
  • an {@link FieldValue#isOmitted() ommitted FieldValue} when the JSON key is not present. - *
- * @author James Bodkin - */ -class FieldValueDeserializer extends ReferenceTypeDeserializer> { - - @Serial - private static final long serialVersionUID = 1L; - - FieldValueDeserializer(final JavaType fullType, @Nullable final ValueInstantiator vi, - final TypeDeserializer typeDeser, final JsonDeserializer deser) { - - super(fullType, vi, typeDeser, deser); - } - - @Override - protected ReferenceTypeDeserializer> withResolved(final TypeDeserializer typeDeser, - final JsonDeserializer valueDeser) { - - return new FieldValueDeserializer(_fullType, _valueInstantiator, typeDeser, valueDeser); - } - - @Override - public FieldValue getNullValue(final DeserializationContext ctxt) throws JsonMappingException { - return FieldValue.ofNullable((Serializable) _valueDeserializer.getNullValue(ctxt)); - } - - @Override - public Object getEmptyValue(final DeserializationContext ctxt) throws JsonMappingException { - return getNullValue(ctxt); - } - - @Override - public Object getAbsentValue(final DeserializationContext ctxt) { - return FieldValue.omitted(); - } - - @Override - public FieldValue referenceValue(final Object contents) { - return FieldValue.ofNullable((Serializable) contents); - } - - @Nullable - @Override - public Object getReferenced(final FieldValue value) { - return value.value(); - } - - @Override - public FieldValue updateReference(final FieldValue value, final Object contents) { - return FieldValue.ofNullable((Serializable) contents); - } - -} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/json/FieldValueSerializer.java b/spring-graphql/src/main/java/org/springframework/graphql/client/json/FieldValueSerializer.java deleted file mode 100644 index bda47fc2..00000000 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/json/FieldValueSerializer.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2020-2025 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.json; - -import java.io.Serial; - -import com.fasterxml.jackson.databind.BeanProperty; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.jsontype.TypeSerializer; -import com.fasterxml.jackson.databind.ser.std.ReferenceTypeSerializer; -import com.fasterxml.jackson.databind.type.ReferenceType; -import com.fasterxml.jackson.databind.util.NameTransformer; - -import org.springframework.graphql.FieldValue; -import org.springframework.lang.Nullable; - -/** - * {@link ReferenceTypeSerializer} that serializes {@link FieldValue} values as: - *
    - *
  • the embedded value if it is present and not {@literal null}. - *
  • {@literal null} if the embedded value is present and {@literal null}. - *
  • an empty value if the embedded value is not present. - *
- * @author James Bodkin - */ -class FieldValueSerializer extends ReferenceTypeSerializer> { - - @Serial - private static final long serialVersionUID = 1L; - - FieldValueSerializer(final ReferenceType fullType, final boolean staticTyping, - @Nullable final TypeSerializer vts, final JsonSerializer ser) { - - super(fullType, staticTyping, vts, ser); - } - - protected FieldValueSerializer(final FieldValueSerializer base, final BeanProperty property, - final TypeSerializer vts, final JsonSerializer valueSer, - final NameTransformer unwrapper, final Object suppressableValue, - final boolean suppressNulls) { - - super(base, property, vts, valueSer, unwrapper, suppressableValue, suppressNulls); - } - - @Override - protected ReferenceTypeSerializer> withResolved(final BeanProperty prop, final TypeSerializer vts, - final JsonSerializer valueSer, final NameTransformer unwrapper) { - - return new FieldValueSerializer(this, prop, vts, valueSer, unwrapper, _suppressableValue, _suppressNulls); - } - - @Override - public ReferenceTypeSerializer> withContentInclusion(final Object suppressableValue, final boolean suppressNulls) { - return new FieldValueSerializer(this, _property, _valueTypeSerializer, - _valueSerializer, _unwrapper, suppressableValue, suppressNulls); - } - - @Override - protected boolean _isValuePresent(final FieldValue value) { - return !value.isOmitted(); - } - - @Nullable - @Override - protected Object _getReferenced(final FieldValue value) { - return value.value(); - } - - @Nullable - @Override - protected Object _getReferencedIfPresent(final FieldValue value) { - return value.value(); - } - -} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/json/FieldValueTypeModifier.java b/spring-graphql/src/main/java/org/springframework/graphql/client/json/FieldValueTypeModifier.java deleted file mode 100644 index 8b2a72f2..00000000 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/json/FieldValueTypeModifier.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2020-2025 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.json; - -import java.lang.reflect.Type; - -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.type.ReferenceType; -import com.fasterxml.jackson.databind.type.TypeBindings; -import com.fasterxml.jackson.databind.type.TypeFactory; -import com.fasterxml.jackson.databind.type.TypeModifier; - -import org.springframework.graphql.FieldValue; - -/** - * {@link TypeModifier} that upgrades {@link FieldValue} types to {@link ReferenceType}. - * - * @author James Bodkin - */ -class FieldValueTypeModifier extends TypeModifier { - - @Override - public JavaType modifyType(final JavaType type, final Type jdkType, final TypeBindings context, final TypeFactory typeFactory) { - Class raw = type.getRawClass(); - if (!type.isReferenceType() && !type.isContainerType() && raw == FieldValue.class) { - JavaType refType = type.containedTypeOrUnknown(0); - return ReferenceType.upgradeFrom(type, refType); - } - else { - return type; - } - } - -} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/json/GraphQlDeserializers.java b/spring-graphql/src/main/java/org/springframework/graphql/client/json/GraphQlDeserializers.java deleted file mode 100644 index 98bf842c..00000000 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/json/GraphQlDeserializers.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2020-2025 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.json; - -import com.fasterxml.jackson.databind.BeanDescription; -import com.fasterxml.jackson.databind.DeserializationConfig; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.deser.Deserializers; -import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; -import com.fasterxml.jackson.databind.type.ReferenceType; - -import org.springframework.graphql.FieldValue; -import org.springframework.lang.Nullable; - -class GraphQlDeserializers extends Deserializers.Base { - - @Nullable - @Override - public JsonDeserializer findReferenceDeserializer(final ReferenceType refType, final DeserializationConfig config, - final BeanDescription beanDesc, final TypeDeserializer contentTypeDeserializer, - final JsonDeserializer contentDeserializer) { - - if (refType.hasRawClass(FieldValue.class)) { - return new FieldValueDeserializer(refType, null, contentTypeDeserializer, contentDeserializer); - } - else { - return null; - } - } - -} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/json/GraphQlModule.java b/spring-graphql/src/main/java/org/springframework/graphql/client/json/GraphQlModule.java deleted file mode 100644 index 989c5603..00000000 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/json/GraphQlModule.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2020-2025 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.json; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.Version; -import com.fasterxml.jackson.databind.Module; -import com.fasterxml.jackson.databind.type.ReferenceType; - -import org.springframework.graphql.FieldValue; - -/** - * {@link Module Jackson module} for JSON support in GraphQL clients. - *

This module ships with the following features: - *

    - *
  • Manage {@link FieldValue} types as {@link ReferenceType}, similar to {@link java.util.Optional} - *
  • Serializing and Deserializing values contained in {@link FieldValue} reference types - *
- * @author James Bodkin - * @since 1.4.0 - */ -public class GraphQlModule extends Module { - - @Override - public String getModuleName() { - return GraphQlModule.class.getName(); - } - - @Override - public Version version() { - return Version.unknownVersion(); - } - - @Override - public void setupModule(final SetupContext context) { - context.addSerializers(new GraphQlSerializers()); - context.addDeserializers(new GraphQlDeserializers()); - context.addTypeModifier(new FieldValueTypeModifier()); - - context.configOverride(FieldValue.class) - .setInclude(JsonInclude.Value.empty().withValueInclusion(JsonInclude.Include.NON_ABSENT)); - } - -} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/json/GraphQlSerializers.java b/spring-graphql/src/main/java/org/springframework/graphql/client/json/GraphQlSerializers.java deleted file mode 100644 index eb55bd36..00000000 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/json/GraphQlSerializers.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2020-2025 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.json; - -import com.fasterxml.jackson.databind.BeanDescription; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.SerializationConfig; -import com.fasterxml.jackson.databind.jsontype.TypeSerializer; -import com.fasterxml.jackson.databind.ser.Serializers; -import com.fasterxml.jackson.databind.type.ReferenceType; - -import org.springframework.graphql.FieldValue; -import org.springframework.lang.Nullable; - -class GraphQlSerializers extends Serializers.Base { - - @Nullable - @Override - public JsonSerializer findReferenceSerializer(final SerializationConfig config, final ReferenceType refType, - final BeanDescription beanDesc, @Nullable final TypeSerializer contentTypeSerializer, - final JsonSerializer contentValueSerializer) { - - Class raw = refType.getRawClass(); - if (FieldValue.class.isAssignableFrom(raw)) { - boolean staticTyping = contentTypeSerializer == null && config.isEnabled(MapperFeature.USE_STATIC_TYPING); - return new FieldValueSerializer(refType, staticTyping, contentTypeSerializer, contentValueSerializer); - } - else { - return null; - } - } - -} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/json/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/client/json/package-info.java deleted file mode 100644 index 96aec976..00000000 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/json/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2020-2025 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. - */ - -/** - * This package contains JSON support for GraphQL clients. - */ -@NonNullApi -@NonNullFields -package org.springframework.graphql.client.json; - -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/ArgumentValue.java b/spring-graphql/src/main/java/org/springframework/graphql/data/ArgumentValue.java index 44997eaf..5ce87f2f 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/ArgumentValue.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/ArgumentValue.java @@ -18,8 +18,10 @@ package org.springframework.graphql.data; import java.util.Optional; +import java.util.function.Consumer; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; /** @@ -44,9 +46,7 @@ import org.springframework.util.ObjectUtils; * @author Rossen Stoyanchev * @since 1.1.0 * @see Nullable vs Optional - * @deprecated since 1.4.0 in favor of {@link org.springframework.graphql.FieldValue}. */ -@Deprecated(since = "1.4.0", forRemoval = true) public final class ArgumentValue { private static final ArgumentValue EMPTY = new ArgumentValue<>(null, false); @@ -73,6 +73,15 @@ public final class ArgumentValue { return (this.value != null); } + /** + * Return {@code true} if the input value was present in the input but the value was {@code null}, + * and {@code false} otherwise. + * @since 1.4.0 + */ + public boolean isEmpty() { + return !this.omitted && this.value == null; + } + /** * Return {@code true} if the input value was omitted altogether from the * input, and {@code false} if it was provided, but possibly set to the @@ -97,6 +106,18 @@ public final class ArgumentValue { return Optional.ofNullable(this.value); } + /** + * If a value is present, performs the given action with the value, otherwise does nothing. + * @param action the action to be performed, if a value is present + * @since 1.4.0 + */ + public void ifPresent(Consumer action) { + Assert.notNull(action, "Action is required"); + if (this.value != null) { + action.accept(this.value); + } + } + @Override public boolean equals(Object other) { // This covers EMPTY and OMITTED constant diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/GraphQlArgumentBinder.java b/spring-graphql/src/main/java/org/springframework/graphql/data/GraphQlArgumentBinder.java index 96b9f3c5..984874e0 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/GraphQlArgumentBinder.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/GraphQlArgumentBinder.java @@ -40,7 +40,6 @@ import org.springframework.core.ResolvableType; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.TypeDescriptor; import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper; -import org.springframework.graphql.FieldValue; import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; @@ -68,15 +67,13 @@ import org.springframework.validation.FieldError; * *

The binder supports {@link Optional} as a wrapper around any Object or * scalar value in the target Object structure. In addition, it also supports - * {@link org.springframework.graphql.FieldValue} as a wrapper that indicates - * whether a given input argument was omitted rather than set to the - * {@literal "null"} literal. + * {@link ArgumentValue} as a wrapper that indicates whether a given input + * argument was omitted rather than set to the {@literal "null"} literal. * * @author Brian Clozel * @author Rossen Stoyanchev * @since 1.0.0 */ -@SuppressWarnings("removal") public class GraphQlArgumentBinder { @Nullable @@ -118,7 +115,7 @@ public class GraphQlArgumentBinder { * @param name the name of an argument, or {@code null} to use the full map * @param targetType the type of Object to create * @return the created Object, possibly wrapped in {@link Optional} or in - * {@link org.springframework.graphql.FieldValue}, or {@code null} if there is no value + * {@link ArgumentValue}, or {@code null} if there is no value * @throws BindException containing one or more accumulated errors from * matching and/or converting arguments to the target Object */ @@ -178,9 +175,8 @@ public class GraphQlArgumentBinder { boolean isOptional = (targetClass == Optional.class); boolean isArgumentValue = (targetClass == ArgumentValue.class); - boolean isFieldValue = (targetClass == FieldValue.class); - if (isOptional || isArgumentValue || isFieldValue) { + if (isOptional || isArgumentValue) { targetType = targetType.getNested(2); targetClass = targetType.resolve(); } @@ -206,9 +202,6 @@ public class GraphQlArgumentBinder { else if (isArgumentValue) { value = (isOmitted ? ArgumentValue.omitted() : ArgumentValue.ofNullable(value)); } - else if (isFieldValue) { - value = (isOmitted ? FieldValue.omitted() : FieldValue.ofNullable(value)); - } return value; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java index 58250300..ed2ec224 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java @@ -61,7 +61,6 @@ import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.data.domain.ScrollPosition; -import org.springframework.graphql.FieldValue; import org.springframework.graphql.data.ArgumentValue; import org.springframework.graphql.data.GraphQlArgumentBinder; import org.springframework.graphql.data.method.HandlerMethod; @@ -489,12 +488,10 @@ public class AnnotatedControllerConfigurer } @Override - @SuppressWarnings("removal") public Map getArguments() { Predicate argumentPredicate = (p) -> - (p.getParameterAnnotation(Argument.class) != null || p.getParameterType() == ArgumentValue.class || - p.getParameterType() == FieldValue.class); + (p.getParameterAnnotation(Argument.class) != null || p.getParameterType() == ArgumentValue.class); return Arrays.stream(this.mappingInfo.getHandlerMethod().getMethodParameters()) .filter(argumentPredicate) diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolver.java index 1ccb1c45..f7366853 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolver.java @@ -20,7 +20,6 @@ import graphql.schema.DataFetchingEnvironment; import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; -import org.springframework.graphql.FieldValue; import org.springframework.graphql.data.ArgumentValue; import org.springframework.graphql.data.GraphQlArgumentBinder; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; @@ -38,13 +37,12 @@ import org.springframework.validation.BindException; * parameter type. * *

This resolver also supports wrapping the target object with - * {@link FieldValue} if the application - * wants to differentiate between an input argument that was set to - * {@code null} vs not provided at all. - * When this wrapper type is used, the annotation is optional, - * and the name of the argument is derived from the method parameter name. + * {@link ArgumentValue} if the application wants to differentiate between an + * input argument that was set to {@code null} vs not provided at all. When + * this wrapper type is used, the annotation is optional, and the name of the + * argument is derived from the method parameter name. * - *

An {@link FieldValue} can also be nested within the object structure + *

An {@link ArgumentValue} can also be nested within the object structure * of an {@link Argument @Argument}-annotated method parameter. * * @author Rossen Stoyanchev @@ -52,7 +50,6 @@ import org.springframework.validation.BindException; * @since 1.0.0 * @see org.springframework.graphql.data.method.annotation.support.ArgumentsMethodArgumentResolver */ -@SuppressWarnings("removal") public class ArgumentMethodArgumentResolver implements HandlerMethodArgumentResolver { private final GraphQlArgumentBinder argumentBinder; @@ -75,8 +72,7 @@ public class ArgumentMethodArgumentResolver implements HandlerMethodArgumentReso @Override public boolean supportsParameter(MethodParameter parameter) { return (parameter.getParameterAnnotation(Argument.class) != null || - parameter.getParameterType() == ArgumentValue.class || - parameter.getParameterType() == FieldValue.class); + parameter.getParameterType() == ArgumentValue.class); } @Override @@ -107,10 +103,9 @@ public class ArgumentMethodArgumentResolver implements HandlerMethodArgumentReso return argument.name(); } } - else if (parameter.getParameterType() != ArgumentValue.class && - parameter.getParameterType() != FieldValue.class) { + else if (parameter.getParameterType() != ArgumentValue.class) { throw new IllegalStateException( - "Expected either @Argument or a method parameter of type FieldValue"); + "Expected either @Argument or a method parameter of type ArgumentValue"); } String parameterName = parameter.getParameterName(); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentValueValueExtractor.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentValueValueExtractor.java index 0104a555..bf8eb572 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentValueValueExtractor.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ArgumentValueValueExtractor.java @@ -30,7 +30,6 @@ import org.springframework.graphql.data.ArgumentValue; * @since 1.2.2 */ @UnwrapByDefault -@SuppressWarnings("removal") public final class ArgumentValueValueExtractor implements ValueExtractor> { @Override diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/FieldValueValueExtractor.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/FieldValueValueExtractor.java deleted file mode 100644 index 9819dd9f..00000000 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/FieldValueValueExtractor.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2002-2025 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.data.method.annotation.support; - -import jakarta.validation.valueextraction.ExtractedValue; -import jakarta.validation.valueextraction.UnwrapByDefault; -import jakarta.validation.valueextraction.ValueExtractor; - -import org.springframework.graphql.FieldValue; - -/** - * {@link ValueExtractor} that enables {@code @Valid} with {@link FieldValue}, - * and helps to extract the value from it. - * - * @author Rossen Stoyanchev - * @since 1.4.0 - */ -@UnwrapByDefault -public final class FieldValueValueExtractor implements ValueExtractor> { - - @Override - public void extractValues(FieldValue fieldValue, ValueReceiver receiver) { - if (!fieldValue.isOmitted()) { - receiver.value(null, fieldValue.value()); - } - } - -} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ProjectedPayloadMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ProjectedPayloadMethodArgumentResolver.java index 7658cd78..628f7a30 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ProjectedPayloadMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ProjectedPayloadMethodArgumentResolver.java @@ -27,7 +27,6 @@ import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.web.ProjectedPayload; -import org.springframework.graphql.FieldValue; import org.springframework.graphql.data.ArgumentValue; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; import org.springframework.graphql.data.method.annotation.Argument; @@ -98,16 +97,13 @@ public class ProjectedPayloadMethodArgumentResolver implements HandlerMethodArgu return (type.isInterface() && AnnotatedElementUtils.findMergedAnnotation(type, ProjectedPayload.class) != null); } - @SuppressWarnings("removal") private static Class getTargetType(MethodParameter parameter) { Class type = parameter.getParameterType(); - return (type.equals(Optional.class) || type.equals(ArgumentValue.class) || - type.equals(FieldValue.class)) ? + return (type.equals(Optional.class) || type.equals(ArgumentValue.class)) ? parameter.nested().getNestedParameterType() : parameter.getParameterType(); } @Override - @SuppressWarnings("removal") public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception { String name = (parameter.hasParameterAnnotation(Argument.class) ? @@ -116,9 +112,8 @@ public class ProjectedPayloadMethodArgumentResolver implements HandlerMethodArgu Class targetType = parameter.getParameterType(); boolean isOptional = (targetType == Optional.class); boolean isArgumentValue = (targetType == ArgumentValue.class); - boolean isFieldValue = (targetType == FieldValue.class); - if (isOptional || isArgumentValue || isFieldValue) { + if (isOptional || isArgumentValue) { targetType = parameter.nested().getNestedParameterType(); } @@ -133,10 +128,6 @@ public class ProjectedPayloadMethodArgumentResolver implements HandlerMethodArgu return (name != null && arguments.containsKey(name)) ? ArgumentValue.ofNullable(value) : ArgumentValue.omitted(); } - else if (isFieldValue) { - return (name != null && arguments.containsKey(name)) ? - FieldValue.ofNullable(value) : FieldValue.omitted(); - } else { return value; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingBeanFactoryInitializationAotProcessor.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingBeanFactoryInitializationAotProcessor.java index 514baf56..da47ab22 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingBeanFactoryInitializationAotProcessor.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingBeanFactoryInitializationAotProcessor.java @@ -43,7 +43,6 @@ import org.springframework.core.MethodParameter; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.projection.TargetAware; -import org.springframework.graphql.FieldValue; import org.springframework.graphql.data.ArgumentValue; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; import org.springframework.graphql.data.method.HandlerMethodArgumentResolverComposite; @@ -246,11 +245,9 @@ class SchemaMappingBeanFactoryInitializationAotProcessor implements BeanFactoryI } @Override - @SuppressWarnings("removal") public void apply(RuntimeHints runtimeHints) { Type parameterType = this.methodParameter.getGenericParameterType(); - if (ArgumentValue.class.isAssignableFrom(this.methodParameter.getParameterType()) || - FieldValue.class.isAssignableFrom(this.methodParameter.getParameterType())) { + if (ArgumentValue.class.isAssignableFrom(this.methodParameter.getParameterType())) { parameterType = this.methodParameter.nested().getNestedGenericParameterType(); } bindingRegistrar.registerReflectionHints(runtimeHints.reflection(), parameterType); diff --git a/spring-graphql/src/main/resources/META-INF/services/jakarta.validation.valueextraction.ValueExtractor b/spring-graphql/src/main/resources/META-INF/services/jakarta.validation.valueextraction.ValueExtractor index 9809d7cd..410cf01b 100644 --- a/spring-graphql/src/main/resources/META-INF/services/jakarta.validation.valueextraction.ValueExtractor +++ b/spring-graphql/src/main/resources/META-INF/services/jakarta.validation.valueextraction.ValueExtractor @@ -1,2 +1 @@ -org.springframework.graphql.data.method.annotation.support.FieldValueValueExtractor org.springframework.graphql.data.method.annotation.support.ArgumentValueValueExtractor \ No newline at end of file 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 af216fad..bf95ae00 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 @@ -31,7 +31,6 @@ import graphql.validation.ValidationErrorType; import org.junit.jupiter.api.Test; import org.springframework.core.ParameterizedTypeReference; -import org.springframework.graphql.FieldValue; import org.springframework.graphql.GraphQlRequest; import org.springframework.graphql.support.DefaultGraphQlRequest; @@ -59,45 +58,6 @@ class GraphQlClientTests extends GraphQlClientTestSupport { assertThat(movieCharacter).isEqualTo(MovieCharacter.create("Luke Skywalker")); } - @Test - void retrieveEntityFieldValuePresent() { - - String document = "mockRequest1"; - getGraphQlService().setDataAsJson(document, "{\"current\": {\"id\":\"spring-graphql\", \"name\":\"Spring for GraphQL\"}}"); - - Project currentProject = graphQlClient().document(document) - .retrieve("current").toEntity(Project.class) - .block(TIMEOUT); - - assertThat(currentProject).isEqualTo(new Project("spring-graphql", FieldValue.ofNullable("Spring for GraphQL"))); - } - - @Test - void retrieveEntityOmittedField() { - - String document = "mockRequest1"; - getGraphQlService().setDataAsJson(document, "{\"current\": {\"id\":\"spring-graphql\"}}"); - - Project currentProject = graphQlClient().document(document) - .retrieve("current").toEntity(Project.class) - .block(TIMEOUT); - - assertThat(currentProject).isEqualTo(new Project("spring-graphql", FieldValue.omitted())); - } - - @Test - void retrieveEntityNullField() { - - String document = "mockRequest1"; - getGraphQlService().setDataAsJson(document, "{\"current\": {\"id\":\"spring-graphql\", \"name\": null}}"); - - Project currentProject = graphQlClient().document(document) - .retrieve("current").toEntity(Project.class) - .block(TIMEOUT); - - assertThat(currentProject).isEqualTo(new Project("spring-graphql", FieldValue.ofNullable(null))); - } - @Test void retrieveEntityList() { diff --git a/spring-graphql/src/test/java/org/springframework/graphql/client/HttpGraphQlTransportIntegrationTests.java b/spring-graphql/src/test/java/org/springframework/graphql/client/HttpGraphQlTransportIntegrationTests.java index de4bd2b4..503a1c72 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/client/HttpGraphQlTransportIntegrationTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/client/HttpGraphQlTransportIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2025 the original author or authors. + * Copyright 2020-2024 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. @@ -17,28 +17,16 @@ package org.springframework.graphql.client; -import java.util.Map; -import java.util.stream.Stream; - -import com.fasterxml.jackson.databind.ObjectMapper; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; import org.springframework.graphql.Book; -import org.springframework.graphql.FieldValue; -import org.springframework.graphql.MediaTypes; import org.springframework.graphql.MockWebServerExtension; -import org.springframework.graphql.client.json.GraphQlModule; import org.springframework.http.MediaType; -import org.springframework.http.codec.json.Jackson2JsonEncoder; -import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.web.reactive.function.client.WebClient; import static org.assertj.core.api.Assertions.assertThat; @@ -51,49 +39,6 @@ import static org.assertj.core.api.Assertions.assertThat; @ExtendWith(MockWebServerExtension.class) class HttpGraphQlTransportIntegrationTests { - @ParameterizedTest - @MethodSource("fieldValues") - void shouldSerializeFieldValues(ProjectInput projectInput, String variable, MockWebServer server) throws Exception { - ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().modules(new GraphQlModule()).build(); - Jackson2JsonEncoder jsonEncoder = new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON); - WebClient webClient = WebClient.builder() - .baseUrl(server.url("/graphql").toString()) - .codecs(codecs -> codecs.defaultCodecs().jackson2JsonEncoder(jsonEncoder)) - .build(); - HttpGraphQlClient graphQlClient = HttpGraphQlClient.create(webClient); - - server.enqueue(new MockResponse().addHeader("Content-Type", MediaTypes.APPLICATION_GRAPHQL_RESPONSE) - .setBody(""" - { - "data": { - "createProject": { - "id": "spring-graphql" - } - } - } - """)); - graphQlClient.document(""" - mutation createProject($project: ProjectInput!) { - createProject($project: $project) { - id - } - } - """) - .variables(Map.of("project", projectInput)) - .executeSync(); - - assertThat(server.takeRequest().getBody().readUtf8()).contains("\"variables\":{\"project\":" + variable + "}"); - } - - static Stream fieldValues() { - return Stream.of( - Arguments.arguments(new ProjectInput("spring-graphql", FieldValue.omitted()), "{\"id\":\"spring-graphql\"}"), - Arguments.arguments(new ProjectInput("spring-graphql", FieldValue.ofNullable(null)), "{\"id\":\"spring-graphql\",\"name\":null}"), - Arguments.arguments(new ProjectInput("spring-graphql", FieldValue.ofNullable("Spring for GraphQL")), "{\"id\":\"spring-graphql\",\"name\":\"Spring for GraphQL\"}") - ); - } - - @Test void shouldStreamSubscriptionResultsOverSse(MockWebServer server) { WebClient webClient = WebClient.create(server.url("/graphql").toString()); @@ -150,8 +95,4 @@ class HttpGraphQlTransportIntegrationTests { } - public record ProjectInput(String id, FieldValue name) { - - } - } diff --git a/spring-graphql/src/test/java/org/springframework/graphql/client/Project.java b/spring-graphql/src/test/java/org/springframework/graphql/client/Project.java deleted file mode 100644 index 4c756b2f..00000000 --- a/spring-graphql/src/test/java/org/springframework/graphql/client/Project.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2020-2025 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 org.springframework.graphql.FieldValue; - -public record Project(String id, FieldValue name) { - -} diff --git a/spring-graphql/src/test/java/org/springframework/graphql/client/json/FieldValueJsonTests.java b/spring-graphql/src/test/java/org/springframework/graphql/client/json/FieldValueJsonTests.java deleted file mode 100644 index 74212213..00000000 --- a/spring-graphql/src/test/java/org/springframework/graphql/client/json/FieldValueJsonTests.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2020-2025 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.json; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -import org.springframework.graphql.FieldValue; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link org.springframework.graphql.FieldValue} support in {@link GraphQlModule}. - */ -class FieldValueJsonTests { - - private final ObjectMapper objectMapper = new ObjectMapper().registerModule(new GraphQlModule()); - - @Nested - class DeserializationTests { - - @Test - void valueIsOmittedWhenJsonKeyMissing() throws Exception { - Library library = objectMapper.readValue("{}", Library.class); - - assertThat(library.name()).isNotNull() - .satisfies(name -> assertThat(name.isOmitted()).isTrue()); - } - - @Test - void valueIsEmptyWhenJsonValueIsNull() throws Exception { - Library library = objectMapper.readValue("{\"name\":null}", Library.class); - - assertThat(library.name()).isNotNull() - .satisfies(name -> assertThat(name.isEmpty()).isTrue()); - } - - @Test - void valueIsPresentWhenJsonValueIsNotNull() throws Exception { - Library library = objectMapper.readValue("{\"name\":\"The Library\"}", Library.class); - - assertThat(library.name()).isNotNull() - .satisfies( - name -> assertThat(name.isPresent()).isTrue(), - name -> assertThat(name.value()).isEqualTo("The Library") - ); - } - - } - - @Nested - class SerializationTests { - - @Test - void skipJsonAttributeWhenValueOmitted() throws Exception { - Library library = new Library(FieldValue.omitted()); - - assertThat(objectMapper.writeValueAsString(library)).isEqualTo("{}"); - } - - @Test - void nullJsonValueWhenValueIsNull() throws Exception { - Library library = new Library(FieldValue.ofNullable(null)); - - assertThat(objectMapper.writeValueAsString(library)).isEqualTo("{\"name\":null}"); - } - - @Test - void emptyJsonValueWhenValueIsEmpty() throws Exception { - Library library = new Library(FieldValue.ofNullable("")); - - assertThat(objectMapper.writeValueAsString(library)).isEqualTo("{\"name\":\"\"}"); - } - - @Test - void jsonValueWhenValueIsPresent() throws Exception { - Library library = new Library(FieldValue.ofNullable("The Library")); - - assertThat(objectMapper.writeValueAsString(library)).isEqualTo("{\"name\":\"The Library\"}"); - } - - } - - public record Library(FieldValue name) { - - } - -} diff --git a/spring-graphql/src/test/java/org/springframework/graphql/FieldValueTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/ArgumentValueTests.java similarity index 71% rename from spring-graphql/src/test/java/org/springframework/graphql/FieldValueTests.java rename to spring-graphql/src/test/java/org/springframework/graphql/data/ArgumentValueTests.java index 918ffc22..fdfa4f0a 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/FieldValueTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/ArgumentValueTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.graphql; +package org.springframework.graphql.data; import java.util.concurrent.atomic.AtomicBoolean; @@ -23,14 +23,14 @@ import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link FieldValue}. + * Tests for {@link ArgumentValue}. * @author Brian Clozel */ -class FieldValueTests { +class ArgumentValueTests { @Test void existingValueShouldBePresent() { - FieldValue message = FieldValue.ofNullable("hello"); + ArgumentValue message = ArgumentValue.ofNullable("hello"); assertThat(message.isOmitted()).isFalse(); assertThat(message.isPresent()).isTrue(); assertThat(message.isEmpty()).isFalse(); @@ -38,7 +38,7 @@ class FieldValueTests { @Test void nullValueShouldBePresent() { - FieldValue message = FieldValue.ofNullable(null); + ArgumentValue message = ArgumentValue.ofNullable(null); assertThat(message.isOmitted()).isFalse(); assertThat(message.isPresent()).isFalse(); assertThat(message.isEmpty()).isTrue(); @@ -46,7 +46,7 @@ class FieldValueTests { @Test void noValueShouldBeOmitted() { - FieldValue message = FieldValue.omitted(); + ArgumentValue message = ArgumentValue.omitted(); assertThat(message.isOmitted()).isTrue(); assertThat(message.isPresent()).isFalse(); assertThat(message.isEmpty()).isFalse(); @@ -54,29 +54,29 @@ class FieldValueTests { @Test void asOptionalShouldMapOmitted() { - assertThat(FieldValue.omitted().asOptional()).isEmpty(); - assertThat(FieldValue.ofNullable(null).asOptional()).isEmpty(); - assertThat(FieldValue.ofNullable("hello").asOptional()).isPresent(); + assertThat(ArgumentValue.omitted().asOptional()).isEmpty(); + assertThat(ArgumentValue.ofNullable(null).asOptional()).isEmpty(); + assertThat(ArgumentValue.ofNullable("hello").asOptional()).isPresent(); } @Test void ifPresentShouldExecuteWhenValue() { AtomicBoolean called = new AtomicBoolean(); - FieldValue.ofNullable("hello").ifPresent(value -> called.set(true)); + ArgumentValue.ofNullable("hello").ifPresent(value -> called.set(true)); assertThat(called.get()).isTrue(); } @Test void ifPresentShouldSkipWhenNull() { AtomicBoolean called = new AtomicBoolean(); - FieldValue.ofNullable(null).ifPresent(value -> called.set(true)); + ArgumentValue.ofNullable(null).ifPresent(value -> called.set(true)); assertThat(called.get()).isFalse(); } @Test void ifPresentShouldSkipWhenOmitted() { AtomicBoolean called = new AtomicBoolean(); - FieldValue.omitted().ifPresent(value -> called.set(true)); + ArgumentValue.omitted().ifPresent(value -> called.set(true)); assertThat(called.get()).isFalse(); } diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/GraphQlArgumentBinderTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/GraphQlArgumentBinderTests.java index b9356b7b..680802e6 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/GraphQlArgumentBinderTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/GraphQlArgumentBinderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2025 the original author or authors. + * Copyright 2020-2023 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. @@ -38,7 +38,6 @@ import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.graphql.Book; -import org.springframework.graphql.FieldValue; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.lang.Nullable; import org.springframework.validation.BindException; @@ -54,7 +53,6 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; * @author Brian Clozel * @author Rossen Stoyanchev */ -@SuppressWarnings("removal") class GraphQlArgumentBinderTests { private final ObjectMapper mapper = new ObjectMapper(); @@ -250,30 +248,6 @@ class GraphQlArgumentBinderTests { assertThat(itemBean.getName().isPresent()).isFalse(); } - @Test - void primaryConstructorWithOptionalFieldBeanArgument() throws Exception { - - ResolvableType targetType = - ResolvableType.forClass(PrimaryConstructorOptionalFieldItemBean.class); - - Object result = bind( - "{\"item\":{\"name\":\"Item name\",\"age\":\"30\"},\"name\":\"Hello\"}", targetType); - - assertThat(result).isInstanceOf(PrimaryConstructorOptionalFieldItemBean.class).isNotNull(); - PrimaryConstructorOptionalFieldItemBean itemBean = (PrimaryConstructorOptionalFieldItemBean) result; - - assertThat(itemBean.getItem().value().getName()).isEqualTo("Item name"); - assertThat(itemBean.getItem().value().getAge()).isEqualTo(30); - assertThat(itemBean.getName().value()).isEqualTo("Hello"); - - result = bind("{\"key\":{}}", targetType); - itemBean = (PrimaryConstructorOptionalFieldItemBean) result; - - assertThat(itemBean).isNotNull(); - assertThat(itemBean.getItem().isOmitted()).isTrue(); - assertThat(itemBean.getName().isPresent()).isFalse(); - } - @Test void primaryConstructorWithNestedBeanList() throws Exception { @@ -596,26 +570,6 @@ class GraphQlArgumentBinderTests { } } - static class PrimaryConstructorOptionalFieldItemBean { - - private final FieldValue name; - - private final FieldValue item; - - public PrimaryConstructorOptionalFieldItemBean(FieldValue name, FieldValue item) { - this.name = name; - this.item = item; - } - - public FieldValue getName() { - return this.name; - } - - public FieldValue getItem() { - return item; - } - } - @SuppressWarnings("unused") static class NoPrimaryConstructorBean { diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolverTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolverTests.java index 8c8f665a..1293fcab 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolverTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2025 the original author or authors. + * Copyright 2020-2023 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. @@ -25,7 +25,6 @@ import org.junit.jupiter.api.Test; import org.springframework.core.MethodParameter; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.graphql.Book; -import org.springframework.graphql.FieldValue; import org.springframework.graphql.data.ArgumentValue; import org.springframework.graphql.data.GraphQlArgumentBinder; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; @@ -54,9 +53,6 @@ class ArgumentMethodArgumentResolverTests extends ArgumentResolverTestSupport { param = methodParam(BookController.class, "addBook", ArgumentValue.class); assertThat(this.resolver.supportsParameter(param)).isTrue(); - param = methodParam(BookController.class, "addBook", FieldValue.class); - assertThat(this.resolver.supportsParameter(param)).isTrue(); - param = methodParam(BookController.class, "rawArgumentValue", Map.class); assertThat(this.resolver.supportsParameter(param)).isTrue(); @@ -85,7 +81,7 @@ class ArgumentMethodArgumentResolverTests extends ArgumentResolverTestSupport { } @Test - void shouldResolveJavaBeanArgumentWithArgumentWrapper() throws Exception { + void shouldResolveJavaBeanArgumentWithWrapper() throws Exception { Object result = this.resolver.resolveArgument( methodParam(BookController.class, "addBook", ArgumentValue.class), environment("{\"bookInput\": { \"name\": \"test name\", \"authorId\": 42} }")); @@ -98,20 +94,6 @@ class ArgumentMethodArgumentResolverTests extends ArgumentResolverTestSupport { .hasFieldOrPropertyWithValue("authorId", 42L); } - @Test - void shouldResolveJavaBeanArgumentWithFieldWrapper() throws Exception { - Object result = this.resolver.resolveArgument( - methodParam(BookController.class, "addBook", FieldValue.class), - environment("{\"bookInput\": { \"name\": \"test name\", \"authorId\": 42} }")); - - assertThat(result) - .isNotNull() - .isInstanceOf(FieldValue.class) - .extracting(value -> ((FieldValue) value).value()) - .hasFieldOrPropertyWithValue("name", "test name") - .hasFieldOrPropertyWithValue("authorId", 42L); - } - @Test void shouldResolveListOfJavaBeansArgument() throws Exception { Object result = this.resolver.resolveArgument( @@ -170,11 +152,6 @@ class ArgumentMethodArgumentResolverTests extends ArgumentResolverTestSupport { return null; } - @MutationMapping - public Book addBook(FieldValue bookInput) { - return null; - } - @MutationMapping public List addBooks(@Argument List books) { return null; diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentsMethodArgumentResolverTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentsMethodArgumentResolverTests.java index 9a748bf0..66ef2ed2 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentsMethodArgumentResolverTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentsMethodArgumentResolverTests.java @@ -25,7 +25,7 @@ import org.junit.jupiter.api.Test; import org.springframework.core.MethodParameter; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.graphql.Book; -import org.springframework.graphql.FieldValue; +import org.springframework.graphql.data.ArgumentValue; import org.springframework.graphql.data.GraphQlArgumentBinder; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; import org.springframework.graphql.data.method.annotation.Arguments; @@ -109,15 +109,15 @@ class ArgumentsMethodArgumentResolverTests extends ArgumentResolverTestSupport { @SuppressWarnings({"NotNullFieldNotInitialized", "unused"}) static class BookInput { - FieldValue name; + ArgumentValue name; Long authorId; - public FieldValue getName() { + public ArgumentValue getName() { return this.name; } - public void setName(FieldValue name) { + public void setName(ArgumentValue name) { this.name = name; } diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ProjectedPayloadMethodArgumentResolverTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ProjectedPayloadMethodArgumentResolverTests.java index 85da6d55..70f08eb0 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ProjectedPayloadMethodArgumentResolverTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ProjectedPayloadMethodArgumentResolverTests.java @@ -26,7 +26,7 @@ import org.springframework.context.support.StaticApplicationContext; import org.springframework.core.MethodParameter; import org.springframework.data.web.ProjectedPayload; import org.springframework.graphql.Book; -import org.springframework.graphql.FieldValue; +import org.springframework.graphql.data.ArgumentValue; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.QueryMapping; import org.springframework.stereotype.Controller; @@ -54,7 +54,7 @@ class ProjectedPayloadMethodArgumentResolverTests extends ArgumentResolverTestSu testSupports("projection", BookProjection.class, true); testSupports("optionalProjection", Optional.class, true); testSupports("optionalString", Optional.class, false); - testSupports("fieldValueProjection", FieldValue.class, true); + testSupports("argumentValueProjection", ArgumentValue.class, true); } void testSupports(String methodName, Class methodParamType, boolean supported) { @@ -86,39 +86,39 @@ class ProjectedPayloadMethodArgumentResolverTests extends ArgumentResolverTestSu } @Test - void fieldValuePresent() throws Exception { + void argumentValuePresent() throws Exception { Object result = this.resolver.resolveArgument( - methodParam(BookController.class, "fieldValueProjection", FieldValue.class), + methodParam(BookController.class, "argumentValueProjection", ArgumentValue.class), environment("{ \"where\" : { \"author\" : \"Orwell\" }}")); - assertThat(result).isNotNull().isInstanceOf(FieldValue.class); - BookProjection book = ((FieldValue) result).value(); + assertThat(result).isNotNull().isInstanceOf(ArgumentValue.class); + BookProjection book = ((ArgumentValue) result).value(); assertThat(book.getAuthor()).isEqualTo("Orwell"); } @Test - void fieldValueSetToNull() throws Exception { + void argumentValueSetToNull() throws Exception { Object result = this.resolver.resolveArgument( - methodParam(BookController.class, "fieldValueProjection", FieldValue.class), + methodParam(BookController.class, "argumentValueProjection", ArgumentValue.class), environment("{ \"where\" : null}")); - assertThat(result).isNotNull().isInstanceOf(FieldValue.class); - FieldValue value = ((FieldValue) result); + assertThat(result).isNotNull().isInstanceOf(ArgumentValue.class); + ArgumentValue value = ((ArgumentValue) result); assertThat(value.isPresent()).isFalse(); assertThat(value.isOmitted()).isFalse(); } @Test - void fieldValueIsOmitted() throws Exception { + void argumentValueIsOmitted() throws Exception { Object result = this.resolver.resolveArgument( - methodParam(BookController.class, "fieldValueProjection", FieldValue.class), + methodParam(BookController.class, "argumentValueProjection", ArgumentValue.class), environment("{}")); - assertThat(result).isNotNull().isInstanceOf(FieldValue.class); - FieldValue value = ((FieldValue) result); + assertThat(result).isNotNull().isInstanceOf(ArgumentValue.class); + ArgumentValue value = ((ArgumentValue) result); assertThat(value.isPresent()).isFalse(); assertThat(value.isOmitted()).isTrue(); } @@ -153,7 +153,7 @@ class ProjectedPayloadMethodArgumentResolverTests extends ArgumentResolverTestSu } @QueryMapping - public List fieldValueProjection(@Argument(name = "where") FieldValue projection) { + public List argumentValueProjection(@Argument(name = "where") ArgumentValue projection) { return null; } diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingBeanFactoryInitializationAotProcessorTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingBeanFactoryInitializationAotProcessorTests.java index fede9c68..295aa563 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingBeanFactoryInitializationAotProcessorTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingBeanFactoryInitializationAotProcessorTests.java @@ -58,7 +58,7 @@ import org.springframework.data.projection.TargetAware; import org.springframework.data.web.ProjectedPayload; import org.springframework.graphql.Author; import org.springframework.graphql.Book; -import org.springframework.graphql.FieldValue; +import org.springframework.graphql.data.ArgumentValue; import org.springframework.graphql.data.federation.EntityMapping; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.BatchMapping; @@ -120,12 +120,12 @@ class SchemaMappingBeanFactoryInitializationAotProcessorTests { } @Test - void registerBindingReflectionOnFieldValue() { - processBeanClasses(FieldValueController.class); - assertThatIntrospectionOnMethodsHintRegisteredForType(FieldValueController.class); - assertThatInvocationHintRegisteredForMethods(FieldValueController.class, "addBook"); + void registerBindingReflectionOnArgumentValue() { + processBeanClasses(ArgumentValueController.class); + assertThatIntrospectionOnMethodsHintRegisteredForType(ArgumentValueController.class); + assertThatInvocationHintRegisteredForMethods(ArgumentValueController.class, "addBook"); assertThatHintsForJavaBeanBindingRegisteredForTypes(Book.class, BookInput.class); - assertThatHintsAreNotRegisteredForTypes(FieldValue.class); + assertThatHintsAreNotRegisteredForTypes(ArgumentValue.class); } @Test @@ -173,9 +173,9 @@ class SchemaMappingBeanFactoryInitializationAotProcessorTests { } @Controller - static class FieldValueController { + static class ArgumentValueController { @MutationMapping - public Book addBook(FieldValue bookInput) { + public Book addBook(ArgumentValue bookInput) { return null; } diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ValidationHelperTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ValidationHelperTests.java index d7a31fa4..4b0abbf4 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ValidationHelperTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ValidationHelperTests.java @@ -36,7 +36,7 @@ import org.assertj.core.api.ThrowableAssert; import org.junit.jupiter.api.Test; import org.springframework.beans.BeanUtils; -import org.springframework.graphql.FieldValue; +import org.springframework.graphql.data.ArgumentValue; import org.springframework.graphql.data.method.HandlerMethod; import org.springframework.validation.annotation.Validated; @@ -71,20 +71,20 @@ class ValidationHelperTests { BiConsumer validator2 = validateFunction(MyBean.class, "myValidatedParameterMethod"); assertViolation(() -> validator2.accept(bean, new Object[] {new ConstrainedInput(100)}), "integerValue"); - BiConsumer validator3 = validateFunction(MyBean.class, "myValidFieldValue"); - assertViolation(() -> validator3.accept(bean, new Object[] {FieldValue.ofNullable("")}), "myValidFieldValue.arg0"); + BiConsumer validator3 = validateFunction(MyBean.class, "myValidArgumentValue"); + assertViolation(() -> validator3.accept(bean, new Object[] {ArgumentValue.ofNullable("")}), "myValidArgumentValue.arg0"); // Validate that an explicit null value is validated. - assertViolation(() -> validator3.accept(bean, new Object[] {FieldValue.ofNullable(null)}), "myValidFieldValue.arg0"); + assertViolation(() -> validator3.accept(bean, new Object[] {ArgumentValue.ofNullable(null)}), "myValidArgumentValue.arg0"); } @Test - void shouldNotRaiseValidationErrorForOmittedFieldValue() { + void shouldNotRaiseValidationErrorForOmittedArgumentValue() { MyBean bean = new MyBean(); // Validate that an omitted value is allowed. - BiConsumer validator3 = validateFunction(MyBean.class, "myValidFieldValue"); - validator3.accept(bean, new Object[] {FieldValue.omitted()}); + BiConsumer validator3 = validateFunction(MyBean.class, "myValidArgumentValue"); + validator3.accept(bean, new Object[] {ArgumentValue.omitted()}); } @Test @@ -173,7 +173,7 @@ class ValidationHelperTests { return null; } - public Object myValidFieldValue(@Valid FieldValue<@NotBlank String> arg0) { + public Object myValidArgumentValue(@Valid ArgumentValue<@NotBlank String> arg0) { return null; } }