Apply checkstyle changes to spring-graphql

See gh-943
This commit is contained in:
Brian Clozel
2024-04-04 22:05:00 +02:00
parent b66eb64241
commit 163027e525
219 changed files with 1297 additions and 983 deletions

View File

@@ -61,7 +61,7 @@ public interface GraphQlRequest {
/**
* Convert the request to a {@link Map} as defined in
* <a href="https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md">GraphQL over HTTP</a> and
* <a href="https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md">GraphQL over WebSocket</a>:
* <a href="https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md">GraphQL over WebSocket</a>.
* <table>
* <tr><th>Key</th><th>Value</th></tr>
* <tr><td>query</td><td>{@link #getDocument() document}</td></tr>

View File

@@ -1,3 +1,19 @@
/*
* 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.
* 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.List;

View File

@@ -43,7 +43,7 @@ public interface ResponseField {
* </ul>
* @deprecated as of 1.0.3 in favor of checking via {@link #getValue()}
*/
@Deprecated
@Deprecated(since = "1.0.3", forRemoval = true)
boolean hasValue();
/**
@@ -90,7 +90,7 @@ public interface ResponseField {
* @deprecated since 1.0.3 in favor of {@link #getErrors()}
*/
@Nullable
@Deprecated
@Deprecated(since = "1.0.3", forRemoval = true)
ResponseError getError();
/**

View File

@@ -46,6 +46,7 @@ import org.springframework.util.ClassUtils;
* agnostic {@code GraphQlClient}. A transport specific extension can then wrap
* this default tester by extending {@link AbstractDelegatingGraphQlClient}.
*
* @param <B> the builder type
* @author Rossen Stoyanchev
* @since 1.0.0
* @see AbstractDelegatingGraphQlClient
@@ -114,6 +115,8 @@ public abstract class AbstractGraphQlClientBuilder<B extends AbstractGraphQlClie
* Transport-specific subclasses can provide their JSON {@code Encoder} and
* {@code Decoder} for use at the client level, for mapping response data
* to some target entity type.
* @param encoder the JSON encoder to use
* @param decoder the JSON decoder to use
*/
protected void setJsonCodecs(Encoder<?> encoder, Decoder<?> decoder) {
this.jsonEncoder = encoder;
@@ -122,6 +125,7 @@ public abstract class AbstractGraphQlClientBuilder<B extends AbstractGraphQlClie
/**
* Variant of {@link #setJsonCodecs} for setting each codec individually.
* @param encoder the JSON encoder to use
*/
protected void setJsonEncoder(Encoder<?> encoder) {
this.jsonEncoder = encoder;
@@ -137,6 +141,7 @@ public abstract class AbstractGraphQlClientBuilder<B extends AbstractGraphQlClie
/**
* Variant of {@link #setJsonCodecs} for setting each codec individually.
* @param decoder the JSON decoder to use
*/
protected void setJsonDecoder(Decoder<?> decoder) {
this.jsonDecoder = decoder;
@@ -161,12 +166,13 @@ public abstract class AbstractGraphQlClientBuilder<B extends AbstractGraphQlClie
/**
* Build the default transport-agnostic client that subclasses can then wrap
* with {@link AbstractDelegatingGraphQlClient}.
* @param transport the GraphQL transport to be used by the client
*/
protected GraphQlClient buildGraphQlClient(GraphQlTransport transport) {
if (jackson2Present) {
this.jsonEncoder = (this.jsonEncoder == null ? DefaultJackson2Codecs.encoder() : this.jsonEncoder);
this.jsonDecoder = (this.jsonDecoder == null ? DefaultJackson2Codecs.decoder() : this.jsonDecoder);
this.jsonEncoder = (this.jsonEncoder == null) ? DefaultJackson2Codecs.encoder() : this.jsonEncoder;
this.jsonDecoder = (this.jsonDecoder == null) ? DefaultJackson2Codecs.decoder() : this.jsonDecoder;
}
return new DefaultGraphQlClient(
@@ -177,32 +183,32 @@ public abstract class AbstractGraphQlClientBuilder<B extends AbstractGraphQlClie
* Return a {@code Consumer} to initialize new builders from "this" builder.
*/
protected Consumer<AbstractGraphQlClientBuilder<?>> getBuilderInitializer() {
return builder -> {
builder.interceptors(interceptorList -> interceptorList.addAll(interceptors));
builder.documentSource(documentSource);
return (builder) -> {
builder.interceptors((interceptorList) -> interceptorList.addAll(this.interceptors));
builder.documentSource(this.documentSource);
builder.setJsonCodecs(getEncoder(), getDecoder());
};
}
private Chain createExecuteChain(GraphQlTransport transport) {
Chain chain = request -> transport.execute(request).map(response ->
Chain chain = (request) -> transport.execute(request).map((response) ->
new DefaultClientGraphQlResponse(request, response, getEncoder(), getDecoder()));
return this.interceptors.stream()
.reduce(GraphQlClientInterceptor::andThen)
.map(interceptor -> (Chain) (request) -> interceptor.intercept(request, chain))
.map((interceptor) -> (Chain) (request) -> interceptor.intercept(request, chain))
.orElse(chain);
}
private SubscriptionChain createExecuteSubscriptionChain(GraphQlTransport transport) {
SubscriptionChain chain = request -> transport.executeSubscription(request)
.map(response -> new DefaultClientGraphQlResponse(request, response, getEncoder(), getDecoder()));
SubscriptionChain chain = (request) -> transport.executeSubscription(request)
.map((response) -> new DefaultClientGraphQlResponse(request, response, getEncoder(), getDecoder()));
return this.interceptors.stream()
.reduce(GraphQlClientInterceptor::andThen)
.map(interceptor -> (SubscriptionChain) (request) -> interceptor.interceptSubscription(request, chain))
.map((interceptor) -> (SubscriptionChain) (request) -> interceptor.interceptSubscription(request, chain))
.orElse(chain);
}

View File

@@ -32,10 +32,12 @@ public interface ClientGraphQlResponse extends GraphQlResponse {
/**
* {@inheritDoc}
*/
@Override
ClientResponseField field(String path);
/**
* Decode the full response map to the given target type.
* @param <D> the target type
* @param type the target class
* @return the decoded value, or never {@code null}
* @throws FieldAccessException if the response is not {@link #isValid() valid}
@@ -44,7 +46,8 @@ public interface ClientGraphQlResponse extends GraphQlResponse {
/**
* Variant of {@link #toEntity(Class)} with a {@link ParameterizedTypeReference}.
* @param type the target type
* @param <D> the target type
* @param type the target parameterized type
* @return the decoded value, or never {@code null}
* @throws FieldAccessException if the response is not {@link #isValid() valid}
*/

View File

@@ -34,6 +34,7 @@ public interface ClientResponseField extends ResponseField {
/**
* Decode the field to an entity of the given type.
* @param <D> the entity type
* @param entityType the type to convert to
* @return the decoded entity, or {@code null} if the field is {@code null}
* but otherwise there are no errors
@@ -46,12 +47,15 @@ public interface ClientResponseField extends ResponseField {
/**
* Variant of {@link #toEntity(Class)} with a {@link ParameterizedTypeReference}.
* @param <D> the entity type
* @param entityType the type to convert to
*/
@Nullable
<D> D toEntity(ParameterizedTypeReference<D> entityType);
/**
* Variant of {@link #toEntity(Class)} to decode to a list of entities.
* @param <D> the entity type
* @param elementType the type of elements in the list
* @return the list of decoded entities, or an empty list if the field is
* {@code null} but otherwise there are no errors
@@ -61,15 +65,16 @@ public interface ClientResponseField extends ResponseField {
*/
<D> List<D> toEntityList(Class<D> elementType);
/**
* Variant of {@link #toEntity(Class)} to decode to a list of entities.
* @param elementType the type of elements in the list
* @return the list of decoded entities, or an empty list if the field is
* {@code null} but otherwise there are no errors
* @throws FieldAccessException if the target field is {@code null} and the
* response is not {@link GraphQlResponse#isValid() valid} or the field has
* {@link ResponseField#getErrors() errors}.
*/
/**
* Variant of {@link #toEntity(Class)} to decode to a list of entities.
* @param <D> the entity type
* @param elementType the type of elements in the list
* @return the list of decoded entities, or an empty list if the field is
* {@code null} but otherwise there are no errors
* @throws FieldAccessException if the target field is {@code null} and the
* response is not {@link GraphQlResponse#isValid() valid} or the field has
* {@link ResponseField#getErrors() errors}.
*/
<D> List<D> toEntityList(ParameterizedTypeReference<D> elementType);
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.client;
import java.util.List;
@@ -37,7 +38,6 @@ import org.springframework.web.reactive.socket.WebSocketSession;
* Helper class for encoding and decoding GraphQL messages.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class CodecDelegate {
@@ -60,14 +60,14 @@ final class CodecDelegate {
static Encoder<?> findJsonEncoder(CodecConfigurer configurer) {
return findJsonEncoder(configurer.getWriters().stream()
.filter(writer -> writer instanceof EncoderHttpMessageWriter)
.map(writer -> ((EncoderHttpMessageWriter<?>) writer).getEncoder()));
.filter((writer) -> writer instanceof EncoderHttpMessageWriter)
.map((writer) -> ((EncoderHttpMessageWriter<?>) writer).getEncoder()));
}
static Decoder<?> findJsonDecoder(CodecConfigurer configurer) {
return findJsonDecoder(configurer.getReaders().stream()
.filter(reader -> reader instanceof DecoderHttpMessageReader)
.map(reader -> ((DecoderHttpMessageReader<?>) reader).getDecoder()));
.filter((reader) -> reader instanceof DecoderHttpMessageReader)
.map((reader) -> ((DecoderHttpMessageReader<?>) reader).getDecoder()));
}
static Encoder<?> findJsonEncoder(List<Encoder<?>> encoders) {
@@ -80,26 +80,26 @@ final class CodecDelegate {
private static Encoder<?> findJsonEncoder(Stream<Encoder<?>> stream) {
return stream
.filter(encoder -> encoder.canEncode(MESSAGE_TYPE, MediaType.APPLICATION_JSON))
.filter((encoder) -> encoder.canEncode(MESSAGE_TYPE, MediaType.APPLICATION_JSON))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("No JSON Encoder"));
}
private static Decoder<?> findJsonDecoder(Stream<Decoder<?>> decoderStream) {
return decoderStream
.filter(decoder -> decoder.canDecode(MESSAGE_TYPE, MediaType.APPLICATION_JSON))
.filter((decoder) -> decoder.canDecode(MESSAGE_TYPE, MediaType.APPLICATION_JSON))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("No JSON Decoder"));
}
public CodecConfigurer getCodecConfigurer() {
CodecConfigurer getCodecConfigurer() {
return this.codecConfigurer;
}
@SuppressWarnings("unchecked")
public <T> WebSocketMessage encode(WebSocketSession session, GraphQlWebSocketMessage message) {
<T> WebSocketMessage encode(WebSocketSession session, GraphQlWebSocketMessage message) {
DataBuffer buffer = ((Encoder<T>) this.encoder).encodeValue(
(T) message, session.bufferFactory(), MESSAGE_TYPE, MimeTypeUtils.APPLICATION_JSON, null);
@@ -108,7 +108,7 @@ final class CodecDelegate {
}
@SuppressWarnings("ConstantConditions")
public GraphQlWebSocketMessage decode(WebSocketMessage webSocketMessage) {
GraphQlWebSocketMessage decode(WebSocketMessage webSocketMessage) {
DataBuffer buffer = DataBufferUtils.retain(webSocketMessage.getPayload());
return (GraphQlWebSocketMessage) this.decoder.decode(buffer, MESSAGE_TYPE, null, null);
}

View File

@@ -27,7 +27,6 @@ import org.springframework.lang.Nullable;
* Default implementation of {@link ClientGraphQlRequest}.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class DefaultClientGraphQlRequest extends DefaultGraphQlRequest implements ClientGraphQlRequest {

View File

@@ -26,7 +26,6 @@ import org.springframework.graphql.GraphQlResponse;
* Default implementation of {@link ClientGraphQlResponse}.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class DefaultClientGraphQlResponse extends ResponseMapGraphQlResponse implements ClientGraphQlResponse {

View File

@@ -40,7 +40,6 @@ import org.springframework.util.MimeTypeUtils;
* support for decoding.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class DefaultClientResponseField implements ClientResponseField {
@@ -55,7 +54,7 @@ final class DefaultClientResponseField implements ClientResponseField {
}
@SuppressWarnings("deprecation")
@SuppressWarnings("removal")
@Override
public boolean hasValue() {
return (this.field.getValue() != null);
@@ -76,7 +75,7 @@ final class DefaultClientResponseField implements ClientResponseField {
return this.field.getValue();
}
@SuppressWarnings("deprecation")
@SuppressWarnings("removal")
@Override
public ResponseError getError() {
return this.field.getError();
@@ -100,13 +99,13 @@ final class DefaultClientResponseField implements ClientResponseField {
@Override
public <D> List<D> toEntityList(Class<D> elementType) {
List<D> list = toEntity(ResolvableType.forClassWithGenerics(List.class, elementType));
return (list != null ? list : Collections.emptyList());
return (list != null) ? list : Collections.emptyList();
}
@Override
public <D> List<D> toEntityList(ParameterizedTypeReference<D> elementType) {
List<D> list = toEntity(ResolvableType.forClassWithGenerics(List.class, ResolvableType.forType(elementType)));
return (list != null ? list : Collections.emptyList());
return (list != null) ? list : Collections.emptyList();
}
@SuppressWarnings("unchecked")

View File

@@ -34,7 +34,6 @@ import org.springframework.util.Assert;
* Default, final {@link GraphQlClient} implementation for use with any transport.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class DefaultGraphQlClient implements GraphQlClient {
@@ -155,22 +154,22 @@ final class DefaultGraphQlClient implements GraphQlClient {
@Override
public Mono<ClientGraphQlResponse> execute() {
return initRequest().flatMap(request -> executeChain.next(request)
return initRequest().flatMap((request) -> DefaultGraphQlClient.this.executeChain.next(request)
.onErrorResume(
ex -> !(ex instanceof GraphQlClientException),
ex -> Mono.error(new GraphQlTransportException(ex, request))));
(ex) -> !(ex instanceof GraphQlClientException),
(ex) -> Mono.error(new GraphQlTransportException(ex, request))));
}
@Override
public Flux<ClientGraphQlResponse> executeSubscription() {
return initRequest().flatMapMany(request -> executeSubscriptionChain.next(request)
return initRequest().flatMapMany((request) -> DefaultGraphQlClient.this.executeSubscriptionChain.next(request)
.onErrorResume(
ex -> !(ex instanceof GraphQlClientException),
ex -> Mono.error(new GraphQlTransportException(ex, request))));
(ex) -> !(ex instanceof GraphQlClientException),
(ex) -> Mono.error(new GraphQlTransportException(ex, request))));
}
private Mono<ClientGraphQlRequest> initRequest() {
return this.documentMono.map(document ->
return this.documentMono.map((document) ->
new DefaultClientGraphQlRequest(document, this.operationName, this.variables, this.extensions, this.attributes));
}
@@ -198,7 +197,7 @@ final class DefaultGraphQlClient implements GraphQlClient {
throw new FieldAccessException(
((DefaultClientGraphQlResponse) response).getRequest(), response, field);
}
return (field.getValue() != null ? field : null);
return (field.getValue() != null) ? field : null;
}
}
@@ -215,27 +214,27 @@ final class DefaultGraphQlClient implements GraphQlClient {
@Override
public <D> Mono<D> toEntity(Class<D> entityType) {
return this.responseMono.mapNotNull(this::getValidField).mapNotNull(field -> field.toEntity(entityType));
return this.responseMono.mapNotNull(this::getValidField).mapNotNull((field) -> field.toEntity(entityType));
}
@Override
public <D> Mono<D> toEntity(ParameterizedTypeReference<D> entityType) {
return this.responseMono.mapNotNull(this::getValidField).mapNotNull(field -> field.toEntity(entityType));
return this.responseMono.mapNotNull(this::getValidField).mapNotNull((field) -> field.toEntity(entityType));
}
@Override
public <D> Mono<List<D>> toEntityList(Class<D> elementType) {
return this.responseMono.map(response -> {
return this.responseMono.map((response) -> {
ClientResponseField field = getValidField(response);
return (field != null ? field.toEntityList(elementType) : Collections.emptyList());
return (field != null) ? field.toEntityList(elementType) : Collections.emptyList();
});
}
@Override
public <D> Mono<List<D>> toEntityList(ParameterizedTypeReference<D> elementType) {
return this.responseMono.map(response -> {
return this.responseMono.map((response) -> {
ClientResponseField field = getValidField(response);
return (field != null ? field.toEntityList(elementType) : Collections.emptyList());
return (field != null) ? field.toEntityList(elementType) : Collections.emptyList();
});
}
@@ -253,27 +252,27 @@ final class DefaultGraphQlClient implements GraphQlClient {
@Override
public <D> Flux<D> toEntity(Class<D> entityType) {
return this.responseFlux.mapNotNull(this::getValidField).mapNotNull(field -> field.toEntity(entityType));
return this.responseFlux.mapNotNull(this::getValidField).mapNotNull((field) -> field.toEntity(entityType));
}
@Override
public <D> Flux<D> toEntity(ParameterizedTypeReference<D> entityType) {
return this.responseFlux.mapNotNull(this::getValidField).mapNotNull(field -> field.toEntity(entityType));
return this.responseFlux.mapNotNull(this::getValidField).mapNotNull((field) -> field.toEntity(entityType));
}
@Override
public <D> Flux<List<D>> toEntityList(Class<D> elementType) {
return this.responseFlux.map(response -> {
return this.responseFlux.map((response) -> {
ClientResponseField field = getValidField(response);
return (field != null ? field.toEntityList(elementType) : Collections.emptyList());
return (field != null) ? field.toEntityList(elementType) : Collections.emptyList();
});
}
@Override
public <D> Flux<List<D>> toEntityList(ParameterizedTypeReference<D> elementType) {
return this.responseFlux.map(response -> {
return this.responseFlux.map((response) -> {
ClientResponseField field = getValidField(response);
return (field != null ? field.toEntityList(elementType) : Collections.emptyList());
return (field != null) ? field.toEntityList(elementType) : Collections.emptyList();
});
}

View File

@@ -33,7 +33,6 @@ import org.springframework.web.util.UriComponentsBuilder;
* around a {@link WebClient.Builder}.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class DefaultHttpGraphQlClientBuilder
extends AbstractGraphQlClientBuilder<DefaultHttpGraphQlClientBuilder>
@@ -105,7 +104,7 @@ final class DefaultHttpGraphQlClientBuilder
public HttpGraphQlClient build() {
// Pass the codecs to the parent for response decoding
this.webClientBuilder.codecs(configurer ->
this.webClientBuilder.codecs((configurer) ->
setJsonCodecs(
CodecDelegate.findJsonEncoder(configurer),
CodecDelegate.findJsonDecoder(configurer)));
@@ -139,6 +138,7 @@ final class DefaultHttpGraphQlClientBuilder
this.builderInitializer = builderInitializer;
}
@Override
public DefaultHttpGraphQlClientBuilder mutate() {
DefaultHttpGraphQlClientBuilder builder = new DefaultHttpGraphQlClientBuilder(this.webClient);
this.builderInitializer.accept(builder);

View File

@@ -41,7 +41,6 @@ import org.springframework.util.MimeTypeUtils;
* a {@link RSocketRequester.Builder}.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class DefaultRSocketGraphQlClientBuilder
extends AbstractGraphQlClientBuilder<DefaultRSocketGraphQlClientBuilder>
@@ -134,9 +133,9 @@ final class DefaultRSocketGraphQlClientBuilder
public RSocketGraphQlClient build() {
// Pass the codecs to the parent for response decoding
this.requesterBuilder.rsocketStrategies(builder -> {
builder.decoders(decoders -> setJsonDecoder(CodecDelegate.findJsonDecoder(decoders)));
builder.encoders(encoders -> setJsonEncoder(CodecDelegate.findJsonEncoder(encoders)));
this.requesterBuilder.rsocketStrategies((builder) -> {
builder.decoders((decoders) -> setJsonDecoder(CodecDelegate.findJsonDecoder(decoders)));
builder.encoders((encoders) -> setJsonEncoder(CodecDelegate.findJsonEncoder(encoders)));
});
RSocketRequester requester;

View File

@@ -26,7 +26,6 @@ import org.springframework.util.Assert;
* Default {@link GraphQlClient.Builder} with a given, externally, prepared transport.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class DefaultTransportGraphQlClientBuilder
extends AbstractGraphQlClientBuilder<DefaultTransportGraphQlClientBuilder> {

View File

@@ -20,7 +20,6 @@ import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import reactor.core.publisher.Mono;
@@ -37,7 +36,6 @@ import org.springframework.web.util.DefaultUriBuilderFactory;
* {@code WebSocketGraphQlTransport}.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class DefaultWebSocketGraphQlClientBuilder
extends AbstractGraphQlClientBuilder<DefaultWebSocketGraphQlClientBuilder>
@@ -130,14 +128,14 @@ final class DefaultWebSocketGraphQlClientBuilder
private WebSocketGraphQlClientInterceptor getInterceptor() {
List<WebSocketGraphQlClientInterceptor> interceptors = getInterceptors().stream()
.filter(interceptor -> interceptor instanceof WebSocketGraphQlClientInterceptor)
.map(interceptor -> (WebSocketGraphQlClientInterceptor) interceptor)
.filter((interceptor) -> interceptor instanceof WebSocketGraphQlClientInterceptor)
.map((interceptor) -> (WebSocketGraphQlClientInterceptor) interceptor)
.toList();
Assert.state(interceptors.size() <= 1,
"Only a single interceptor of type WebSocketGraphQlClientInterceptor may be configured");
return (!interceptors.isEmpty() ? interceptors.get(0) : new WebSocketGraphQlClientInterceptor() {});
return (!interceptors.isEmpty() ? interceptors.get(0) : new WebSocketGraphQlClientInterceptor() { });
}

View File

@@ -38,6 +38,9 @@ public class FieldAccessException extends GraphQlClientException {
/**
* Constructor with the request and response, and the accessed field.
* @param request the client request
* @param response the client response
* @param field the accessed field that caused the error
*/
public FieldAccessException(
ClientGraphQlRequest request, ClientGraphQlResponse response, ClientResponseField field) {

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.client;
import java.util.List;
@@ -61,6 +62,7 @@ public interface GraphQlClient {
* Variant of {@link #document(String)} that uses the given key to resolve
* the GraphQL document from a file with the help of the configured
* {@link Builder#documentSource(DocumentSource) DocumentSource}.
* @param name the document name
* @throws IllegalArgumentException if the content could not be loaded
*/
RequestSpec documentName(String name);
@@ -87,6 +89,7 @@ public interface GraphQlClient {
/**
* Defines a builder for creating {@link GraphQlClient} instances.
* @param <B> the client builder type
*/
interface Builder<B extends Builder<B>> {
@@ -112,6 +115,7 @@ public interface GraphQlClient {
* <p>By default, this is set to {@link ResourceDocumentSource} with
* classpath location {@code "graphql-documents/"} and
* {@link ResourceDocumentSource#FILE_EXTENSIONS} as extensions.
* @param contentLoader the document source
*/
B documentSource(DocumentSource contentLoader);
@@ -190,6 +194,7 @@ public interface GraphQlClient {
* <pre>
* client.document("..").execute().map(response -> response.toEntity(..))
* </pre>
* @param path the field path
* @return a spec with decoding options
* @throws FieldAccessException if the field has any field errors,
* including errors at, above or below the field path.
@@ -203,6 +208,7 @@ public interface GraphQlClient {
* <pre>
* client.document("..").executeSubscription().map(response -> response.toEntity(..))
* </pre>
* @param path the field path
* @return a spec with decoding options
*/
RetrieveSubscriptionSpec retrieveSubscription(String path);
@@ -242,6 +248,7 @@ public interface GraphQlClient {
/**
* Decode the field to an entity of the given type.
* @param <D> the entity type
* @param entityType the type to convert to
* @return {@code Mono} with the decoded entity; completes with
* {@link FieldAccessException} in case of {@link ResponseField field
@@ -253,17 +260,21 @@ public interface GraphQlClient {
/**
* Variant of {@link #toEntity(Class)} with a {@link ParameterizedTypeReference}.
* @param <D> the entity type
* @param entityType the type to convert to
*/
<D> Mono<D> toEntity(ParameterizedTypeReference<D> entityType);
/**
* Variant of {@link #toEntity(Class)} to decode to a List of entities.
* @param <D> the entity type
* @param elementType the type of elements in the list
*/
<D> Mono<List<D>> toEntityList(Class<D> elementType);
/**
* Variant of {@link #toEntity(Class)} to decode to a List of entities.
* @param <D> the entity type
* @param elementType the type of elements in the list
*/
<D> Mono<List<D>> toEntityList(ParameterizedTypeReference<D> elementType);
@@ -278,6 +289,7 @@ public interface GraphQlClient {
/**
* Decode the field to an entity of the given type.
* @param <D> the entity type
* @param entityType the type to convert to
* @return {@code Mono} with the decoded entity; completes with
* {@link FieldAccessException} in case of {@link ResponseField field
@@ -289,20 +301,25 @@ public interface GraphQlClient {
/**
* Variant of {@link #toEntity(Class)} with a {@link ParameterizedTypeReference}.
* @param <D> the entity type
* @param entityType the type to convert to
*/
<D> Flux<D> toEntity(ParameterizedTypeReference<D> entityType);
/**
* Variant of {@link #toEntity(Class)} to decode each response to a List of entities.
* @param <D> the entity type
* @param elementType the type of elements in the list
*/
<D> Flux<List<D>> toEntityList(Class<D> elementType);
/**
* Variant of {@link #toEntity(Class)} to decode each response to a List of entities.
* @param <D> the entity type
* @param elementType the type of elements in the list
*/
<D> Flux<List<D>> toEntityList(ParameterizedTypeReference<D> elementType);
}
}
}

View File

@@ -36,6 +36,9 @@ public class GraphQlClientException extends NestedRuntimeException {
/**
* Constructor with a message, optional cause, and the request details.
* @param message the exception message to use
* @param cause the original cause for the client exception
* @param request the request that failed
*/
public GraphQlClientException(String message, @Nullable Throwable cause, GraphQlRequest request) {
super(message, cause);

View File

@@ -65,13 +65,13 @@ public interface GraphQlClientInterceptor {
@Override
public Mono<ClientGraphQlResponse> intercept(ClientGraphQlRequest request, Chain chain) {
return GraphQlClientInterceptor.this.intercept(
request, nextRequest -> interceptor.intercept(nextRequest, chain));
request, (nextRequest) -> interceptor.intercept(nextRequest, chain));
}
@Override
public Flux<ClientGraphQlResponse> interceptSubscription(ClientGraphQlRequest request, SubscriptionChain chain) {
return GraphQlClientInterceptor.this.interceptSubscription(
request, nextRequest -> interceptor.interceptSubscription(nextRequest, chain));
request, (nextRequest) -> interceptor.interceptSubscription(nextRequest, chain));
}
};
}

View File

@@ -63,6 +63,7 @@ public interface GraphQlTransport {
/**
* Factory method to create {@link GraphQlResponse} from a GraphQL response
* map for use in transport implementations.
* @param responseMap the GraphQL response map
*/
static GraphQlResponse createResponse(Map<String, Object> responseMap) {
return new ResponseMapGraphQlResponse(responseMap);

View File

@@ -32,6 +32,8 @@ public class GraphQlTransportException extends GraphQlClientException {
/**
* Constructor with a default message.
* @param cause the original cause of the transport error
* @param request the request that failed at the transport level
*/
public GraphQlTransportException(@Nullable Throwable cause, GraphQlRequest request) {
super("GraphQlTransport error: " + cause.getMessage(), cause, request);
@@ -39,6 +41,9 @@ public class GraphQlTransportException extends GraphQlClientException {
/**
* Constructor with a given message.
* @param message the exception message to use
* @param cause the original cause of the transport error
* @param request the request that failed at the transport level
*/
public GraphQlTransportException(String message, @Nullable Throwable cause, GraphQlRequest request) {
super(message, cause, request);

View File

@@ -36,6 +36,7 @@ public interface HttpGraphQlClient extends WebGraphQlClient {
/**
* Create an {@link HttpGraphQlClient} that uses the given {@link WebClient}.
* @param webClient the {@code WebClient} to use for sending HTTP requests
*/
static HttpGraphQlClient create(WebClient webClient) {
return builder(webClient.mutate()).build();
@@ -51,6 +52,7 @@ public interface HttpGraphQlClient extends WebGraphQlClient {
/**
* Variant of {@link #builder()} with a pre-configured {@code WebClient}
* to mutate and customize further through the returned builder.
* @param webClient the {@code WebClient} to use for sending HTTP requests
*/
static Builder<?> builder(WebClient webClient) {
return builder(webClient.mutate());
@@ -59,6 +61,7 @@ public interface HttpGraphQlClient extends WebGraphQlClient {
/**
* Variant of {@link #builder()} with a pre-configured {@code WebClient}
* to mutate and customize further through the returned builder.
* @param webClientBuilder the {@code WebClient.Builder} to use for building the HTTP client
*/
static Builder<?> builder(WebClient.Builder webClientBuilder) {
return new DefaultHttpGraphQlClientBuilder(webClientBuilder);
@@ -67,6 +70,7 @@ public interface HttpGraphQlClient extends WebGraphQlClient {
/**
* Builder for the GraphQL over HTTP client.
* @param <B> the builder type
*/
interface Builder<B extends Builder<B>> extends WebGraphQlClient.Builder<B> {
@@ -74,6 +78,7 @@ public interface HttpGraphQlClient extends WebGraphQlClient {
* Customize the {@code WebClient} to use.
* <p>Note that some properties of {@code WebClient.Builder} like the
* base URL, headers, and codecs can be customized through this builder.
* @param webClient the function for customizing the {@code WebClient.Builder} that's used to build the HTTP client
* @see #url(String)
* @see #header(String, String...)
* @see #codecConfigurer(Consumer)

View File

@@ -37,12 +37,11 @@ import org.springframework.web.reactive.function.client.WebClient;
* see {@link WebSocketGraphQlTransport} and {@link RSocketGraphQlTransport}.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class HttpGraphQlTransport implements GraphQlTransport {
private static final ParameterizedTypeReference<Map<String, Object>> MAP_TYPE =
new ParameterizedTypeReference<Map<String, Object>>() {};
new ParameterizedTypeReference<Map<String, Object>>() { };
// To be removed in favor of Framework's MediaType.APPLICATION_GRAPHQL_RESPONSE
private static final MediaType APPLICATION_GRAPHQL_RESPONSE =
@@ -64,7 +63,7 @@ final class HttpGraphQlTransport implements GraphQlTransport {
HttpHeaders headers = new HttpHeaders();
webClient.mutate().defaultHeaders(headers::putAll);
MediaType contentType = headers.getContentType();
return (contentType != null ? contentType : MediaType.APPLICATION_JSON);
return (contentType != null) ? contentType : MediaType.APPLICATION_JSON;
}
@@ -75,7 +74,7 @@ final class HttpGraphQlTransport implements GraphQlTransport {
.contentType(this.contentType)
.accept(MediaType.APPLICATION_JSON, APPLICATION_GRAPHQL_RESPONSE, MediaType.APPLICATION_GRAPHQL)
.bodyValue(request.toMap())
.attributes(attributes -> {
.attributes((attributes) -> {
if (request instanceof ClientGraphQlRequest clientRequest) {
attributes.putAll(clientRequest.getAttributes());
}

View File

@@ -70,6 +70,7 @@ public interface RSocketGraphQlClient extends GraphQlClient {
/**
* Start with a given {@link #builder()}.
* @param requesterBuilder the existing request builder
*/
static Builder<?> builder(RSocketRequester.Builder requesterBuilder) {
return new DefaultRSocketGraphQlClientBuilder(requesterBuilder);
@@ -78,6 +79,7 @@ public interface RSocketGraphQlClient extends GraphQlClient {
/**
* Builder for the GraphQL over HTTP client.
* @param <B> the builder type
*/
interface Builder<B extends Builder<B>> extends GraphQlClient.Builder<B> {
@@ -146,11 +148,12 @@ public interface RSocketGraphQlClient extends GraphQlClient {
* <p>Note that some properties of {@code RSocketRequester.Builder} like the
* data MimeType, and the underlying RSocket transport can be customized
* through this builder.
* @param requester the requester to be customized
* @return the same builder instance
* @see #dataMimeType(MimeType)
* @see #tcp(String, int)
* @see #webSocket(URI)
* @see #clientTransport(ClientTransport)
* @return the same builder instance
*/
B rsocketRequester(Consumer<RSocketRequester.Builder> requester);

View File

@@ -45,12 +45,11 @@ import org.springframework.util.Assert;
* metadata extension.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
final class RSocketGraphQlTransport implements GraphQlTransport {
private static final ParameterizedTypeReference<Map<String, Object>> MAP_TYPE =
new ParameterizedTypeReference<Map<String, Object>>() {};
new ParameterizedTypeReference<Map<String, Object>>() { };
private static final ResolvableType LIST_TYPE = ResolvableType.forClass(List.class);
@@ -83,7 +82,7 @@ final class RSocketGraphQlTransport implements GraphQlTransport {
public Flux<GraphQlResponse> executeSubscription(GraphQlRequest request) {
return this.rsocketRequester.route(this.route).data(request.toMap())
.retrieveFlux(MAP_TYPE)
.onErrorResume(RejectedException.class, ex -> Flux.error(decodeErrors(request, ex)))
.onErrorResume(RejectedException.class, (ex) -> Flux.error(decodeErrors(request, ex)))
.map(ResponseMapGraphQlResponse::new);
}

View File

@@ -36,7 +36,6 @@ import org.springframework.util.ObjectUtils;
* {@link GraphQlResponse} that wraps a deserialized the GraphQL response map.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
class ResponseMapGraphQlResponse extends AbstractGraphQlResponse {
@@ -60,7 +59,7 @@ class ResponseMapGraphQlResponse extends AbstractGraphQlResponse {
@SuppressWarnings("unchecked")
private static List<ResponseError> wrapErrors(Map<String, Object> map) {
List<Map<String, Object>> errors = (List<Map<String, Object>>) map.get("errors");
errors = (errors != null ? errors : Collections.emptyList());
errors = (errors != null) ? errors : Collections.emptyList();
return errors.stream().map(MapResponseError::new).collect(Collectors.toList());
}
@@ -134,7 +133,7 @@ class ResponseMapGraphQlResponse extends AbstractGraphQlResponse {
return Collections.emptyList();
}
return locations.stream()
.map(m -> new SourceLocation(getInt(m, "line"), getInt(m, "column"), (String) m.get("sourceName")))
.map((m) -> new SourceLocation(getInt(m, "line"), getInt(m, "column"), (String) m.get("sourceName")))
.collect(Collectors.toList());
}
@@ -155,7 +154,7 @@ class ResponseMapGraphQlResponse extends AbstractGraphQlResponse {
return "";
}
return path.stream().reduce("",
(s, o) -> s + (o instanceof Integer ? "[" + o + "]" : (s.isEmpty() ? o : "." + o)),
(s, o) -> s + ((o instanceof Integer) ? "[" + o + "]" : (s.isEmpty() ? o : "." + o)),
(s, s2) -> null);
}
@@ -163,7 +162,7 @@ class ResponseMapGraphQlResponse extends AbstractGraphQlResponse {
@Override
@Nullable
public String getMessage() {
return (String) errorMap.get("message");
return (String) this.errorMap.get("message");
}
@Override

View File

@@ -38,6 +38,8 @@ public class SubscriptionErrorException extends GraphQlTransportException {
/**
* Constructor with the request details and the errors listed in the payload
* of the {@code "errors"} message.
* @param request the request details
* @param errors the errors listed in the payload
*/
public SubscriptionErrorException(GraphQlRequest request, List<ResponseError> errors) {
super("GraphQL subscription completed with an \"error\" message, " +

View File

@@ -39,6 +39,7 @@ public interface WebGraphQlClient extends GraphQlClient {
/**
* Base builder for GraphQL clients over a Web transport.
* @param <B> the builder type
*/
interface Builder<B extends Builder<B>> extends GraphQlClient.Builder<B> {
@@ -71,6 +72,7 @@ public interface WebGraphQlClient extends GraphQlClient {
/**
* Configure the underlying {@code CodecConfigurer} to use for all JSON
* encoding and decoding needs.
* @param codecsConsumer a consumer that configures the {@code CodecConfigurer}
*/
B codecConfigurer(Consumer<CodecConfigurer> codecsConsumer);

View File

@@ -35,6 +35,9 @@ public class WebSocketDisconnectedException extends GraphQlTransportException {
/**
* Constructor with an explanation about the closure, along with the request
* details and the status used to close the WebSocket session.
* @param closeStatusMessage the message received when the connection was closed
* @param request the ongoing request when the connection was closed
* @param status the received close status
*/
public WebSocketDisconnectedException(String closeStatusMessage, GraphQlRequest request, CloseStatus status) {
super(closeStatusMessage, null, request);

View File

@@ -85,6 +85,7 @@ public interface WebSocketGraphQlClient extends WebGraphQlClient {
/**
* Builder for a GraphQL over WebSocket client.
* @param <B> the builder type
*/
interface Builder<B extends Builder<B>> extends WebGraphQlClient.Builder<B> {

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.client;
import java.net.URI;
@@ -50,7 +51,6 @@ import org.springframework.web.reactive.socket.client.WebSocketClient;
* {@link GraphQlTransport} for GraphQL over WebSocket via {@link WebSocketClient}.
*
* @author Rossen Stoyanchev
* @since 1.0.0
* @see <a href="https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md">GraphQL over WebSocket protocol</a>
*/
final class WebSocketGraphQlTransport implements GraphQlTransport {
@@ -78,7 +78,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
Assert.notNull(interceptor, "WebSocketGraphQlClientInterceptor is required");
this.url = url;
this.headers.putAll(headers != null ? headers : HttpHeaders.EMPTY);
this.headers.putAll((headers != null) ? headers : HttpHeaders.EMPTY);
this.webSocketClient = client;
this.graphQlSessionHandler = new GraphQlSessionHandler(codecConfigurer, interceptor);
@@ -100,7 +100,9 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
Mono<GraphQlSession> sessionMono = handler.getGraphQlSession();
client.execute(uri, headers, handler)
.subscribe(aVoid -> {},
.subscribe((aVoid) -> {
},
handler::handleWebSocketSessionError,
handler::handleWebSocketSessionClosed);
@@ -109,19 +111,19 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
}
public URI getUrl() {
URI getUrl() {
return this.url;
}
public HttpHeaders getHeaders() {
HttpHeaders getHeaders() {
return this.headers;
}
public WebSocketClient getWebSocketClient() {
WebSocketClient getWebSocketClient() {
return this.webSocketClient;
}
public CodecConfigurer getCodecConfigurer() {
CodecConfigurer getCodecConfigurer() {
return this.graphQlSessionHandler.getCodecConfigurer();
}
@@ -132,7 +134,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
* @return {@code Mono} that completes when the WebSocket is connected and
* ready to begin sending GraphQL requests
*/
public Mono<Void> start() {
Mono<Void> start() {
this.graphQlSessionHandler.setStopped(false);
return this.graphQlSessionMono.then();
}
@@ -145,19 +147,19 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
* call {@link #start()} to allow requests again.
* @return {@code Mono} that completes when the underlying session is closed
*/
public Mono<Void> stop() {
Mono<Void> stop() {
this.graphQlSessionHandler.setStopped(true);
return this.graphQlSessionMono.flatMap(GraphQlSession::close).onErrorResume(ex -> Mono.empty());
return this.graphQlSessionMono.flatMap(GraphQlSession::close).onErrorResume((ex) -> Mono.empty());
}
@Override
public Mono<GraphQlResponse> execute(GraphQlRequest request) {
return this.graphQlSessionMono.flatMap(session -> session.execute(request));
return this.graphQlSessionMono.flatMap((session) -> session.execute(request));
}
@Override
public Flux<GraphQlResponse> executeSubscription(GraphQlRequest request) {
return this.graphQlSessionMono.flatMapMany(session -> session.executeSubscription(request));
return this.graphQlSessionMono.flatMapMany((session) -> session.executeSubscription(request));
}
@@ -189,7 +191,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
}
public CodecConfigurer getCodecConfigurer() {
CodecConfigurer getCodecConfigurer() {
return this.codecDelegate.getCodecConfigurer();
}
@@ -205,7 +207,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
* the "connection_init" and "connection_ack" messages are exchanged or
* returns an error if it fails for any reason.
*/
public Mono<GraphQlSession> getGraphQlSession() {
Mono<GraphQlSession> getGraphQlSession() {
return this.graphQlSessionSink.asMono();
}
@@ -213,14 +215,14 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
* When the handler is marked "stopped", i.e. set to {@code true}, new
* requests are rejected. When set to {@code true} they are allowed.
*/
public void setStopped(boolean stopped) {
void setStopped(boolean stopped) {
this.stopped.set(stopped);
}
/**
* Whether the handler is marked {@link #setStopped(boolean) "stopped"}.
*/
public boolean isStopped() {
boolean isStopped() {
return this.stopped.get();
}
@@ -241,10 +243,10 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
Mono<Void> sendCompletion =
session.send(connectionInitMono.concatWith(graphQlSession.getRequestFlux())
.map(message -> this.codecDelegate.encode(session, message)));
.map((message) -> this.codecDelegate.encode(session, message)));
Mono<Void> receiveCompletion = session.receive()
.flatMap(webSocketMessage -> {
.flatMap((webSocketMessage) -> {
if (sessionNotInitialized()) {
try {
GraphQlWebSocketMessage message = this.codecDelegate.decode(webSocketMessage);
@@ -301,14 +303,14 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
private void registerCloseStatusHandling(GraphQlSession graphQlSession, WebSocketSession session) {
session.closeStatus()
.defaultIfEmpty(CloseStatus.NO_STATUS_CODE)
.doOnNext(closeStatus -> {
.doOnNext((closeStatus) -> {
String closeStatusMessage = initCloseStatusMessage(closeStatus, null, graphQlSession);
if (logger.isDebugEnabled()) {
logger.debug(closeStatusMessage);
}
graphQlSession.terminateRequests(closeStatusMessage, closeStatus);
})
.doOnError(cause -> {
.doOnError((cause) -> {
CloseStatus closeStatus = CloseStatus.NO_STATUS_CODE;
String closeStatusMessage = initCloseStatusMessage(closeStatus, cause, graphQlSession);
if (logger.isErrorEnabled()) {
@@ -347,7 +349,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
* with an error. The error is routed to subscribers of
* {@link #getGraphQlSession()} which is necessary for connection issues.
*/
public void handleWebSocketSessionError(Throwable ex) {
void handleWebSocketSessionError(Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Session handling error: " + ex.getMessage(), ex);
@@ -364,7 +366,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
* This must be called from code that calls the {@code WebSocketClient}
* when execution completes.
*/
public void handleWebSocketSessionClosed() {
void handleWebSocketSessionClosed() {
this.graphQlSessionSink = Sinks.unsafe().one();
}
@@ -396,16 +398,16 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
/**
* Return the {@code Flux} of GraphQL requests to send as WebSocket messages.
*/
public Flux<GraphQlWebSocketMessage> getRequestFlux() {
Flux<GraphQlWebSocketMessage> getRequestFlux() {
return this.requestSink.getRequestFlux();
}
// Outbound messages
public Mono<GraphQlResponse> execute(GraphQlRequest request) {
Mono<GraphQlResponse> execute(GraphQlRequest request) {
String id = String.valueOf(this.requestIndex.incrementAndGet());
return Mono.<GraphQlResponse>create(sink -> {
return Mono.<GraphQlResponse>create((sink) -> {
SingleResponseRequestState state = new SingleResponseRequestState(request, sink);
this.requestStateMap.put(id, state);
try {
@@ -419,9 +421,9 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
}).doOnCancel(() -> this.requestStateMap.remove(id));
}
public Flux<GraphQlResponse> executeSubscription(GraphQlRequest request) {
Flux<GraphQlResponse> executeSubscription(GraphQlRequest request) {
String id = String.valueOf(this.requestIndex.incrementAndGet());
return Flux.<GraphQlResponse>create(sink -> {
return Flux.<GraphQlResponse>create((sink) -> {
SubscriptionRequestState state = new SubscriptionRequestState(request, sink);
this.requestStateMap.put(id, state);
try {
@@ -452,7 +454,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
}
}
public void sendPong(@Nullable Map<String, Object> payload) {
void sendPong(@Nullable Map<String, Object> payload) {
GraphQlWebSocketMessage message = GraphQlWebSocketMessage.pong(payload);
this.requestSink.sendRequest(message);
}
@@ -463,7 +465,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
/**
* Handle a "next" message and route to its recipient.
*/
public void handleNext(GraphQlWebSocketMessage message) {
void handleNext(GraphQlWebSocketMessage message) {
String id = message.getId();
RequestState requestState = this.requestStateMap.get(id);
if (requestState == null) {
@@ -486,7 +488,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
* Handle an "error" message, turning it into an {@link GraphQlResponse}
* for single responses, or signaling an error for streams.
*/
public void handleError(GraphQlWebSocketMessage message) {
void handleError(GraphQlWebSocketMessage message) {
String id = message.getId();
RequestState requestState = this.requestStateMap.remove(id);
if (requestState == null) {
@@ -512,7 +514,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
/**
* Handle a "complete" message.
*/
public void handleComplete(GraphQlWebSocketMessage message) {
void handleComplete(GraphQlWebSocketMessage message) {
String id = message.getId();
RequestState requestState = this.requestStateMap.remove(id);
if (requestState == null) {
@@ -528,22 +530,22 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
* Return a {@code Mono} that completes when the connection is closed
* for any reason.
*/
public Mono<Void> notifyWhenClosed() {
Mono<Void> notifyWhenClosed() {
return this.connection.notifyWhenClosed();
}
/**
* Close the underlying connection.
*/
public Mono<Void> close() {
Mono<Void> close() {
return this.connection.close(CloseStatus.GOING_AWAY);
}
/**
* Terminate and clean all in-progress requests with the given error.
*/
public void terminateRequests(String message, CloseStatus status) {
this.requestStateMap.values().forEach(info -> info.emitDisconnectError(message, status));
void terminateRequests(String message, CloseStatus status) {
this.requestStateMap.values().forEach((info) -> info.emitDisconnectError(message, status));
this.requestStateMap.clear();
}
@@ -595,21 +597,21 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
/**
* Holds the request {@code Flux} and associated {@link FluxSink}.
*/
private static class RequestSink {
private static final class RequestSink {
@Nullable
private FluxSink<GraphQlWebSocketMessage> requestSink;
private final Flux<GraphQlWebSocketMessage> requestFlux = Flux.create(sink -> {
private final Flux<GraphQlWebSocketMessage> requestFlux = Flux.create((sink) -> {
Assert.state(this.requestSink == null, "Expected single subscriber only for outbound messages");
this.requestSink = sink;
});
public Flux<GraphQlWebSocketMessage> getRequestFlux() {
Flux<GraphQlWebSocketMessage> getRequestFlux() {
return this.requestFlux;
}
public void sendRequest(GraphQlWebSocketMessage message) {
void sendRequest(GraphQlWebSocketMessage message) {
Assert.state(this.requestSink != null, "Unexpected request before Flux is subscribed to");
this.requestSink.next(message);
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data;
@@ -39,8 +40,8 @@ import org.springframework.util.ObjectUtils;
* object.
* </ul>
*
* @author Rossen Stoyanchev
* @param <T> the type of value contained
* @author Rossen Stoyanchev
* @since 1.1.0
* @see <a href="http://spec.graphql.org/October2021/#sec-Non-Null.Nullable-vs-Optional">Nullable vs Optional</a>
*/
@@ -115,6 +116,7 @@ public final class ArgumentValue<T> {
/**
* Static factory method for an argument value that was provided, even if
* it was set to {@literal "null}.
* @param <T> the type of value
* @param value the value to hold in the instance
*/
public static <T> ArgumentValue<T> ofNullable(@Nullable T value) {
@@ -123,6 +125,7 @@ public final class ArgumentValue<T> {
/**
* Static factory method for an argument value that was omitted.
* @param <T> the type of value
*/
@SuppressWarnings("unchecked")
public static <T> ArgumentValue<T> omitted() {

View File

@@ -139,7 +139,7 @@ public class GraphQlArgumentBinder {
DataFetchingEnvironment environment, @Nullable String name, ResolvableType targetType)
throws BindException {
Object rawValue = (name != null ? environment.getArgument(name) : environment.getArguments());
Object rawValue = (name != null) ? environment.getArgument(name) : environment.getArguments();
boolean isOmitted = (name != null && !environment.getArguments().containsKey(name));
ArgumentsBindingResult bindingResult = new ArgumentsBindingResult(targetType);
@@ -246,9 +246,9 @@ public class GraphQlArgumentBinder {
Constructor<?> constructor = BeanUtils.getResolvableConstructor(targetClass);
Object value = (constructor.getParameterCount() > 0 ?
Object value = (constructor.getParameterCount() > 0) ?
bindMapToObjectViaConstructor(rawMap, constructor, targetType, bindingResult) :
bindMapToObjectViaSetters(rawMap, constructor, targetType, bindingResult));
bindMapToObjectViaSetters(rawMap, constructor, targetType, bindingResult);
bindingResult.popNestedPath();
@@ -360,7 +360,7 @@ public class GraphQlArgumentBinder {
Object value = null;
try {
TypeConverter converter =
(this.typeConverter != null ? this.typeConverter : new SimpleTypeConverter());
(this.typeConverter != null) ? this.typeConverter : new SimpleTypeConverter();
value = converter.convertIfNecessary(
rawValue, (Class<?>) clazz, new TypeDescriptor(type, null, null));
@@ -385,9 +385,9 @@ public class GraphQlArgumentBinder {
}
private static String initObjectName(ResolvableType targetType) {
return (targetType.getSource() instanceof MethodParameter methodParameter ?
return (targetType.getSource() instanceof MethodParameter methodParameter) ?
Conventions.getVariableNameForParameter(methodParameter) :
ClassUtils.getShortNameAsProperty(targetType.resolve(Object.class)));
ClassUtils.getShortNameAsProperty(targetType.resolve(Object.class));
}
@Override
@@ -400,7 +400,7 @@ public class GraphQlArgumentBinder {
return null;
}
public void rejectArgumentValue(
void rejectArgumentValue(
String field, @Nullable Object rawValue, String code, String defaultMessage) {
addError(new FieldError(

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data;
import java.lang.annotation.Documented;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method;
import java.lang.annotation.Annotation;
@@ -77,6 +78,8 @@ public class HandlerMethod {
/**
* Constructor with a handler instance and a method.
* @param bean the handler instance
* @param method the handler method
*/
public HandlerMethod(Object bean, Method method) {
Assert.notNull(bean, "Bean is required");
@@ -94,6 +97,9 @@ public class HandlerMethod {
* Constructor with a bean name for the handler along with a {@code BeanFactory}
* to allow {@link #createWithResolvedBean() resolving} the handler instance
* later.
* @param beanName the bean name
* @param beanFactory the bean factory to use for bean resolution
* @param method the handler method
*/
public HandlerMethod(String beanName, BeanFactory beanFactory, Method method) {
Assert.hasText(beanName, "Bean name is required");
@@ -115,6 +121,7 @@ public class HandlerMethod {
/**
* Copy constructor for use from subclasses that accept more arguments.
* @param handlerMethod the handler method
*/
protected HandlerMethod(HandlerMethod handlerMethod) {
this(handlerMethod, handlerMethod.bean);
@@ -191,6 +198,7 @@ public class HandlerMethod {
/**
* Return the actual return value type.
* @param returnValue the return value instance, can be {@code null}
*/
public MethodParameter getReturnValueType(@Nullable Object returnValue) {
return new ReturnValueMethodParameter(returnValue);
@@ -208,6 +216,7 @@ public class HandlerMethod {
* if no annotation can be found on the given method itself.
* <p>Also supports <em>merged</em> composed annotations with attribute
* overrides as of Spring Framework 4.3.
* @param <A> the annotation type
* @param annotationType the type of annotation to introspect the method for
* @return the annotation, or {@code null} if none found
* @see AnnotatedElementUtils#findMergedAnnotation
@@ -219,6 +228,7 @@ public class HandlerMethod {
/**
* Return whether the parameter is declared with the given annotation type.
* @param <A> the annotation type
* @param annotationType the annotation type to look for
* @see AnnotatedElementUtils#hasAnnotation
*/
@@ -331,6 +341,9 @@ public class HandlerMethod {
* processing time may be a JDK dynamic proxy (lazy initialization, prototype
* beans, and others). Endpoint classes that require proxying should prefer
* class-based proxy mechanisms.
* @param method the handler method
* @param targetBean the bean instance
* @param args the method arguments
*/
protected void assertTargetBean(Method method, Object targetBean, Object[] args) {
Class<?> methodDeclaringClass = method.getDeclaringClass();
@@ -347,9 +360,9 @@ public class HandlerMethod {
protected String formatInvokeError(String text, Object[] args) {
String formattedArgs = IntStream.range(0, args.length)
.mapToObj(i -> (args[i] != null ?
.mapToObj((i) -> (args[i] != null) ?
"[" + i + "] [type=" + args[i].getClass().getName() + "] [value=" + args[i] + "]" :
"[" + i + "] [null]"))
"[" + i + "] [null]")
.collect(Collectors.joining(",\n", " ", " "));
return text + "\n" +
@@ -401,21 +414,7 @@ public class HandlerMethod {
if (index < ifcAnns.length) {
Annotation[] paramAnns = ifcAnns[index];
if (paramAnns.length > 0) {
List<Annotation> merged = new ArrayList<>(anns.length + paramAnns.length);
merged.addAll(Arrays.asList(anns));
for (Annotation paramAnn : paramAnns) {
boolean existingType = false;
for (Annotation ann : anns) {
if (ann.annotationType() == paramAnn.annotationType()) {
existingType = true;
break;
}
}
if (!existingType) {
merged.add(adaptAnnotation(paramAnn));
}
}
anns = merged.toArray(new Annotation[0]);
anns = mergeAnnotations(anns, paramAnns);
}
}
}
@@ -424,6 +423,25 @@ public class HandlerMethod {
}
return anns;
}
private Annotation[] mergeAnnotations(Annotation[] anns, Annotation[] paramAnns) {
List<Annotation> merged = new ArrayList<>(anns.length + paramAnns.length);
merged.addAll(Arrays.asList(anns));
for (Annotation paramAnn : paramAnns) {
boolean existingType = false;
for (Annotation ann : anns) {
if (ann.annotationType() == paramAnn.annotationType()) {
existingType = true;
break;
}
}
if (!existingType) {
merged.add(adaptAnnotation(paramAnn));
}
}
anns = merged.toArray(new Annotation[0]);
return anns;
}
}
@@ -435,7 +453,7 @@ public class HandlerMethod {
@Nullable
private final Object returnValue;
public ReturnValueMethodParameter(@Nullable Object returnValue) {
ReturnValueMethodParameter(@Nullable Object returnValue) {
super(-1);
this.returnValue = returnValue;
}
@@ -447,7 +465,7 @@ public class HandlerMethod {
@Override
public Class<?> getParameterType() {
return (this.returnValue != null ? this.returnValue.getClass() : super.getParameterType());
return (this.returnValue != null) ? this.returnValue.getClass() : super.getParameterType();
}
@Override

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method;
import graphql.schema.DataFetchingEnvironment;
@@ -35,20 +36,18 @@ public interface HandlerMethodArgumentResolver {
/**
* Whether this resolver supports the given {@link MethodParameter}.
* @param parameter the method parameter to check for support
*/
boolean supportsParameter(MethodParameter parameter);
/**
* Resolve a method parameter to a value.
*
* @param parameter the method parameter to resolve. This parameter must
* have previously checked via {@link #supportsParameter}.
* @param environment the environment to use to resolve the value
*
* @return the resolved value, which may be {@code null} if not resolved;
* the value may also be a {@link reactor.core.publisher.Mono} if it
* requires asynchronous resolution.
*
* @throws Exception in case of errors with the preparation of argument values
*/
@Nullable

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method;
import java.util.ArrayList;
@@ -43,6 +44,7 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
/**
* Add the given {@link HandlerMethodArgumentResolver}.
* @param resolver the argument resolver
*/
public void addResolver(HandlerMethodArgumentResolver resolver) {
this.argumentResolvers.add(resolver);
@@ -84,10 +86,11 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
/**
* Find a registered {@link HandlerMethodArgumentResolver} that supports
* the given method parameter.
* @param parameter the method parameter
*/
@Nullable
public HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
return this.argumentResolverCache.computeIfAbsent(parameter, p -> {
return this.argumentResolverCache.computeIfAbsent(parameter, (p) -> {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
return resolver;
@@ -97,4 +100,4 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
});
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method;
import java.lang.reflect.InvocationTargetException;
@@ -69,6 +70,7 @@ public abstract class InvocableHandlerMethodSupport extends HandlerMethod {
/**
* Invoke the handler method with the given argument values.
* @param graphQLContext the GraphQL context for this data fetching operation
* @param argValues the values to use to invoke the method
* @return the value returned from the method or a {@code Mono<Throwable>}
* if the invocation fails.
@@ -89,7 +91,7 @@ public abstract class InvocableHandlerMethodSupport extends HandlerMethod {
}
catch (IllegalArgumentException ex) {
assertTargetBean(method, getBean(), argValues);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
String text = (ex.getMessage() != null) ? ex.getMessage() : "Illegal argument";
return Mono.error(new IllegalStateException(formatInvokeError(text, argValues), ex));
}
catch (InvocationTargetException ex) {
@@ -143,15 +145,16 @@ public abstract class InvocableHandlerMethodSupport extends HandlerMethod {
/**
* Use this method to resolve the arguments asynchronously. This is only
* useful when at least one of the values is a {@link Mono}
* @param args the arguments to be resolved asynchronously
*/
@SuppressWarnings("unchecked")
protected Mono<Object[]> toArgsMono(Object[] args) {
List<Mono<Object>> monoList = new ArrayList<>();
for (Object arg : args) {
Mono<Object> argMono = (arg instanceof Mono ? (Mono<Object>) arg : Mono.justOrEmpty(arg));
Mono<Object> argMono = ((arg instanceof Mono) ? (Mono<Object>) arg : Mono.justOrEmpty(arg));
monoList.add(argMono.defaultIfEmpty(NO_VALUE));
}
return Mono.zip(monoList, values -> {
return Mono.zip(monoList, (values) -> {
for (int i = 0; i < values.length; i++) {
if (values[i] == NO_VALUE) {
values[i] = null;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation;
import java.lang.annotation.Documented;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation;
import java.lang.annotation.Documented;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation;
import java.lang.annotation.Documented;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation;
import java.lang.annotation.Documented;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation;
import java.lang.annotation.Documented;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation;
import java.lang.annotation.Documented;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation;
import java.lang.annotation.Documented;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation;
import java.lang.annotation.Documented;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation;
import java.lang.annotation.Documented;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation;
import java.lang.annotation.Documented;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import java.lang.annotation.Annotation;
@@ -103,8 +104,6 @@ import org.springframework.validation.DataBinder;
* is configured for use.
* </ul>
*
*
*
* @author Rossen Stoyanchev
* @author Brian Clozel
* @since 1.0.0
@@ -113,17 +112,17 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
private static final ClassLoader classLoader = AnnotatedControllerConfigurer.class.getClassLoader();
private final static boolean springDataPresent = ClassUtils.isPresent(
private static final boolean springDataPresent = ClassUtils.isPresent(
"org.springframework.data.projection.SpelAwareProxyProjectionFactory", classLoader);
private final static boolean springSecurityPresent = ClassUtils.isPresent(
private static final boolean springSecurityPresent = ClassUtils.isPresent(
"org.springframework.security.core.context.SecurityContext", classLoader);
private final static boolean beanValidationPresent = ClassUtils.isPresent(
private static final boolean beanValidationPresent = ClassUtils.isPresent(
"jakarta.validation.executable.ExecutableValidator", classLoader);
private final static Log logger = LogFactory.getLog(AnnotatedControllerConfigurer.class);
private static final Log logger = LogFactory.getLog(AnnotatedControllerConfigurer.class);
/**
* Bean name prefix for target beans behind scoped proxies. Used to exclude those
@@ -165,6 +164,7 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
* that assists in binding GraphQL arguments onto
* {@link org.springframework.graphql.data.method.annotation.Argument @Argument}
* annotated method parameters.
* @param registrar the formatter registrar
*/
public void addFormatterRegistrar(FormatterRegistrar registrar) {
registrar.registerFormatters(this.conversionService);
@@ -175,6 +175,7 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
* {@link org.springframework.graphql.data.method.annotation.Argument @Argument}
* should falls back to direct field access in case the target object does
* not use accessor methods.
* @param fallBackOnDirectFieldAccess whether we should fall back on direct field access
* @since 1.2.0
*/
public void setFallBackOnDirectFieldAccess(boolean fallBackOnDirectFieldAccess) {
@@ -185,7 +186,6 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
* Add a {@link HandlerMethodArgumentResolver} for custom controller method
* arguments. Such custom resolvers are ordered after built-in resolvers
* except for {@link SourceMethodArgumentResolver}, which is always last.
*
* @param resolver the resolver to add.
* @since 1.2.0
*/
@@ -206,11 +206,9 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
* exceptions from non-controller {@link DataFetcher}s since exceptions from
* {@code @SchemaMapping} controller methods are handled automatically at
* the point of invocation.
*
* @return a resolver instance that can be plugged into
* {@link org.springframework.graphql.execution.GraphQlSource.Builder#exceptionResolvers(List)
* GraphQlSource.Builder}
*
* @since 1.2.0
*/
public DataFetcherExceptionResolver getExceptionResolver() {
@@ -352,7 +350,7 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
else {
dataFetcher = registerBatchLoader(info);
}
runtimeWiringBuilder.type(info.getCoordinates().getTypeName(), typeBuilder ->
runtimeWiringBuilder.type(info.getCoordinates().getTypeName(), (typeBuilder) ->
typeBuilder.dataFetcher(info.getCoordinates().getFieldName(), dataFetcher));
});
}
@@ -482,17 +480,17 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
private HandlerMethod createHandlerMethod(Method method, Object handler, Class<?> handlerType) {
Method theMethod = AopUtils.selectInvocableMethod(method, handlerType);
return (handler instanceof String ?
return (handler instanceof String) ?
new HandlerMethod((String) handler, obtainApplicationContext().getAutowireCapableBeanFactory(), theMethod) :
new HandlerMethod(handler, theMethod));
new HandlerMethod(handler, theMethod);
}
private String formatMappings(Class<?> handlerType, Collection<MappingInfo> infos) {
String formattedType = Arrays.stream(ClassUtils.getPackageName(handlerType).split("\\."))
.map(p -> p.substring(0, 1))
.map((p) -> p.substring(0, 1))
.collect(Collectors.joining(".", "", "." + handlerType.getSimpleName()));
return infos.stream()
.map(mappingInfo -> {
.map((mappingInfo) -> {
Method method = mappingInfo.getHandlerMethod().getMethod();
String methodParameters = Arrays.stream(method.getGenericParameterTypes())
.map(Type::getTypeName)
@@ -511,7 +509,7 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
BatchLoaderRegistry registry = obtainApplicationContext().getBean(BatchLoaderRegistry.class);
BatchLoaderRegistry.RegistrationSpec<Object, Object> registration = registry.forName(dataLoaderKey);
if (info.getMaxBatchSize() > 0) {
registration.withOptions(options -> options.setMaxBatchSize(info.getMaxBatchSize()));
registration.withOptions((options) -> options.setMaxBatchSize(info.getMaxBatchSize()));
}
HandlerMethod handlerMethod = info.getHandlerMethod();
@@ -551,6 +549,7 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
* Alternative to {@link #configure(RuntimeWiring.Builder)} that registers
* data fetchers in a {@link GraphQLCodeRegistry.Builder}. This could be
* used with programmatic creation of {@link graphql.schema.GraphQLSchema}.
* @param codeRegistryBuilder the code registry to be processed
*/
@SuppressWarnings("rawtypes")
public void configure(GraphQLCodeRegistry.Builder codeRegistryBuilder) {
@@ -577,7 +576,7 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
private final HandlerMethod handlerMethod;
public MappingInfo(
MappingInfo(
String typeName, String field, boolean batchMapping, int maxBatchSize,
HandlerMethod handlerMethod) {
@@ -587,20 +586,20 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
this.handlerMethod = handlerMethod;
}
public FieldCoordinates getCoordinates() {
FieldCoordinates getCoordinates() {
return this.coordinates;
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public boolean isBatchMapping() {
boolean isBatchMapping() {
return this.batchMapping;
}
public int getMaxBatchSize() {
int getMaxBatchSize() {
return this.maxBatchSize;
}
public HandlerMethod getHandlerMethod() {
HandlerMethod getHandlerMethod() {
return this.handlerMethod;
}
@@ -639,7 +638,7 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
this.argumentResolvers = argumentResolvers;
this.methodValidationHelper =
(helper != null ? helper.getValidationHelperFor(info.getHandlerMethod()) : null);
(helper != null) ? helper.getValidationHelperFor(info.getHandlerMethod()) : null;
// Register controllers early to validate exception handler return types
Class<?> controllerType = info.getHandlerMethod().getBeanType();
@@ -664,7 +663,7 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
/**
* Return the {@link HandlerMethod} used to fetch data.
*/
public HandlerMethod getHandlerMethod() {
HandlerMethod getHandlerMethod() {
return this.info.getHandlerMethod();
}
@@ -690,13 +689,13 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
DataFetchingEnvironment env, DataFetcherHandlerMethod handlerMethod, Object result) {
if (this.subscription && result instanceof Publisher<?> publisher) {
result = Flux.from(publisher).onErrorResume(ex -> handleSubscriptionError(ex, env, handlerMethod));
result = Flux.from(publisher).onErrorResume((ex) -> handleSubscriptionError(ex, env, handlerMethod));
}
else if (result instanceof Mono) {
result = ((Mono<T>) result).onErrorResume(ex -> (Mono<T>) handleException(ex, env, handlerMethod));
result = ((Mono<T>) result).onErrorResume((ex) -> (Mono<T>) handleException(ex, env, handlerMethod));
}
else if (result instanceof Flux<?>) {
result = ((Flux<T>) result).onErrorResume(ex -> (Mono<T>) handleException(ex, env, handlerMethod));
result = ((Flux<T>) result).onErrorResume((ex) -> (Mono<T>) handleException(ex, env, handlerMethod));
}
return result;
}
@@ -705,7 +704,7 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
Throwable ex, DataFetchingEnvironment env, DataFetcherHandlerMethod handlerMethod) {
return this.exceptionResolver.resolveException(ex, env, handlerMethod.getBean())
.map(errors -> DataFetcherResult.newResult().errors(errors).build())
.map((errors) -> DataFetcherResult.newResult().errors(errors).build())
.switchIfEmpty(Mono.error(ex));
}
@@ -714,7 +713,7 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
Throwable ex, DataFetchingEnvironment env, DataFetcherHandlerMethod handlerMethod) {
return (Publisher<T>) this.exceptionResolver.resolveException(ex, env, handlerMethod.getBean())
.flatMap(errors -> Mono.error(new SubscriptionPublisherException(errors, ex)))
.flatMap((errors) -> Mono.error(new SubscriptionPublisherException(errors, ex)))
.switchIfEmpty(Mono.error(ex));
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import java.lang.reflect.Method;
@@ -72,7 +73,6 @@ import org.springframework.web.method.ControllerAdviceBean;
*
* @author Rossen Stoyanchev
* @author Brian Clozel
* @since 1.2.0
*/
final class AnnotatedControllerExceptionResolver {
@@ -98,9 +98,9 @@ final class AnnotatedControllerExceptionResolver {
* are validated to ensure they are within a range of supported types.
* @param controllerType the controller type to register
*/
public void registerController(Class<?> controllerType) {
void registerController(Class<?> controllerType) {
this.controllerCache.computeIfAbsent(
controllerType, type -> new MethodResolver(findExceptionHandlers(controllerType)));
controllerType, (type) -> new MethodResolver(findExceptionHandlers(controllerType)));
}
/**
@@ -110,7 +110,7 @@ final class AnnotatedControllerExceptionResolver {
* for use at runtime.
* @param context the context to look into
*/
public void registerControllerAdvice(ApplicationContext context) {
void registerControllerAdvice(ApplicationContext context) {
Map<ControllerAdviceBean, MethodResolver> detectedControllerAdvice = new HashMap<>();
for (ControllerAdviceBean bean : ControllerAdviceBean.findAnnotatedBeans(context)) {
Class<?> beanType = bean.getBeanType();
@@ -121,12 +121,11 @@ final class AnnotatedControllerExceptionResolver {
}
}
}
detectedControllerAdvice.keySet().stream().sorted(OrderComparator.INSTANCE).forEach(bean -> {
this.controllerAdviceCache.put(bean, detectedControllerAdvice.get(bean));
});
detectedControllerAdvice.keySet().stream().sorted(OrderComparator.INSTANCE).forEach((bean) ->
this.controllerAdviceCache.put(bean, detectedControllerAdvice.get(bean)));
if (logger.isDebugEnabled()) {
logger.debug("@GraphQlException methods in ControllerAdvice beans: " +
(this.controllerAdviceCache.size() == 0 ? "none" : this.controllerAdviceCache.size()));
((this.controllerAdviceCache.size() == 0) ? "none" : this.controllerAdviceCache.size()));
}
}
@@ -134,7 +133,7 @@ final class AnnotatedControllerExceptionResolver {
private static Map<Class<? extends Throwable>, Method> findExceptionHandlers(Class<?> handlerType) {
Map<Method, GraphQlExceptionHandler> handlerMap = MethodIntrospector.selectMethods(
handlerType, (MethodIntrospector.MetadataLookup<GraphQlExceptionHandler>) method ->
handlerType, (MethodIntrospector.MetadataLookup<GraphQlExceptionHandler>) (method) ->
AnnotatedElementUtils.findMergedAnnotation(method, GraphQlExceptionHandler.class));
Map<Class<? extends Throwable>, Method> mappings = new HashMap<>(handlerMap.size());
@@ -172,7 +171,7 @@ final class AnnotatedControllerExceptionResolver {
* @return a {@code Mono} with resolved {@code GraphQLError}s as specified in
* {@link DataFetcherExceptionResolver#resolveException(Throwable, DataFetchingEnvironment)}
*/
public Mono<List<GraphQLError>> resolveException(
Mono<List<GraphQLError>> resolveException(
Throwable ex, DataFetchingEnvironment environment, @Nullable Object controller) {
Object controllerOrAdvice = null;
@@ -229,7 +228,7 @@ final class AnnotatedControllerExceptionResolver {
while (exToExpose != null) {
exceptions.add(exToExpose);
Throwable cause = exToExpose.getCause();
exToExpose = (cause != exToExpose ? cause : null);
exToExpose = (cause != exToExpose) ? cause : null;
}
Object[] arguments = new Object[exceptions.size() + 1];
exceptions.toArray(arguments); // efficient arraycopy call in ArrayList
@@ -277,7 +276,7 @@ final class AnnotatedControllerExceptionResolver {
* @return the exception handler to use, or {@code null} if no match
*/
@Nullable
public MethodHolder resolveMethod(Throwable exception) {
MethodHolder resolveMethod(Throwable exception) {
MethodHolder method = resolveMethodByExceptionType(exception.getClass());
if (method == null) {
Throwable cause = exception.getCause();
@@ -295,7 +294,7 @@ final class AnnotatedControllerExceptionResolver {
method = getMappedMethod(exceptionType);
this.resolvedExceptionCache.put(exceptionType, method);
}
return (method != NO_MATCH ? method : null);
return (method != NO_MATCH) ? method : null;
}
private MethodHolder getMappedMethod(Class<? extends Throwable> exceptionType) {
@@ -341,11 +340,11 @@ final class AnnotatedControllerExceptionResolver {
this.adapter = ReturnValueAdapter.createFor(this.returnType);
}
public Method getMethod() {
Method getMethod() {
return this.method;
}
public Mono<List<GraphQLError>> adapt(@Nullable Object result, Throwable ex) {
Mono<List<GraphQLError>> adapt(@Nullable Object result, Throwable ex) {
return this.adapter.adapt(result, this.returnType, ex);
}
@@ -420,24 +419,24 @@ final class AnnotatedControllerExceptionResolver {
}
/** Adapter for void */
/* Adapter for void */
ReturnValueAdapter forVoid = (result, returnType, ex) -> Mono.just(Collections.emptyList());
/** Adapter for a single GraphQLError */
/* Adapter for a single GraphQLError */
ReturnValueAdapter forSingleError = (result, returnType, ex) ->
(result == null ?
Mono.empty() :
Mono.just(Collections.singletonList((GraphQLError) result)));
(result != null) ?
Mono.just(Collections.singletonList((GraphQLError) result)) :
Mono.empty();
/** Adapter for a collection of GraphQLError's */
/* Adapter for a collection of GraphQLError's */
ReturnValueAdapter forCollection = (result, returnType, ex) ->
(result == null ?
Mono.empty() :
Mono.just((result instanceof List ?
(result != null) ?
Mono.just((result instanceof List) ?
(List<GraphQLError>) result :
new ArrayList<>((Collection<GraphQLError>) result))));
new ArrayList<>((Collection<GraphQLError>) result)) :
Mono.empty();
/** Adapter for Object */
/* Adapter for Object */
ReturnValueAdapter forObject = (result, returnType, ex) -> {
if (result == null) {
return Mono.empty();
@@ -457,15 +456,15 @@ final class AnnotatedControllerExceptionResolver {
}
};
/** Adapter for {@code Mono<Void>} */
/* Adapter for {@code Mono<Void>} */
ReturnValueAdapter forMonoVoid = (result, returnType, ex) ->
(result == null ? Mono.empty() : Mono.just(Collections.emptyList()));
(result != null) ? Mono.just(Collections.emptyList()) : Mono.empty();
/** Adapter for a {@code Mono} wrapping any of the other synchronous return value types */
/* Adapter for a {@code Mono} wrapping any of the other synchronous return value types */
ReturnValueAdapter forMono = (result, returnType, ex) ->
(result == null ?
Mono.empty() :
((Mono<?>) result).flatMap(o -> forObject.adapt(o, returnType, ex)).switchIfEmpty(Mono.error(ex)));
(result != null) ?
((Mono<?>) result).flatMap((o) -> forObject.adapt(o, returnType, ex)).switchIfEmpty(Mono.error(ex)) :
Mono.empty();
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import graphql.schema.DataFetchingEnvironment;

View File

@@ -19,22 +19,24 @@ 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.data.ArgumentValue;
/**
* {@link ValueExtractor} that enables {@code @Valid} with {@link ArgumentValue},
* and helps to extract the value from it.
*
* @author Rossen Stoyanchev
* @since 1.2.2
*/
@UnwrapByDefault
public final class ArgumentValueValueExtractor implements ValueExtractor<ArgumentValue<@ExtractedValue ?>> {
@Override
public void extractValues(ArgumentValue<?> argumentValue, ValueReceiver receiver) {
if (!argumentValue.isOmitted()) {
receiver.value(null, argumentValue.value());
}
}
@Override
public void extractValues(ArgumentValue<?> argumentValue, ValueReceiver receiver) {
if (!argumentValue.isOmitted()) {
receiver.value(null, argumentValue.value());
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import graphql.schema.DataFetchingEnvironment;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import java.lang.annotation.Annotation;
@@ -97,7 +98,7 @@ public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArg
@Override
public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) throws Exception {
return getCurrentAuthentication(parameter)
.mapNotNull(auth -> resolvePrincipal(parameter, auth.getPrincipal()))
.mapNotNull((auth) -> resolvePrincipal(parameter, auth.getPrincipal()))
.transform((argument) -> isPublisherOrMono(parameter) ? Mono.just(argument) : argument);
}
@@ -109,7 +110,7 @@ public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArg
@SuppressWarnings("unchecked")
private Mono<Authentication> getCurrentAuthentication(MethodParameter parameter) {
Object value = PrincipalMethodArgumentResolver.resolveAuthentication(parameter);
return (value instanceof Authentication auth ? Mono.just(auth) : (Mono<Authentication>) value);
return (value instanceof Authentication auth) ? Mono.just(auth) : (Mono<Authentication>) value;
}
@Nullable

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import java.security.Principal;
@@ -50,7 +51,7 @@ import org.springframework.util.ClassUtils;
*/
public class BatchLoaderHandlerMethod extends InvocableHandlerMethodSupport {
private final static boolean springSecurityPresent = ClassUtils.isPresent(
private static final boolean springSecurityPresent = ClassUtils.isPresent(
"org.springframework.security.core.context.SecurityContext",
AnnotatedControllerConfigurer.class.getClassLoader());
@@ -66,7 +67,6 @@ public class BatchLoaderHandlerMethod extends InvocableHandlerMethodSupport {
/**
* Invoke the underlying batch loader method with a collection of keys to
* return a Map of key-value pairs.
*
* @param keys the keys for which to load values
* @param environment the environment available to batch loaders
* @param <K> the type of keys in the map
@@ -80,7 +80,7 @@ public class BatchLoaderHandlerMethod extends InvocableHandlerMethodSupport {
Object result = doInvoke(environment.getContext(), args);
return toMonoMap(result);
}
return toArgsMono(args).flatMap(argValues -> {
return toArgsMono(args).flatMap((argValues) -> {
Object result = doInvoke(environment.getContext(), argValues);
return toMonoMap(result);
});
@@ -89,7 +89,6 @@ public class BatchLoaderHandlerMethod extends InvocableHandlerMethodSupport {
/**
* Invoke the underlying batch loader method with a collection of input keys
* to return a collection of matching values.
*
* @param keys the keys for which to load values
* @param environment the environment available to batch loaders
* @param <V> the type of values returned
@@ -101,7 +100,7 @@ public class BatchLoaderHandlerMethod extends InvocableHandlerMethodSupport {
Object result = doInvoke(environment.getContext(), args);
return toFlux(result);
}
return toArgsMono(args).flatMapMany(resolvedArgs -> {
return toArgsMono(args).flatMapMany((resolvedArgs) -> {
Object result = doInvoke(environment.getContext(), resolvedArgs);
return toFlux(result);
});
@@ -164,7 +163,7 @@ public class BatchLoaderHandlerMethod extends InvocableHandlerMethodSupport {
}
private boolean doesNotHaveAsyncArgs(Object[] args) {
return Arrays.stream(args).noneMatch(arg -> arg instanceof Mono);
return Arrays.stream(args).noneMatch((arg) -> arg instanceof Mono);
}
@SuppressWarnings("unchecked")
@@ -176,7 +175,7 @@ public class BatchLoaderHandlerMethod extends InvocableHandlerMethodSupport {
return (Mono<Map<K, V>>) result;
}
else if (result instanceof CompletableFuture) {
return Mono.fromFuture((CompletableFuture<? extends Map<K,V>>) result);
return Mono.fromFuture((CompletableFuture<? extends Map<K, V>>) result);
}
return Mono.error(new IllegalStateException("Unexpected return value: " + result));
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import java.lang.annotation.Annotation;
@@ -72,7 +73,7 @@ public class ContextValueMethodArgumentResolver implements HandlerMethodArgument
@Nullable GraphQLContext graphQlContext) {
Class<?> parameterType = parameter.getParameterType();
Object value = (graphQlContext != null ? graphQlContext.get(contextValueName) : null);
Object value = (graphQlContext != null) ? graphQlContext.get(contextValueName) : null;
boolean isOptional = parameterType.equals(Optional.class);
boolean isMono = parameterType.equals(Mono.class);
@@ -85,14 +86,14 @@ public class ContextValueMethodArgumentResolver implements HandlerMethodArgument
if (value == null) {
value = Mono.empty();
}
else if (!( value instanceof Mono)) {
else if (!(value instanceof Mono)) {
value = Mono.just(value);
}
return Mono.just(value);
}
if (isOptional) {
return (value instanceof Optional ? value : Optional.ofNullable(value));
return (value instanceof Optional) ? value : Optional.ofNullable(value);
}
return value;

View File

@@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import graphql.schema.DataFetchingEnvironment;
import org.springframework.core.MethodParameter;
import org.springframework.graphql.data.method.HandlerMethodArgumentResolver;
@@ -27,14 +29,14 @@ import org.springframework.graphql.data.method.HandlerMethodArgumentResolver;
*/
public class ContinuationHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return "kotlin.coroutines.Continuation".equals(parameter.getParameterType().getName());
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return "kotlin.coroutines.Continuation".equals(parameter.getParameterType().getName());
}
@Override
public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) {
return null;
}
@Override
public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment environment) {
return null;
}
}

View File

@@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.BiConsumer;
@@ -52,7 +54,7 @@ public class DataFetcherHandlerMethod extends InvocableHandlerMethodSupport {
private final HandlerMethodArgumentResolverComposite resolvers;
private final BiConsumer<Object, Object[]> validationHelper;
private final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
private final boolean subscription;
@@ -63,6 +65,7 @@ public class DataFetcherHandlerMethod extends InvocableHandlerMethodSupport {
* @param handlerMethod the handler method
* @param resolvers the argument resolvers
* @param validationHelper to apply bean validation with
* @param executor an {@link Executor} to use for {@link Callable} return values
* @param subscription whether the field being fetched is of subscription type
*/
public DataFetcherHandlerMethod(
@@ -73,7 +76,7 @@ public class DataFetcherHandlerMethod extends InvocableHandlerMethodSupport {
super(handlerMethod, executor);
Assert.isTrue(!resolvers.getResolvers().isEmpty(), "No argument resolvers");
this.resolvers = resolvers;
this.validationHelper = (validationHelper != null ? validationHelper : (controller, args) -> {});
this.validationHelper = (validationHelper != null) ? validationHelper : (controller, args) -> { };
this.subscription = subscription;
}
@@ -95,9 +98,7 @@ public class DataFetcherHandlerMethod extends InvocableHandlerMethodSupport {
* The {@code providedArgs} parameter however may supply argument values to
* be used directly, i.e. without argument resolution. Provided argument
* values are checked before argument resolvers.
*
* @param environment the environment to resolve arguments from
*
* @return the raw value returned by the invoked method, possibly a
* {@code Mono} in case a method argument requires asynchronous resolution;
* {@code Mono<Throwable>} is returned if invocation fails.
@@ -110,6 +111,8 @@ public class DataFetcherHandlerMethod extends InvocableHandlerMethodSupport {
/**
* Variant of {@link #invoke(DataFetchingEnvironment)} that also accepts
* "given" arguments, which are matched by type.
* @param environment the data fetching environment for this operation
* @param providedArgs the argument values to be used directly
* @since 1.2.0
*/
@Nullable
@@ -122,17 +125,17 @@ public class DataFetcherHandlerMethod extends InvocableHandlerMethodSupport {
return Mono.error(ex);
}
if (Arrays.stream(args).noneMatch(arg -> arg instanceof Mono)) {
if (Arrays.stream(args).noneMatch((arg) -> arg instanceof Mono)) {
return validateAndInvoke(args, environment);
}
return this.subscription ?
toArgsMono(args).flatMapMany(argValues -> {
toArgsMono(args).flatMapMany((argValues) -> {
Object result = validateAndInvoke(argValues, environment);
Assert.state(result instanceof Publisher, "Expected a Publisher from a Subscription response");
return Flux.from((Publisher<?>) result);
}) :
toArgsMono(args).flatMap(argValues -> {
toArgsMono(args).flatMap((argValues) -> {
Object result = validateAndInvoke(argValues, environment);
if (result instanceof Mono<?> mono) {
return mono;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import java.util.Locale;
@@ -27,7 +28,7 @@ import org.springframework.graphql.data.method.HandlerMethodArgumentResolver;
/**
* Resolver for {@link DataFetchingEnvironment} and related values that can be
* accessed through the {@link DataFetchingEnvironment} such as:
* accessed through the {@link DataFetchingEnvironment}. This includes:
* <ul>
* <li>{@link GraphQLContext}
* <li>{@link DataFetchingFieldSelectionSet}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import java.lang.reflect.ParameterizedType;
@@ -41,7 +42,7 @@ import org.springframework.util.Assert;
* @since 1.0.0
*/
public class DataLoaderMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(DataLoader.class);
@@ -80,8 +81,8 @@ public class DataLoaderMethodArgumentResolver implements HandlerMethodArgumentRe
ParameterizedType parameterizedType = (ParameterizedType) genericType;
if (parameterizedType.getActualTypeArguments().length == 2) {
Type valueType = parameterizedType.getActualTypeArguments()[1];
return (valueType instanceof Class ?
(Class<?>) valueType : ResolvableType.forType(valueType).resolve());
return (valueType instanceof Class) ?
(Class<?>) valueType : ResolvableType.forType(valueType).resolve();
}
}
return null;
@@ -92,7 +93,7 @@ public class DataLoaderMethodArgumentResolver implements HandlerMethodArgumentRe
@Nullable Class<?> valueType, @Nullable String parameterName) {
String message = "Cannot resolve DataLoader for parameter" +
(parameterName != null ? " '" + parameterName + "'" : "[" + parameter.getParameterIndex() + "]" ) +
((parameterName != null) ? " '" + parameterName + "'" : "[" + parameter.getParameterIndex() + "]") +
" in method " + parameter.getMethod().toGenericString() + ". ";
if (valueType == null) {

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import graphql.GraphQLContext;

View File

@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import java.security.Principal;
import graphql.schema.DataFetchingEnvironment;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.graphql.data.method.HandlerMethodArgumentResolver;
@@ -26,7 +28,6 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import reactor.core.publisher.Mono;
/**
* Resolver to obtain {@link Principal} from Spring Security context via

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2022 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
@@ -75,7 +76,7 @@ public class ProjectedPayloadMethodArgumentResolver implements HandlerMethodArgu
Assert.notNull(applicationContext, "ApplicationContext must not be null");
this.projectionFactory.setBeanFactory(applicationContext);
ClassLoader classLoader = applicationContext.getClassLoader();
if(classLoader != null) {
if (classLoader != null) {
this.projectionFactory.setBeanClassLoader(classLoader);
}
}
@@ -98,8 +99,8 @@ public class ProjectedPayloadMethodArgumentResolver implements HandlerMethodArgu
private static Class<?> getTargetType(MethodParameter parameter) {
Class<?> type = parameter.getParameterType();
return (type.equals(Optional.class) || type.equals(ArgumentValue.class) ?
parameter.nested().getNestedParameterType() : parameter.getParameterType());
return (type.equals(Optional.class) || type.equals(ArgumentValue.class)) ?
parameter.nested().getNestedParameterType() : parameter.getParameterType();
}
@Override
@@ -117,15 +118,15 @@ public class ProjectedPayloadMethodArgumentResolver implements HandlerMethodArgu
}
Map<String, Object> arguments = environment.getArguments();
Object rawValue = (name != null ? arguments.get(name) : arguments);
Object value = (rawValue != null ? createProjection(targetType, rawValue) : null);
Object rawValue = (name != null) ? arguments.get(name) : arguments;
Object value = (rawValue != null) ? createProjection(targetType, rawValue) : null;
if (isOptional) {
return Optional.ofNullable(value);
}
else if (isArgumentValue) {
return (name != null && arguments.containsKey(name) ?
ArgumentValue.ofNullable(value) : ArgumentValue.omitted());
return (name != null && arguments.containsKey(name)) ?
ArgumentValue.ofNullable(value) : ArgumentValue.omitted();
}
else {
return value;
@@ -140,7 +141,7 @@ public class ProjectedPayloadMethodArgumentResolver implements HandlerMethodArgu
* or the map of arguments
* @return the created project instance
*/
protected Object createProjection(Class<?> targetType, Object rawValue){
protected Object createProjection(Class<?> targetType, Object rawValue) {
return this.projectionFactory.createProjection(targetType, rawValue);
}

View File

@@ -54,8 +54,6 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import static org.springframework.core.annotation.MergedAnnotations.SearchStrategy.TYPE_HIERARCHY;
/**
* {@link BeanFactoryInitializationAotProcessor} implementation for registering
* runtime hints discoverable through GraphQL controllers, such as:
@@ -80,11 +78,10 @@ import static org.springframework.core.annotation.MergedAnnotations.SearchStrate
*
* @author Brian Clozel
* @see org.springframework.graphql.data.method.HandlerMethodArgumentResolver
* @since 1.1.0
*/
class SchemaMappingBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor {
private final static boolean springDataPresent = ClassUtils.isPresent(
private static final boolean springDataPresent = ClassUtils.isPresent(
"org.springframework.data.projection.SpelAwareProxyProjectionFactory",
SchemaMappingBeanFactoryInitializationAotProcessor.class.getClassLoader());
@@ -94,8 +91,8 @@ class SchemaMappingBeanFactoryInitializationAotProcessor implements BeanFactoryI
List<Class<?>> controllers = new ArrayList<>();
List<Class<?>> controllerAdvices = new ArrayList<>();
Arrays.stream(beanFactory.getBeanDefinitionNames())
.map(beanName -> RegisteredBean.of(beanFactory, beanName).getBeanClass())
.forEach(beanClass -> {
.map((beanName) -> RegisteredBean.of(beanFactory, beanName).getBeanClass())
.forEach((beanClass) -> {
if (isController(beanClass)) {
controllers.add(beanClass);
}
@@ -107,11 +104,11 @@ class SchemaMappingBeanFactoryInitializationAotProcessor implements BeanFactoryI
}
private boolean isController(AnnotatedElement element) {
return MergedAnnotations.from(element, TYPE_HIERARCHY).isPresent(Controller.class);
return MergedAnnotations.from(element, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY).isPresent(Controller.class);
}
private boolean isControllerAdvice(AnnotatedElement element) {
return MergedAnnotations.from(element, TYPE_HIERARCHY).isPresent(ControllerAdvice.class);
return MergedAnnotations.from(element, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY).isPresent(ControllerAdvice.class);
}
@@ -124,7 +121,7 @@ class SchemaMappingBeanFactoryInitializationAotProcessor implements BeanFactoryI
private final HandlerMethodArgumentResolverComposite argumentResolvers;
public SchemaMappingBeanFactoryInitializationAotContribution(List<Class<?>> controllers, List<Class<?>> controllerAdvices) {
SchemaMappingBeanFactoryInitializationAotContribution(List<Class<?>> controllers, List<Class<?>> controllerAdvices) {
this.controllers = controllers;
this.controllerAdvices = controllerAdvices;
this.argumentResolvers = createArgumentResolvers();
@@ -141,19 +138,19 @@ class SchemaMappingBeanFactoryInitializationAotProcessor implements BeanFactoryI
public void applyTo(GenerationContext context, BeanFactoryInitializationCode initializationCode) {
RuntimeHints runtimeHints = context.getRuntimeHints();
registerSpringDataSpelSupport(runtimeHints);
this.controllers.forEach(controller -> {
this.controllers.forEach((controller) -> {
runtimeHints.reflection().registerType(controller, MemberCategory.INTROSPECT_DECLARED_METHODS);
ReflectionUtils.doWithMethods(controller,
method -> processSchemaMappingMethod(runtimeHints, method),
(method) -> processSchemaMappingMethod(runtimeHints, method),
this::isGraphQlHandlerMethod);
ReflectionUtils.doWithMethods(controller,
method -> processExceptionHandlerMethod(runtimeHints, method),
(method) -> processExceptionHandlerMethod(runtimeHints, method),
this::isExceptionHandlerMethod);
});
this.controllerAdvices.forEach(controllerAdvice -> {
this.controllerAdvices.forEach((controllerAdvice) -> {
runtimeHints.reflection().registerType(controllerAdvice, MemberCategory.INTROSPECT_DECLARED_METHODS);
ReflectionUtils.doWithMethods(controllerAdvice,
method -> processExceptionHandlerMethod(runtimeHints, method),
(method) -> processExceptionHandlerMethod(runtimeHints, method),
this::isExceptionHandlerMethod);
});
}
@@ -163,18 +160,18 @@ class SchemaMappingBeanFactoryInitializationAotProcessor implements BeanFactoryI
runtimeHints.reflection()
.registerType(SpelAwareProxyProjectionFactory.class)
.registerType(TypeReference.of("org.springframework.data.projection.SpelEvaluatingMethodInterceptor$TargetWrapper"),
builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
(builder) -> builder.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.INVOKE_PUBLIC_METHODS));
}
}
private boolean isGraphQlHandlerMethod(AnnotatedElement element) {
MergedAnnotations annotations = MergedAnnotations.from(element, TYPE_HIERARCHY);
MergedAnnotations annotations = MergedAnnotations.from(element, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
return annotations.isPresent(SchemaMapping.class) || annotations.isPresent(BatchMapping.class);
}
private boolean isExceptionHandlerMethod(AnnotatedElement element) {
return MergedAnnotations.from(element, TYPE_HIERARCHY).isPresent(GraphQlExceptionHandler.class);
return MergedAnnotations.from(element, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY).isPresent(GraphQlExceptionHandler.class);
}
private void processSchemaMappingMethod(RuntimeHints runtimeHints, Method method) {
@@ -229,7 +226,7 @@ class SchemaMappingBeanFactoryInitializationAotProcessor implements BeanFactoryI
}
private static class NoHintsRequired implements MethodParameterRuntimeHintsRegistrar {
private static final class NoHintsRequired implements MethodParameterRuntimeHintsRegistrar {
@Override
public void apply(RuntimeHints runtimeHints) {
@@ -242,14 +239,14 @@ class SchemaMappingBeanFactoryInitializationAotProcessor implements BeanFactoryI
private final MethodParameter methodParameter;
public ArgumentBindingHints(MethodParameter methodParameter) {
ArgumentBindingHints(MethodParameter methodParameter) {
this.methodParameter = methodParameter;
}
@Override
public void apply(RuntimeHints runtimeHints) {
Type parameterType = this.methodParameter.getGenericParameterType();
if (ArgumentValue.class.isAssignableFrom(methodParameter.getParameterType())) {
if (ArgumentValue.class.isAssignableFrom(this.methodParameter.getParameterType())) {
parameterType = this.methodParameter.nested().getNestedGenericParameterType();
}
bindingRegistrar.registerReflectionHints(runtimeHints.reflection(), parameterType);
@@ -261,7 +258,7 @@ class SchemaMappingBeanFactoryInitializationAotProcessor implements BeanFactoryI
private final MethodParameter methodParameter;
public DataLoaderHints(MethodParameter methodParameter) {
DataLoaderHints(MethodParameter methodParameter) {
this.methodParameter = methodParameter;
}
@@ -277,7 +274,7 @@ class SchemaMappingBeanFactoryInitializationAotProcessor implements BeanFactoryI
private final MethodParameter methodParameter;
public ProjectedPayloadHints(MethodParameter methodParameter) {
ProjectedPayloadHints(MethodParameter methodParameter) {
this.methodParameter = methodParameter;
}

View File

@@ -57,11 +57,11 @@ public class SortMethodArgumentResolver implements HandlerMethodArgumentResolver
Sort sort = this.sortStrategy.extract(environment);
if (parameter.isOptional()) {
sort = (sort == Sort.unsorted() ? null : sort);
sort = (sort == Sort.unsorted()) ? null : sort;
return Optional.ofNullable(sort);
}
return (sort != null ? sort : Sort.unsorted());
return (sort != null) ? sort : Sort.unsorted();
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import java.net.URI;

View File

@@ -30,6 +30,7 @@ import org.springframework.util.Assert;
* Resolver for a method argument of type {@link Subrange} initialized
* from "first", "last", "before", and "after" GraphQL arguments.
*
* @param <P> the type of position in the subrange
* @author Rossen Stoyanchev
* @since 1.2.0
*/
@@ -62,12 +63,15 @@ public class SubrangeMethodArgumentResolver<P> implements HandlerMethodArgumentR
forward = false;
}
}
P pos = (cursor != null ? this.cursorStrategy.fromCursor(cursor) : null);
P pos = (cursor != null) ? this.cursorStrategy.fromCursor(cursor) : null;
return createSubrange(pos, count, forward);
}
/**
* Allows subclasses to create an extension of {@link Subrange}.
* @param pos the position in the subrange
* @param count the number of elements in the subrange
* @param forward whether the scroll direction is forward or backward from this position
*/
protected Subrange<P> createSubrange(@Nullable P pos, @Nullable Integer count, boolean forward) {
return new Subrange<>(pos, count, forward);

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.method.annotation.support;
import java.lang.annotation.Annotation;
@@ -43,9 +44,8 @@ import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
* requires bean validation.
*
* @author Rossen Stoyanchev
* @since 1.2.0
*/
class ValidationHelper {
final class ValidationHelper {
private final Validator validator;
@@ -62,7 +62,7 @@ class ValidationHelper {
* {@link Validated}, {@link Valid}, or {@link Constraint} annotations.
*/
@Nullable
public BiConsumer<Object, Object[]> getValidationHelperFor(HandlerMethod handlerMethod) {
BiConsumer<Object, Object[]> getValidationHelperFor(HandlerMethod handlerMethod) {
boolean requiresMethodValidation = false;
Class<?>[] methodValidationGroups = null;
@@ -88,18 +88,18 @@ class ValidationHelper {
}
else if (annot.annotationType().equals(Validated.class)) {
Class<?>[] groups = ((Validated) annot).value();
parameterValidator = (parameterValidator != null ?
parameterValidator = (parameterValidator != null) ?
parameterValidator.andThen(new MethodParameterValidator(i, groups)) :
new MethodParameterValidator(i, groups));
new MethodParameterValidator(i, groups);
}
}
}
BiConsumer<Object, Object[]> result = (requiresMethodValidation ?
new HandlerMethodValidator(handlerMethod, methodValidationGroups) : null);
BiConsumer<Object, Object[]> result = (requiresMethodValidation) ?
new HandlerMethodValidator(handlerMethod, methodValidationGroups) : null;
if (parameterValidator != null) {
return (result != null ? result.andThen(parameterValidator) : parameterValidator);
return (result != null) ? result.andThen(parameterValidator) : parameterValidator;
}
return result;
@@ -120,7 +120,7 @@ class ValidationHelper {
* {@link Validator} bean declared, or {@code null} otherwise.
*/
@Nullable
public static ValidationHelper createIfValidatorPresent(ApplicationContext context) {
static ValidationHelper createIfValidatorPresent(ApplicationContext context) {
Validator validator = context.getBeanProvider(Validator.class).getIfAvailable();
if (validator instanceof LocalValidatorFactoryBean) {
validator = ((LocalValidatorFactoryBean) validator).getValidator();
@@ -128,13 +128,13 @@ class ValidationHelper {
else if (validator instanceof SpringValidatorAdapter) {
validator = validator.unwrap(Validator.class);
}
return (validator != null ? create(validator) : null);
return (validator != null) ? create(validator) : null;
}
/**
* Factory method with a given {@link Validator} instance.
*/
public static ValidationHelper create(Validator validator) {
static ValidationHelper create(Validator validator) {
return new ValidationHelper(validator);
}
@@ -151,7 +151,7 @@ class ValidationHelper {
HandlerMethodValidator(HandlerMethod handlerMethod, @Nullable Class<?>[] validationGroups) {
Assert.notNull(handlerMethod, "HandlerMethod is required");
this.method = handlerMethod.getMethod();
this.validationGroups = (validationGroups != null ? validationGroups : new Class<?>[] {});
this.validationGroups = (validationGroups != null) ? validationGroups : new Class<?>[] {};
}
@Override
@@ -181,7 +181,7 @@ class ValidationHelper {
MethodParameterValidator(int index, @Nullable Class<?>[] validationGroups) {
this.index = index;
this.validationGroups = (validationGroups != null ? validationGroups : new Class<?>[] {});
this.validationGroups = (validationGroups != null) ? validationGroups : new Class<?>[] {};
}
@Override

View File

@@ -1,3 +1,19 @@
/*
* 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.
* 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.
*/
/**
* Resolvers for method parameters of annotated handler methods.
*/

View File

@@ -28,7 +28,6 @@ import java.util.Base64;
* <p>To create an instance, use {@link CursorEncoder#base64()}.
*
* @author Rossen Stoyanchev
* @since 1.2.0
*/
final class Base64CursorEncoder implements CursorEncoder {

View File

@@ -27,7 +27,6 @@ import org.springframework.util.Assert;
* the first one that supports a given Object container type, and delegates to it.
*
* @author Rossen Stoyanchev
* @since 1.2.0
*/
final class CompositeConnectionAdapter implements ConnectionAdapter {
@@ -45,18 +44,22 @@ final class CompositeConnectionAdapter implements ConnectionAdapter {
return (getAdapter(containerType) != null);
}
@Override
public <T> Collection<T> getContent(Object container) {
return getRequiredAdapter(container).getContent(container);
}
@Override
public boolean hasPrevious(Object container) {
return getRequiredAdapter(container).hasPrevious(container);
}
@Override
public boolean hasNext(Object container) {
return getRequiredAdapter(container).hasNext(container);
}
@Override
public String cursorAt(Object container, int index) {
return getRequiredAdapter(container).cursorAt(container, index);
}

View File

@@ -30,26 +30,33 @@ public interface ConnectionAdapter {
/**
* Whether the adapter supports the given Object container type.
* @param containerType the container type to check for support
*/
boolean supports(Class<?> containerType);
/**
* Return the contained items as a List.
* @param <T> the type of objects in the collection
* @param container the container of elements
*/
<T> Collection<T> getContent(Object container);
/**
* Whether there are more pages before this one.
* @param container the container of elements
*/
boolean hasPrevious(Object container);
/**
* Whether there are more pages after this one.
* @param container the container of elements
*/
boolean hasNext(Object container);
/**
* Return a cursor for the item at the given index.
* @param container the container of elements
* @param index the index of an element in the container
*/
String cursorAt(Object container, int index);

View File

@@ -22,6 +22,7 @@ import org.springframework.util.Assert;
* Convenient base class for implementations of
* {@link org.springframework.graphql.data.pagination.ConnectionAdapter}.
*
* @param <P> the position type
* @author Rossen Stoyanchev
* @since 1.2.0
*/
@@ -32,6 +33,7 @@ public class ConnectionAdapterSupport<P> {
/**
* Constructor with a {@link CursorStrategy} to use.
* @param cursorStrategy the cursor strategy to use
*/
protected ConnectionAdapterSupport(CursorStrategy<P> cursorStrategy) {
Assert.notNull(cursorStrategy, "CursorStrategy is required");

View File

@@ -143,7 +143,7 @@ public final class ConnectionFieldTypeVisitor extends GraphQLTypeVisitorStub {
@Nullable
private static GraphQLObjectType getAsObjectType(@Nullable GraphQLFieldDefinition field) {
return (getType(field) instanceof GraphQLObjectType type ? type : null);
return (getType(field) instanceof GraphQLObjectType type) ? type : null;
}
@Nullable
@@ -162,7 +162,7 @@ public final class ConnectionFieldTypeVisitor extends GraphQLTypeVisitorStub {
return null;
}
GraphQLOutputType type = field.getType();
return (type instanceof GraphQLNonNull nonNullType ? nonNullType.getWrappedType() : type);
return (type instanceof GraphQLNonNull nonNullType) ? nonNullType.getWrappedType() : type;
}
@@ -183,7 +183,7 @@ public final class ConnectionFieldTypeVisitor extends GraphQLTypeVisitorStub {
*/
private record ConnectionDataFetcher(DataFetcher<?> delegate, ConnectionAdapter adapter) implements DataFetcher<Object> {
private final static Connection<?> EMPTY_CONNECTION =
private static final Connection<?> EMPTY_CONNECTION =
new DefaultConnection<>(Collections.emptyList(), new DefaultPageInfo(null, null, false, false));

View File

@@ -24,6 +24,7 @@ package org.springframework.graphql.data.pagination;
* {@link #withEncoder(CursorStrategy, CursorEncoder)} to further encode and
* decode cursor Strings to make them opaque for clients.
*
* @param <P> the type of position
* @author Rossen Stoyanchev
* @since 1.2.0
*/
@@ -31,6 +32,7 @@ public interface CursorStrategy<P> {
/**
* Whether the strategy supports the given type of position Object.
* @param targetType the type of position to be checked
*/
boolean supports(Class<?> targetType);
@@ -52,6 +54,9 @@ public interface CursorStrategy<P> {
/**
* Decorate the given {@code CursorStrategy} with encoding and decoding
* that makes the String cursor opaque to clients.
* @param <T> the type of position for the given strategy
* @param strategy the cursor strategy to decorate
* @param encoder strategy for encoding the cursor
*/
static <T> EncodingCursorStrategy<T> withEncoder(CursorStrategy<T> strategy, CursorEncoder encoder) {
return new EncodingCursorStrategy<>(strategy, encoder);

View File

@@ -25,6 +25,7 @@ import org.springframework.util.Assert;
* <p>To create an instance, use
* {@link CursorStrategy#withEncoder(CursorStrategy, CursorEncoder)}.
*
* @param <T> the type of position
* @author Rossen Stoyanchev
* @since 1.2.0
*/

View File

@@ -22,7 +22,6 @@ package org.springframework.graphql.data.pagination;
* <p>To create an instance, use {@link CursorEncoder#noOpEncoder()}.
*
* @author Rossen Stoyanchev
* @since 1.2.0
*/
final class NoOpCursorEncoder implements CursorEncoder {

View File

@@ -26,6 +26,7 @@ import org.springframework.lang.Nullable;
* Container for parameters that limit result elements to a subrange including a
* relative position, number of elements, and direction.
*
* @param <P> the type of position in the entire collection
* @author Rossen Stoyanchev
* @since 1.2.0
*/
@@ -41,10 +42,13 @@ public class Subrange<P> {
/**
* Constructor with the relative position, count, and direction.
* @param position the position in the entire collection
* @param count the number of elements in the subrange
* @param forward whether the subrange is forward or backward from ths position
*/
public Subrange(@Nullable P position, @Nullable Integer count, boolean forward) {
this.position = Optional.ofNullable(position);
this.count = (count != null ? OptionalInt.of(count) : OptionalInt.empty());
this.count = (count != null) ? OptionalInt.of(count) : OptionalInt.empty();
this.forward = forward;
}

View File

@@ -41,7 +41,7 @@ public abstract class AbstractSortStrategy implements SortStrategy {
List<String> properties = getProperties(environment);
if (!ObjectUtils.isEmpty(properties)) {
Sort.Direction direction = getDirection(environment);
direction = (direction != null ? direction : Sort.DEFAULT_DIRECTION);
direction = (direction != null) ? direction : Sort.DEFAULT_DIRECTION;
List<Sort.Order> sortOrders = new ArrayList<>(properties.size());
for (String property : properties) {
sortOrders.add(new Sort.Order(direction, property));
@@ -53,11 +53,13 @@ public abstract class AbstractSortStrategy implements SortStrategy {
/**
* Return the sort properties to use, or an empty list if there are none.
* @param environment the data fetching environment for this operation
*/
protected abstract List<String> getProperties(DataFetchingEnvironment environment);
/**
* Return the sort direction to use, or {@code null}.
* @param environment the data fetching environment for this operation
*/
@Nullable
protected abstract Sort.Direction getDirection(DataFetchingEnvironment environment);

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.query;
import java.util.List;
@@ -42,11 +43,10 @@ import org.springframework.util.Assert;
* already have registrations.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
class AutoRegistrationRuntimeWiringConfigurer implements RuntimeWiringConfigurer {
private final static Log logger = LogFactory.getLog(AutoRegistrationRuntimeWiringConfigurer.class);
private static final Log logger = LogFactory.getLog(AutoRegistrationRuntimeWiringConfigurer.class);
private final Map<String, DataFetcherFactory> dataFetcherFactories;
@@ -107,7 +107,7 @@ class AutoRegistrationRuntimeWiringConfigurer implements RuntimeWiringConfigurer
@Override
public boolean providesDataFetcher(FieldWiringEnvironment environment) {
if (dataFetcherFactories.isEmpty()) {
if (AutoRegistrationRuntimeWiringConfigurer.this.dataFetcherFactories.isEmpty()) {
return false;
}
@@ -118,7 +118,7 @@ class AutoRegistrationRuntimeWiringConfigurer implements RuntimeWiringConfigurer
String outputTypeName = getOutputTypeName(environment);
boolean result = (outputTypeName != null &&
dataFetcherFactories.containsKey(outputTypeName) &&
AutoRegistrationRuntimeWiringConfigurer.this.dataFetcherFactories.containsKey(outputTypeName) &&
!hasDataFetcherFor(environment.getFieldDefinition()));
if (!result) {
@@ -150,7 +150,7 @@ class AutoRegistrationRuntimeWiringConfigurer implements RuntimeWiringConfigurer
}
private GraphQLType removeNonNullWrapper(GraphQLType outputType) {
return (outputType instanceof GraphQLNonNull wrapper ? wrapper.getWrappedType() : outputType);
return (outputType instanceof GraphQLNonNull wrapper) ? wrapper.getWrappedType() : outputType;
}
private boolean isConnectionType(GraphQLType type) {
@@ -162,7 +162,7 @@ class AutoRegistrationRuntimeWiringConfigurer implements RuntimeWiringConfigurer
private boolean hasDataFetcherFor(FieldDefinition fieldDefinition) {
if (this.existingQueryDataFetcherPredicate == null) {
Map<String, ?> map = this.builder.build().getDataFetcherForType("Query");
this.existingQueryDataFetcherPredicate = fieldName -> map.get(fieldName) != null;
this.existingQueryDataFetcherPredicate = (fieldName) -> map.get(fieldName) != null;
}
return this.existingQueryDataFetcherPredicate.test(fieldDefinition.getName());
}
@@ -171,7 +171,7 @@ class AutoRegistrationRuntimeWiringConfigurer implements RuntimeWiringConfigurer
if (logger.isTraceEnabled()) {
String query = environment.getFieldDefinition().getName();
logger.trace((match ? "Matched" : "Skipped") +
" output typeName " + (typeName != null ? "'" + typeName + "'" : "null") +
" output typeName " + ((typeName != null) ? "'" + typeName + "'" : "null") +
" for query '" + query + "'");
}
}
@@ -182,12 +182,12 @@ class AutoRegistrationRuntimeWiringConfigurer implements RuntimeWiringConfigurer
String outputTypeName = getOutputTypeName(environment);
logTraceMessage(environment, outputTypeName, true);
DataFetcherFactory factory = dataFetcherFactories.get(outputTypeName);
DataFetcherFactory factory = AutoRegistrationRuntimeWiringConfigurer.this.dataFetcherFactories.get(outputTypeName);
Assert.notNull(factory, "Expected DataFetcher factory for typeName '" + outputTypeName + "'");
GraphQLType type = removeNonNullWrapper(environment.getFieldType());
return (isConnectionType(type) ? factory.scrollable() :
(type instanceof GraphQLList ? factory.many() : factory.single()));
(type instanceof GraphQLList) ? factory.many() : factory.single());
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.query;
import java.util.Map;
@@ -39,9 +40,9 @@ import org.springframework.lang.Nullable;
* already have registrations.
*
* @author Rossen Stoyanchev
* @deprecated in favor of {@link AutoRegistrationRuntimeWiringConfigurer}
* @deprecated since 1.0.0 in favor of {@link AutoRegistrationRuntimeWiringConfigurer}
*/
@Deprecated
@Deprecated(since = "1.0.0", forRemoval = true)
class AutoRegistrationTypeVisitor extends GraphQLTypeVisitorStub {
private final Map<String, Function<Boolean, DataFetcher<?>>> dataFetcherFactories;
@@ -52,7 +53,7 @@ class AutoRegistrationTypeVisitor extends GraphQLTypeVisitorStub {
* @param dataFetcherFactories map with GraphQL type names as keys and
* functions as values to create a DataFetcher for single or many values
*/
public AutoRegistrationTypeVisitor(Map<String, Function<Boolean, DataFetcher<?>>> dataFetcherFactories) {
AutoRegistrationTypeVisitor(Map<String, Function<Boolean, DataFetcher<?>>> dataFetcherFactories) {
this.dataFetcherFactories = dataFetcherFactories;
}
@@ -71,9 +72,9 @@ class AutoRegistrationTypeVisitor extends GraphQLTypeVisitorStub {
return TraversalControl.ABORT;
}
DataFetcher<?> dataFetcher = (fieldType instanceof GraphQLList ?
DataFetcher<?> dataFetcher = (fieldType instanceof GraphQLList) ?
getDataFetcher(((GraphQLList) fieldType).getWrappedType(), false) :
getDataFetcher(fieldType, true));
getDataFetcher(fieldType, true);
if (dataFetcher != null) {
GraphQLCodeRegistry.Builder registry = context.getVarFromParents(GraphQLCodeRegistry.Builder.class);

View File

@@ -86,6 +86,7 @@ public final class JsonKeysetCursorStrategy implements CursorStrategy<Map<String
/**
* Constructor with a {@link CodecConfigurer} in which to find the JSON
* encoder and decoder to use.
* @param codecConfigurer the codec configurer to be checked for JSON codec
*/
public JsonKeysetCursorStrategy(CodecConfigurer codecConfigurer) {
Assert.notNull(codecConfigurer, "CodecConfigurer is required");
@@ -128,7 +129,7 @@ public final class JsonKeysetCursorStrategy implements CursorStrategy<Map<String
public Map<String, Object> fromCursor(String cursor) {
DataBuffer buffer = this.bufferFactory.wrap(cursor.getBytes(StandardCharsets.UTF_8));
Map<String, Object> map = ((Decoder<Map<String, Object>>) this.decoder).decode(buffer, MAP_TYPE, null, null);
return (map != null ? map : Collections.emptyMap());
return (map != null) ? map : Collections.emptyMap();
}
@@ -136,9 +137,9 @@ public final class JsonKeysetCursorStrategy implements CursorStrategy<Map<String
* Customizes the {@link ObjectMapper} to use default typing that supports
* {@link Date}, {@link Calendar}, and classes in {@code java.time}.
*/
private static class JacksonObjectMapperCustomizer {
private static final class JacksonObjectMapperCustomizer {
public static void customize(CodecConfigurer configurer) {
static void customize(CodecConfigurer configurer) {
PolymorphicTypeValidator validator = BasicPolymorphicTypeValidator.builder()
.allowIfBaseType(Map.class)

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2023 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -41,9 +41,8 @@ import org.springframework.util.CollectionUtils;
* is considered to be a composite property without further inspection.
*
* @author Mark Paluch
* @since 1.0.0
*/
class PropertySelection {
final class PropertySelection {
private final List<PropertyPath> propertyPaths;
@@ -54,9 +53,9 @@ class PropertySelection {
/**
* @return the property paths as list.
* Return the property paths as list.
*/
public List<String> toList() {
List<String> toList() {
return this.propertyPaths.stream().map(PropertyPath::toDotPath).toList();
}
@@ -64,14 +63,13 @@ class PropertySelection {
/**
* Create a property selection for the given {@link TypeInformation type} and
* {@link DataFetchingFieldSelectionSet}.
*
* @param typeInfo the type to inspect
* @param selectionSet the field selection to apply
* @return a property selection holding all selectable property paths.
*/
public static PropertySelection create(TypeInformation<?> typeInfo, DataFetchingFieldSelectionSet selectionSet) {
static PropertySelection create(TypeInformation<?> typeInfo, DataFetchingFieldSelectionSet selectionSet) {
FieldSelection selection = new DataFetchingFieldSelection(selectionSet);
List<PropertyPath> paths = getPropertyPaths(typeInfo, selection, path -> PropertyPath.from(path, typeInfo));
List<PropertyPath> paths = getPropertyPaths(typeInfo, selection, (path) -> PropertyPath.from(path, typeInfo));
return new PropertySelection(paths);
}
@@ -111,8 +109,8 @@ class PropertySelection {
private static boolean isConnectionEdges(SelectedField selectedField) {
return selectedField.getName().equals("edges") &&
selectedField.getParentField().getType() instanceof GraphQLNamedOutputType namedType &&
namedType.getName().endsWith("Connection");
selectedField.getParentField().getType() instanceof GraphQLNamedOutputType namedType &&
namedType.getName().endsWith("Connection");
}
private static boolean isConnectionEdgeNode(SelectedField selectedField) {
@@ -141,13 +139,12 @@ class PropertySelection {
interface FieldSelection extends Iterable<SelectedField> {
/**
* @return {@code true} if the field selection is empty
* Return {@code true} if the field selection is empty.
*/
boolean isEmpty();
/**
* Obtain the field selection (nested fields) for a given {@code field}.
*
* @param field the field for which nested fields should be obtained
* @return the field selection. Can be empty.
*/
@@ -174,7 +171,7 @@ class PropertySelection {
@Override
public boolean isEmpty() {
return selectedFields.isEmpty();
return this.selectedFields.isEmpty();
}
@Override
@@ -183,14 +180,14 @@ class PropertySelection {
for (SelectedField selectedField : this.allFields) {
if (field.equals(selectedField.getParentField())) {
selectedFields = (selectedFields != null ? selectedFields : new ArrayList<>());
selectedFields = (selectedFields != null) ? selectedFields : new ArrayList<>();
selectedFields.add(selectedField);
}
}
return (selectedFields != null ?
return (selectedFields != null) ?
new DataFetchingFieldSelection(selectedFields, this.allFields) :
EmptyFieldSelection.INSTANCE);
EmptyFieldSelection.INSTANCE;
}
@Override

View File

@@ -101,7 +101,7 @@ import org.springframework.validation.BindException;
*/
public abstract class QueryByExampleDataFetcher<T> {
private final static Log logger = LogFactory.getLog(QueryByExampleDataFetcher.class);
private static final Log logger = LogFactory.getLog(QueryByExampleDataFetcher.class);
private final TypeInformation<T> domainType;
@@ -147,7 +147,7 @@ public abstract class QueryByExampleDataFetcher<T> {
List<GraphQLArgument> definedArguments = environment.getFieldDefinition().getArguments();
if (definedArguments.size() == 1) {
String name = definedArguments.get(0).getName();
if (arguments.get(name) instanceof Map<?,?>) {
if (arguments.get(name) instanceof Map<?, ?>) {
return name;
}
}
@@ -202,6 +202,8 @@ public abstract class QueryByExampleDataFetcher<T> {
* without a {@code CursorStrategy} and default {@link ScrollSubrange}.
* For default values, see the respective methods on {@link Builder} and
* {@link ReactiveBuilder}.
* @param executors repositories to consider for registration
* @param reactiveExecutors reactive repositories to consider for registration
*/
public static RuntimeWiringConfigurer autoRegistrationConfigurer(
List<QueryByExampleExecutor<?>> executors,
@@ -215,10 +217,8 @@ public abstract class QueryByExampleDataFetcher<T> {
* {@link graphql.schema.idl.WiringFactory} to find queries with a return
* type whose name matches to the domain type name of the given repositories
* and registers {@link DataFetcher}s for them.
*
* <p><strong>Note:</strong> This applies only to top-level queries and
* repositories annotated with {@link GraphQlRepository @GraphQlRepository}.
*
* @param executors repositories to consider for registration
* @param reactiveExecutors reactive repositories to consider for registration
* @param cursorStrategy for decoding cursors in pagination requests;
@@ -301,13 +301,13 @@ public abstract class QueryByExampleDataFetcher<T> {
* registers {@link DataFetcher}s for those queries.
* <p><strong>Note:</strong> currently, this method will match only to
* queries under the top-level "Query" type in the GraphQL schema.
*
* @param executors repositories to consider for registration
* @param reactiveExecutors reactive repositories to consider for registration
* @return the created visitor
* @deprecated in favor of {@link #autoRegistrationConfigurer(List, List)}
* @deprecated since 1.0.0, in favor of {@link #autoRegistrationConfigurer(List, List)}
*/
@Deprecated
@Deprecated(since = "1.0.0", forRemoval = true)
@SuppressWarnings("removal")
public static GraphQLTypeVisitor autoRegistrationTypeVisitor(
List<QueryByExampleExecutor<?>> executors,
List<ReactiveQueryByExampleExecutor<?>> reactiveExecutors) {
@@ -318,7 +318,7 @@ public abstract class QueryByExampleDataFetcher<T> {
String typeName = RepositoryUtils.getGraphQlTypeName(executor);
if (typeName != null) {
Builder<?, ?> builder = customize(executor, builder(executor));
factories.put(typeName, single -> single ? builder.single() : builder.many());
factories.put(typeName, (single) -> single ? builder.single() : builder.many());
}
}
@@ -326,7 +326,7 @@ public abstract class QueryByExampleDataFetcher<T> {
String typeName = RepositoryUtils.getGraphQlTypeName(executor);
if (typeName != null) {
ReactiveBuilder<?, ?> builder = customize(executor, builder(executor));
factories.put(typeName, single -> single ? builder.single() : builder.many());
factories.put(typeName, (single) -> single ? builder.single() : builder.many());
}
}
@@ -336,7 +336,7 @@ public abstract class QueryByExampleDataFetcher<T> {
@SuppressWarnings({"unchecked", "rawtypes"})
private static Builder customize(QueryByExampleExecutor<?> executor, Builder builder) {
if(executor instanceof QueryByExampleBuilderCustomizer<?> customizer){
if (executor instanceof QueryByExampleBuilderCustomizer<?> customizer) {
return customizer.customize(builder);
}
return builder;
@@ -344,7 +344,7 @@ public abstract class QueryByExampleDataFetcher<T> {
@SuppressWarnings({"unchecked", "rawtypes"})
private static ReactiveBuilder customize(ReactiveQueryByExampleExecutor<?> executor, ReactiveBuilder builder) {
if(executor instanceof ReactiveQueryByExampleBuilderCustomizer<?> customizer){
if (executor instanceof ReactiveQueryByExampleBuilderCustomizer<?> customizer) {
return customizer.customize(builder);
}
return builder;
@@ -402,6 +402,7 @@ public abstract class QueryByExampleDataFetcher<T> {
* into the target {@code projectionType}. Projection types can be
* either interfaces with property getters to expose or regular classes
* outside the entity type hierarchy for DTO projections.
* @param <P> the result type
* @param projectionType projection type
* @return a new {@link Builder} instance with all previously
* configured options and {@code projectionType} applied
@@ -435,6 +436,8 @@ public abstract class QueryByExampleDataFetcher<T> {
* from the beginning, or {@link KeysetScrollPosition#reverse()} the same
* to go back from the end.
* <p>By default a count of 20 and {@link ScrollPosition#offset()} are used.
* @param defaultCount the default scroll count to use
* @param defaultPosition a function that returns the forward/backward scroll position
* @since 1.2.5
*/
public Builder<T, R> defaultScrollSubrange(
@@ -449,6 +452,7 @@ public abstract class QueryByExampleDataFetcher<T> {
* not specify a cursor and/or a count of items.
* <p>By default, this is {@link OffsetScrollPosition#offset()} with a
* count of 20.
* @param defaultSubrange the default scroll subrange to use, can be {@code null}
* @return a new {@link Builder} instance with all previously configured
* options and {@code Sort} applied
* @deprecated in favor of {@link #defaultScrollSubrange(int, Function)}
@@ -458,8 +462,8 @@ public abstract class QueryByExampleDataFetcher<T> {
public Builder<T, R> defaultScrollSubrange(@Nullable ScrollSubrange defaultSubrange) {
return new Builder<>(this.executor, this.domainType,
this.resultType, this.cursorStrategy,
(defaultSubrange != null ? defaultSubrange.count().getAsInt() : null),
(defaultSubrange != null ? forward -> defaultSubrange.position().get() : null),
(defaultSubrange != null) ? defaultSubrange.count().getAsInt() : null,
(defaultSubrange != null) ? (forward) -> defaultSubrange.position().get() : null,
this.sort);
}
@@ -497,9 +501,9 @@ public abstract class QueryByExampleDataFetcher<T> {
public DataFetcher<Iterable<R>> scrollable() {
return new ScrollableEntityFetcher<>(
this.executor, this.domainType, this.resultType,
(this.cursorStrategy != null ? this.cursorStrategy : RepositoryUtils.defaultCursorStrategy()),
(this.defaultScrollCount != null ? this.defaultScrollCount : RepositoryUtils.defaultScrollCount()),
(this.defaultScrollPosition != null ? this.defaultScrollPosition : RepositoryUtils.defaultScrollPosition()),
(this.cursorStrategy != null) ? this.cursorStrategy : RepositoryUtils.defaultCursorStrategy(),
(this.defaultScrollCount != null) ? this.defaultScrollCount : RepositoryUtils.defaultScrollCount(),
(this.defaultScrollPosition != null) ? this.defaultScrollPosition : RepositoryUtils.defaultScrollPosition(),
this.sort);
}
@@ -511,8 +515,7 @@ public abstract class QueryByExampleDataFetcher<T> {
* <p>This is supported by {@link #autoRegistrationConfigurer(List, List)
* Auto-registration}, which detects if a repository implements this
* interface and applies it accordingly.
*
* @param <T>
* @param <T> domain type
* @since 1.1.1
*/
public interface QueryByExampleBuilderCustomizer<T> {
@@ -578,13 +581,14 @@ public abstract class QueryByExampleDataFetcher<T> {
* into the target {@code projectionType}. Projection types can be
* either interfaces with property getters to expose or regular classes
* outside the entity type hierarchy for DTO projections.
* @param <P> the result type
* @param projectionType projection type
* @return a new {@link ReactiveBuilder} instance with all previously
* configured options and {@code projectionType} applied
*/
public <P> ReactiveBuilder<T, P> projectAs(Class<P> projectionType) {
Assert.notNull(projectionType, "Projection type must not be null");
return new ReactiveBuilder<>(this.executor, this.domainType,
return new ReactiveBuilder<>(this.executor, this.domainType,
projectionType, this.cursorStrategy, this.defaultScrollCount, this.defaultScrollPosition, this.sort);
}
@@ -611,6 +615,8 @@ public abstract class QueryByExampleDataFetcher<T> {
* from the beginning, or {@link KeysetScrollPosition#reverse()} the same
* to go back from the end.
* <p>By default a count of 20 and {@link ScrollPosition#offset()} are used.
* @param defaultCount the default scroll count to use
* @param defaultPosition a function that returns the forward/backward scroll position
* @since 1.2.5
*/
public ReactiveBuilder<T, R> defaultScrollSubrange(
@@ -625,6 +631,7 @@ public abstract class QueryByExampleDataFetcher<T> {
* not specify a cursor and/or a count of items.
* <p>By default, this is {@link OffsetScrollPosition#offset()} with a
* count of 20.
* @param defaultSubrange the default scroll subrange to use, can be {@code null}
* @return a new {@link Builder} instance with all previously configured
* options and {@code Sort} applied
* @deprecated in favor of {@link #defaultScrollSubrange(int, Function)}
@@ -634,8 +641,8 @@ public abstract class QueryByExampleDataFetcher<T> {
public ReactiveBuilder<T, R> defaultScrollSubrange(@Nullable ScrollSubrange defaultSubrange) {
return new ReactiveBuilder<>(this.executor, this.domainType,
this.resultType, this.cursorStrategy,
(defaultSubrange != null ? defaultSubrange.count().getAsInt() : null),
(defaultSubrange != null ? forward -> defaultSubrange.position().get() : null),
(defaultSubrange != null) ? defaultSubrange.count().getAsInt() : null,
(defaultSubrange != null) ? (forward) -> defaultSubrange.position().get() : null,
this.sort);
}
@@ -673,9 +680,9 @@ public abstract class QueryByExampleDataFetcher<T> {
public DataFetcher<Mono<Iterable<R>>> scrollable() {
return new ReactiveScrollableEntityFetcher<>(
this.executor, this.domainType, this.resultType,
(this.cursorStrategy != null ? this.cursorStrategy : RepositoryUtils.defaultCursorStrategy()),
(this.defaultScrollCount != null ? this.defaultScrollCount : RepositoryUtils.defaultScrollCount()),
(this.defaultScrollPosition != null ? this.defaultScrollPosition : RepositoryUtils.defaultScrollPosition()),
(this.cursorStrategy != null) ? this.cursorStrategy : RepositoryUtils.defaultCursorStrategy(),
(this.defaultScrollCount != null) ? this.defaultScrollCount : RepositoryUtils.defaultScrollCount(),
(this.defaultScrollPosition != null) ? this.defaultScrollPosition : RepositoryUtils.defaultScrollPosition(),
this.sort);
}
@@ -687,8 +694,7 @@ public abstract class QueryByExampleDataFetcher<T> {
* <p>This is supported by {@link #autoRegistrationConfigurer(List, List)
* Auto-registration}, which detects if a repository implements this
* interface and applies it accordingly.
*
* @param <T>
* @param <T> the domain type
* @since 1.1.1
*/
public interface ReactiveQueryByExampleBuilderCustomizer<T> {
@@ -728,7 +734,7 @@ public abstract class QueryByExampleDataFetcher<T> {
@Override
@SuppressWarnings({"ConstantConditions", "unchecked"})
public R get(DataFetchingEnvironment env) throws BindException {
return this.executor.findBy(buildExample(env), query -> {
return this.executor.findBy(buildExample(env), (query) -> {
FluentQuery.FetchableFluentQuery<R> queryToUse = (FluentQuery.FetchableFluentQuery<R>) query;
if (this.sort.isSorted()) {
@@ -777,7 +783,7 @@ public abstract class QueryByExampleDataFetcher<T> {
@Override
@SuppressWarnings("unchecked")
public Iterable<R> get(DataFetchingEnvironment env) throws BindException {
return this.executor.findBy(buildExample(env), query -> {
return this.executor.findBy(buildExample(env), (query) -> {
FluentQuery.FetchableFluentQuery<R> queryToUse = (FluentQuery.FetchableFluentQuery<R>) query;
if (this.sort.isSorted()) {
@@ -874,7 +880,7 @@ public abstract class QueryByExampleDataFetcher<T> {
@Override
@SuppressWarnings("unchecked")
public Mono<R> get(DataFetchingEnvironment env) throws BindException {
return this.executor.findBy(buildExample(env), query -> {
return this.executor.findBy(buildExample(env), (query) -> {
FluentQuery.ReactiveFluentQuery<R> queryToUse = (FluentQuery.ReactiveFluentQuery<R>) query;
if (this.sort.isSorted()) {
@@ -922,7 +928,7 @@ public abstract class QueryByExampleDataFetcher<T> {
@Override
@SuppressWarnings("unchecked")
public Flux<R> get(DataFetchingEnvironment env) throws BindException {
return this.executor.findBy(buildExample(env), query -> {
return this.executor.findBy(buildExample(env), (query) -> {
FluentQuery.ReactiveFluentQuery<R> queryToUse = (FluentQuery.ReactiveFluentQuery<R>) query;
if (this.sort.isSorted()) {
@@ -989,7 +995,7 @@ public abstract class QueryByExampleDataFetcher<T> {
@Override
@SuppressWarnings("unchecked")
public Mono<Iterable<R>> get(DataFetchingEnvironment env) throws BindException {
return this.executor.findBy(buildExample(env), query -> {
return this.executor.findBy(buildExample(env), (query) -> {
FluentQuery.ReactiveFluentQuery<R> queryToUse = (FluentQuery.ReactiveFluentQuery<R>) query;
if (this.sort.isSorted()) {

View File

@@ -107,7 +107,7 @@ import org.springframework.util.MultiValueMap;
*/
public abstract class QuerydslDataFetcher<T> {
private final static Log logger = LogFactory.getLog(QueryByExampleDataFetcher.class);
private static final Log logger = LogFactory.getLog(QueryByExampleDataFetcher.class);
private static final QuerydslPredicateBuilder BUILDER = new QuerydslPredicateBuilder(
DefaultConversionService.getSharedInstance(), SimpleEntityPathResolver.INSTANCE);
@@ -153,7 +153,7 @@ public abstract class QuerydslDataFetcher<T> {
for (Map.Entry<String, Object> entry : getArgumentValues(environment).entrySet()) {
Object value = entry.getValue();
List<Object> values = (value instanceof List ? (List<Object>) value : Collections.singletonList(value));
List<Object> values = (value instanceof List) ? (List<Object>) value : Collections.singletonList(value);
parameters.put(entry.getKey(), values);
}
@@ -225,6 +225,8 @@ public abstract class QuerydslDataFetcher<T> {
* without a {@code CursorStrategy} and default {@link ScrollSubrange}.
* For default values, see the respective methods on {@link Builder} and
* {@link ReactiveBuilder}.
* @param executors repositories to consider for registration
* @param reactiveExecutors reactive repositories to consider for registration
*/
public static RuntimeWiringConfigurer autoRegistrationConfigurer(
List<QuerydslPredicateExecutor<?>> executors,
@@ -244,7 +246,6 @@ public abstract class QuerydslDataFetcher<T> {
* If a repository is also an instance of {@link QuerydslBinderCustomizer},
* this is transparently detected and applied through the
* {@code QuerydslDataFetcher} builder methods.
*
* @param executors repositories to consider for registration
* @param reactiveExecutors reactive repositories to consider for registration
* @param cursorStrategy for decoding cursors in pagination requests;
@@ -337,14 +338,13 @@ public abstract class QuerydslDataFetcher<T> {
* If a repository is also an instance of {@link QuerydslBinderCustomizer},
* this is transparently detected and applied through the
* {@code QuerydslDataFetcher} builder methods.
*
* @param executors repositories to consider for registration
* @param reactiveExecutors reactive repositories to consider for registration
* @return the created visitor
* @deprecated in favor of {@link #autoRegistrationConfigurer(List, List)}
* @deprecated since 1.0.0 in favor of {@link #autoRegistrationConfigurer(List, List)}
*/
@SuppressWarnings({"unchecked", "rawtypes"})
@Deprecated
@SuppressWarnings({"unchecked", "rawtypes", "removal"})
@Deprecated(since = "1.0.0", forRemoval = true)
public static GraphQLTypeVisitor autoRegistrationTypeVisitor(
List<QuerydslPredicateExecutor<?>> executors,
List<ReactiveQuerydslPredicateExecutor<?>> reactiveExecutors) {
@@ -355,7 +355,7 @@ public abstract class QuerydslDataFetcher<T> {
String typeName = RepositoryUtils.getGraphQlTypeName(executor);
if (typeName != null) {
Builder<?, ?> builder = customize(executor, QuerydslDataFetcher.builder(executor).customizer(customizer(executor)));
factories.put(typeName, single -> single ? builder.single() : builder.many());
factories.put(typeName, (single) -> single ? builder.single() : builder.many());
}
}
@@ -363,7 +363,7 @@ public abstract class QuerydslDataFetcher<T> {
String typeName = RepositoryUtils.getGraphQlTypeName(executor);
if (typeName != null) {
ReactiveBuilder builder = customize(executor, QuerydslDataFetcher.builder(executor).customizer(customizer(executor)));
factories.put(typeName, single -> single ? builder.single() : builder.many());
factories.put(typeName, (single) -> single ? builder.single() : builder.many());
}
}
@@ -372,7 +372,7 @@ public abstract class QuerydslDataFetcher<T> {
@SuppressWarnings({"unchecked", "rawtypes"})
private static Builder customize(QuerydslPredicateExecutor<?> executor, Builder builder) {
if(executor instanceof QuerydslBuilderCustomizer<?> customizer){
if (executor instanceof QuerydslBuilderCustomizer<?> customizer) {
return customizer.customize(builder);
}
return builder;
@@ -380,7 +380,7 @@ public abstract class QuerydslDataFetcher<T> {
@SuppressWarnings({"unchecked", "rawtypes"})
private static ReactiveBuilder customize(ReactiveQuerydslPredicateExecutor<?> executor, ReactiveBuilder builder) {
if(executor instanceof ReactiveQuerydslBuilderCustomizer<?> customizer){
if (executor instanceof ReactiveQuerydslBuilderCustomizer<?> customizer) {
return customizer.customize(builder);
}
return builder;
@@ -388,9 +388,9 @@ public abstract class QuerydslDataFetcher<T> {
@SuppressWarnings("rawtypes")
private static QuerydslBinderCustomizer customizer(Object executor) {
return (executor instanceof QuerydslBinderCustomizer<?> ?
return (executor instanceof QuerydslBinderCustomizer<?>) ?
(QuerydslBinderCustomizer<? extends EntityPath<?>>) executor :
NO_OP_BINDER_CUSTOMIZER);
NO_OP_BINDER_CUSTOMIZER;
}
@@ -448,6 +448,7 @@ public abstract class QuerydslDataFetcher<T> {
* into the target {@code projectionType}. Projection types can be
* either interfaces with property getters to expose or regular classes
* outside the entity type hierarchy for DTO projections.
* @param <P> the result type
* @param projectionType projection type
* @return a new {@link Builder} instance with all previously
* configured options and {@code projectionType} applied
@@ -483,6 +484,8 @@ public abstract class QuerydslDataFetcher<T> {
* from the beginning, or {@link KeysetScrollPosition#reverse()} the same
* to go back from the end.
* <p>By default a count of 20 and {@link ScrollPosition#offset()} are used.
* @param defaultCount the default scroll count to use
* @param defaultPosition the function that returns the forward/backward scroll position.
* @since 1.2.5
*/
public Builder<T, R> defaultScrollSubrange(
@@ -496,6 +499,7 @@ public abstract class QuerydslDataFetcher<T> {
* Configure a {@link ScrollSubrange} to use when a paginated request does
* not specify a cursor and/or a count of items.
* <p>By default, this is {@link OffsetScrollPosition#offset()} with a count of 20.
* @param defaultSubrange the default scroll subrange to use, can be {@code null}
* @return a new {@link Builder} instance
* @since 1.2.0
* @deprecated in favor of {@link #defaultScrollSubrange(int, Function)}
@@ -504,8 +508,8 @@ public abstract class QuerydslDataFetcher<T> {
@Deprecated(since = "1.2.5", forRemoval = true)
public Builder<T, R> defaultScrollSubrange(@Nullable ScrollSubrange defaultSubrange) {
return new Builder<>(this.executor, this.domainType, this.resultType, this.cursorStrategy,
(defaultSubrange != null ? defaultSubrange.count().getAsInt() : null),
(defaultSubrange != null ? forward -> defaultSubrange.position().get() : null),
(defaultSubrange != null) ? defaultSubrange.count().getAsInt() : null,
(defaultSubrange != null) ? (forward) -> defaultSubrange.position().get() : null,
this.sort, this.customizer);
}
@@ -519,7 +523,7 @@ public abstract class QuerydslDataFetcher<T> {
Assert.notNull(sort, "Sort must not be null");
return new Builder<>(this.executor, this.domainType, this.resultType,
this.cursorStrategy, this.defaultScrollCount, this.defaultScrollPosition,
sort, customizer);
sort, this.customizer);
}
/**
@@ -529,7 +533,6 @@ public abstract class QuerydslDataFetcher<T> {
* itself, this is automatically detected and applied during
* {@link #autoRegistrationConfigurer(List, List) auto-registration}.
* For manual registration, you will need to use this method to apply it.
*
* @param customizer to customize the binding of the GraphQL request to
* Querydsl Predicate
* @return a new {@link Builder} instance with all previously configured
@@ -566,9 +569,9 @@ public abstract class QuerydslDataFetcher<T> {
public DataFetcher<Iterable<R>> scrollable() {
return new ScrollableEntityFetcher<>(
this.executor, this.domainType, this.resultType,
(this.cursorStrategy != null ? this.cursorStrategy : RepositoryUtils.defaultCursorStrategy()),
(this.defaultScrollCount != null ? this.defaultScrollCount : RepositoryUtils.defaultScrollCount()),
(this.defaultScrollPosition != null ? this.defaultScrollPosition : RepositoryUtils.defaultScrollPosition()),
(this.cursorStrategy != null) ? this.cursorStrategy : RepositoryUtils.defaultCursorStrategy(),
(this.defaultScrollCount != null) ? this.defaultScrollCount : RepositoryUtils.defaultScrollCount(),
(this.defaultScrollPosition != null) ? this.defaultScrollPosition : RepositoryUtils.defaultScrollPosition(),
this.sort, this.customizer);
}
@@ -577,12 +580,11 @@ public abstract class QuerydslDataFetcher<T> {
/**
* Callback interface that can be used to customize QuerydslDataFetcher
* {@link Builder} to change its configuration.
* {@link Builder} to change its configuration.
* <p>This is supported by {@link #autoRegistrationConfigurer(List, List)
* Auto-registration}, which detects if a repository implements this
* interface and applies it accordingly.
*
* @param <T>
* @param <T> the domain type
* @since 1.1.1
*/
public interface QuerydslBuilderCustomizer<T> {
@@ -651,6 +653,7 @@ public abstract class QuerydslDataFetcher<T> {
* into the target {@code projectionType}. Projection types can be
* either interfaces with property getters to expose or regular classes
* outside the entity type hierarchy for DTO projections.
* @param <P> the project type
* @param projectionType projection type
* @return a new {@link Builder} instance with all previously
* configured options and {@code projectionType} applied
@@ -686,6 +689,8 @@ public abstract class QuerydslDataFetcher<T> {
* from the beginning, or {@link KeysetScrollPosition#reverse()} the same
* to go back from the end.
* <p>By default a count of 20 and {@link ScrollPosition#offset()} are used.
* @param defaultCount the default scroll count to use
* @param defaultPosition a function that returns the forward/backward scroll position
* @since 1.2.5
*/
public ReactiveBuilder<T, R> defaultScrollSubrange(
@@ -699,6 +704,7 @@ public abstract class QuerydslDataFetcher<T> {
* Configure a {@link ScrollSubrange} to use when a paginated request does
* not specify a cursor and/or a count of items.
* <p>By default, this is {@link OffsetScrollPosition#offset()} with a count of 20.
* @param defaultSubrange the default scroll subrange to use, can be {@code null}
* @return a new {@link Builder} instance
* @since 1.2.0
* @deprecated in favor of {@link #defaultScrollSubrange(int, Function)}
@@ -708,8 +714,8 @@ public abstract class QuerydslDataFetcher<T> {
public ReactiveBuilder<T, R> defaultScrollSubrange(@Nullable ScrollSubrange defaultSubrange) {
return new ReactiveBuilder<>(this.executor, this.domainType, this.resultType,
this.cursorStrategy,
(defaultSubrange != null ? defaultSubrange.count().getAsInt() : null),
(defaultSubrange != null ? forward -> defaultSubrange.position().get() : null),
(defaultSubrange != null) ? defaultSubrange.count().getAsInt() : null,
(defaultSubrange != null) ? (forward) -> defaultSubrange.position().get() : null,
this.sort, this.customizer);
}
@@ -733,7 +739,6 @@ public abstract class QuerydslDataFetcher<T> {
* itself, this is automatically detected and applied during
* {@link #autoRegistrationConfigurer(List, List) auto-registration}.
* For manual registration, you will need to use this method to apply it.
*
* @param customizer to customize the GraphQL query to Querydsl
* Predicate binding with
* @return a new {@link Builder} instance with all previously configured
@@ -770,9 +775,9 @@ public abstract class QuerydslDataFetcher<T> {
public DataFetcher<Mono<Iterable<R>>> scrollable() {
return new ReactiveScrollableEntityFetcher<>(
this.executor, this.domainType, this.resultType,
(this.cursorStrategy != null ? this.cursorStrategy : RepositoryUtils.defaultCursorStrategy()),
(this.defaultScrollCount != null ? this.defaultScrollCount : RepositoryUtils.defaultScrollCount()),
(this.defaultScrollPosition != null ? this.defaultScrollPosition : RepositoryUtils.defaultScrollPosition()),
(this.cursorStrategy != null) ? this.cursorStrategy : RepositoryUtils.defaultCursorStrategy(),
(this.defaultScrollCount != null) ? this.defaultScrollCount : RepositoryUtils.defaultScrollCount(),
(this.defaultScrollPosition != null) ? this.defaultScrollPosition : RepositoryUtils.defaultScrollPosition(),
this.sort, this.customizer);
}
@@ -786,7 +791,7 @@ public abstract class QuerydslDataFetcher<T> {
* Auto-registration}, which detects if a repository implements this
* interface and applies it accordingly.
*
* @param <T>
* @param <T> the domain type
* @since 1.1.1
*/
public interface ReactiveQuerydslBuilderCustomizer<T> {
@@ -828,15 +833,15 @@ public abstract class QuerydslDataFetcher<T> {
@Override
@SuppressWarnings({"ConstantConditions", "unchecked"})
public R get(DataFetchingEnvironment env) {
return this.executor.findBy(buildPredicate(env), query -> {
return this.executor.findBy(buildPredicate(env), (query) -> {
FetchableFluentQuery<R> queryToUse = (FetchableFluentQuery<R>) query;
if (this.sort.isSorted()){
if (this.sort.isSorted()) {
queryToUse = queryToUse.sortBy(this.sort);
}
Class<R> resultType = this.resultType;
if (requiresProjection(resultType)){
if (requiresProjection(resultType)) {
queryToUse = queryToUse.as(resultType);
}
else {
@@ -878,14 +883,14 @@ public abstract class QuerydslDataFetcher<T> {
@Override
@SuppressWarnings("unchecked")
public Iterable<R> get(DataFetchingEnvironment env) {
return this.executor.findBy(buildPredicate(env), query -> {
return this.executor.findBy(buildPredicate(env), (query) -> {
FetchableFluentQuery<R> queryToUse = (FetchableFluentQuery<R>) query;
if (this.sort.isSorted()){
if (this.sort.isSorted()) {
queryToUse = queryToUse.sortBy(this.sort);
}
if (requiresProjection(this.resultType)){
if (requiresProjection(this.resultType)) {
queryToUse = queryToUse.as(this.resultType);
}
else {
@@ -971,14 +976,14 @@ public abstract class QuerydslDataFetcher<T> {
@Override
@SuppressWarnings("unchecked")
public Mono<R> get(DataFetchingEnvironment env) {
return this.executor.findBy(buildPredicate(env), query -> {
return this.executor.findBy(buildPredicate(env), (query) -> {
FluentQuery.ReactiveFluentQuery<R> queryToUse = (FluentQuery.ReactiveFluentQuery<R>) query;
if (this.sort.isSorted()){
if (this.sort.isSorted()) {
queryToUse = queryToUse.sortBy(this.sort);
}
if (requiresProjection(this.resultType)){
if (requiresProjection(this.resultType)) {
queryToUse = queryToUse.as(this.resultType);
}
else {
@@ -1021,14 +1026,14 @@ public abstract class QuerydslDataFetcher<T> {
@Override
@SuppressWarnings("unchecked")
public Flux<R> get(DataFetchingEnvironment env) {
return this.executor.findBy(buildPredicate(env), query -> {
return this.executor.findBy(buildPredicate(env), (query) -> {
FluentQuery.ReactiveFluentQuery<R> queryToUse = (FluentQuery.ReactiveFluentQuery<R>) query;
if (this.sort.isSorted()){
if (this.sort.isSorted()) {
queryToUse = queryToUse.sortBy(this.sort);
}
if (requiresProjection(this.resultType)){
if (requiresProjection(this.resultType)) {
queryToUse = queryToUse.as(this.resultType);
}
else {
@@ -1091,14 +1096,14 @@ public abstract class QuerydslDataFetcher<T> {
@Override
@SuppressWarnings("unchecked")
public Mono<Iterable<R>> get(DataFetchingEnvironment env) {
return this.executor.findBy(buildPredicate(env), query -> {
return this.executor.findBy(buildPredicate(env), (query) -> {
FluentQuery.ReactiveFluentQuery<R> queryToUse = (FluentQuery.ReactiveFluentQuery<R>) query;
if (this.sort.isSorted()){
if (this.sort.isSorted()) {
queryToUse = queryToUse.sortBy(this.sort);
}
if (requiresProjection(this.resultType)){
if (requiresProjection(this.resultType)) {
queryToUse = queryToUse.as(this.resultType);
}
else {

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.data.query;
import java.lang.reflect.Type;
@@ -40,16 +41,19 @@ import org.springframework.util.StringUtils;
*
* @author Rossen Stoyanchev
* @author Oliver Drotbohm
* @since 1.0.0
*/
class RepositoryUtils {
final class RepositoryUtils {
private RepositoryUtils() {
}
@SuppressWarnings("unchecked")
public static <T> Class<T> getDomainType(Object executor) {
static <T> Class<T> getDomainType(Object executor) {
return (Class<T>) getRepositoryMetadata(executor).getDomainType();
}
public static RepositoryMetadata getRepositoryMetadata(Object executor) {
static RepositoryMetadata getRepositoryMetadata(Object executor) {
Assert.isInstanceOf(Repository.class, executor);
Type[] genericInterfaces = executor.getClass().getGenericInterfaces();
@@ -68,7 +72,7 @@ class RepositoryUtils {
}
@Nullable
public static String getGraphQlTypeName(Object repository) {
static String getGraphQlTypeName(Object repository) {
GraphQlRepository annotation =
AnnotatedElementUtils.findMergedAnnotation(repository.getClass(), GraphQlRepository.class);
@@ -81,19 +85,19 @@ class RepositoryUtils {
}
public static CursorStrategy<ScrollPosition> defaultCursorStrategy() {
static CursorStrategy<ScrollPosition> defaultCursorStrategy() {
return CursorStrategy.withEncoder(new ScrollPositionCursorStrategy(), CursorEncoder.base64());
}
public static int defaultScrollCount() {
static int defaultScrollCount() {
return 20;
}
public static Function<Boolean, ScrollPosition> defaultScrollPosition() {
return forward -> ScrollPosition.offset();
static Function<Boolean, ScrollPosition> defaultScrollPosition() {
return (forward) -> ScrollPosition.offset();
}
public static ScrollSubrange getScrollSubrange(
static ScrollSubrange getScrollSubrange(
DataFetchingEnvironment env, CursorStrategy<ScrollPosition> cursorStrategy) {
boolean forward = true;
@@ -106,7 +110,7 @@ class RepositoryUtils {
forward = false;
}
}
ScrollPosition pos = (cursor != null ? cursorStrategy.fromCursor(cursor) : null);
ScrollPosition pos = (cursor != null) ? cursorStrategy.fromCursor(cursor) : null;
return ScrollSubrange.create(pos, count, forward);
}

View File

@@ -51,6 +51,7 @@ public final class ScrollPositionCursorStrategy implements CursorStrategy<Scroll
/**
* Constructor with a given strategy to convert a
* {@link KeysetScrollPosition#getKeys() keyset} to and from a cursor.
* @param keysetCursorStrategy the keyset cursor strategy
*/
public ScrollPositionCursorStrategy(CursorStrategy<Map<String, Object>> keysetCursorStrategy) {
Assert.notNull(keysetCursorStrategy, "'keysetCursorStrategy' is required");
@@ -80,7 +81,7 @@ public final class ScrollPositionCursorStrategy implements CursorStrategy<Scroll
try {
if (cursor.startsWith(OFFSET_PREFIX)) {
long index = Long.parseLong(cursor.substring(2));
return ScrollPosition.offset(index > 0 ? index : 0);
return ScrollPosition.offset((index > 0) ? index : 0);
}
else if (cursor.startsWith(KEYSET_PREFIX)) {
Map<String, Object> keys = this.keysetCursorStrategy.fromCursor(cursor.substring(2));

View File

@@ -49,6 +49,9 @@ public final class ScrollSubrange extends Subrange<ScrollPosition> {
/**
* Public constructor.
* @param pos the reference position, or {@code null} if not specified
* @param count how many to return, or {@code null} if not specified
* @param forward whether scroll forward (true) or backward (false)
* @deprecated in favor of {@link #create}, to be removed in 1.3.
*/
@Deprecated(since = "1.2.4", forRemoval = true)
@@ -111,7 +114,7 @@ public final class ScrollSubrange extends Subrange<ScrollPosition> {
}
else {
// Advance back by 1 at least to item before position
int advanceCount = (count != null ? count : 1);
int advanceCount = (count != null) ? count : 1;
if (position.getOffset() >= advanceCount) {
position = position.advanceBy(-advanceCount);
}

View File

@@ -38,6 +38,7 @@ public final class SliceConnectionAdapter
/**
* Constructor with the {@link CursorStrategy} to use to encode the
* {@code ScrollPosition} of page items.
* @param strategy the cursor strategy to use
*/
public SliceConnectionAdapter(CursorStrategy<ScrollPosition> strategy) {
super(strategy);

View File

@@ -32,6 +32,7 @@ public interface SortStrategy {
/**
* Return a {@link Sort} instance by extracting the sort information from
* GraphQL arguments, or {@link Sort#unsorted()} otherwise.
* @param environment the data fetching environment
*/
Sort extract(DataFetchingEnvironment environment);

View File

@@ -38,6 +38,7 @@ import org.springframework.lang.Nullable;
* Implementation of {@link GraphQlSource.Builder} that leaves it to subclasses
* to initialize {@link GraphQLSchema}.
*
* @param <B> the builder type
* @author Rossen Stoyanchev
* @author Brian Clozel
* @since 1.0.0
@@ -90,8 +91,8 @@ public abstract class AbstractGraphQlSourceBuilder<B extends GraphQlSource.Build
@Override
public B configureGraphQl(Consumer<GraphQL.Builder> configurer) {
this.graphQlConfigurer = (this.graphQlConfigurer != null ?
this.graphQlConfigurer.andThen(configurer) : configurer);
this.graphQlConfigurer = (this.graphQlConfigurer != null) ?
this.graphQlConfigurer.andThen(configurer) : configurer;
return self();
}
@@ -147,13 +148,14 @@ public abstract class AbstractGraphQlSourceBuilder<B extends GraphQlSource.Build
visitorsToUse.add(ContextDataFetcherDecorator.createVisitor(this.subscriptionExceptionResolvers));
new SchemaTraverser().depthFirstFullSchema(visitorsToUse, schema, vars);
return schema.transformWithoutTypes(builder -> builder.codeRegistry(outputCodeRegistry));
return schema.transformWithoutTypes((builder) -> builder.codeRegistry(outputCodeRegistry));
}
/**
* Protected method to apply the
* {@link #configureGraphQl(Consumer) configured graphQlConfigurer}'s.
* Subclasses can use this to customize {@link GraphQL.Builder} further.
* @param builder the builder to be customized
* @since 1.2.5
*/
protected void applyGraphQlConfigurers(GraphQL.Builder builder) {

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.execution;
import java.util.List;
@@ -55,7 +56,6 @@ public interface BatchLoaderRegistry extends DataLoaderRegistrar {
* {@code @SchemaMapping} handler methods can transparenly locate and
* inject a {@code DataLoader<T>} argument based on the generic type
* {@code <T>}.
*
* @param keyType the type of keys that will be used as input
* @param valueType the type of value that will be returned as output
* @param <K> the key type
@@ -71,7 +71,6 @@ public interface BatchLoaderRegistry extends DataLoaderRegistrar {
* <p><strong>Note:</strong> when this method is used, the parameter name
* of a {@code DataLoader<T>} argument in a {@code @SchemaMapping} handler
* method needs to match the name given here.
*
* @param name the name to use to register a {@code DataLoader}
* @param <K> the type of keys that will be used as input
* @param <V> the type of values that will be used as output

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.execution;
import java.util.LinkedHashMap;

View File

@@ -38,44 +38,43 @@ import org.springframework.util.Assert;
*
* @author Mykyta Ivchenko
* @author Rossen Stoyanchev
* @since 1.0.1
*/
class CompositeSubscriptionExceptionResolver implements SubscriptionExceptionResolver {
private static final Log logger = LogFactory.getLog(CompositeSubscriptionExceptionResolver.class);
private static final Log logger = LogFactory.getLog(CompositeSubscriptionExceptionResolver.class);
private final List<SubscriptionExceptionResolver> resolvers;
private final List<SubscriptionExceptionResolver> resolvers;
CompositeSubscriptionExceptionResolver(List<SubscriptionExceptionResolver> resolvers) {
Assert.notNull(resolvers, "'resolvers' is required");
this.resolvers = resolvers;
}
CompositeSubscriptionExceptionResolver(List<SubscriptionExceptionResolver> resolvers) {
Assert.notNull(resolvers, "'resolvers' is required");
this.resolvers = resolvers;
}
@Override
public Mono<List<GraphQLError>> resolveException(Throwable exception) {
return Flux.fromIterable(this.resolvers)
.flatMap(resolver -> resolver.resolveException(exception))
.next()
.onErrorResume(error -> Mono.just(handleResolverException(error, exception)))
.defaultIfEmpty(createDefaultError());
}
@Override
public Mono<List<GraphQLError>> resolveException(Throwable exception) {
return Flux.fromIterable(this.resolvers)
.flatMap((resolver) -> resolver.resolveException(exception))
.next()
.onErrorResume((error) -> Mono.just(handleResolverException(error, exception)))
.defaultIfEmpty(createDefaultError());
}
private List<GraphQLError> handleResolverException(
Throwable resolverException, Throwable originalException) {
private List<GraphQLError> handleResolverException(
Throwable resolverException, Throwable originalException) {
if (logger.isWarnEnabled()) {
logger.warn("Failure while resolving " + originalException.getClass().getName(), resolverException);
}
return createDefaultError();
}
if (logger.isWarnEnabled()) {
logger.warn("Failure while resolving " + originalException.getClass().getName(), resolverException);
}
return createDefaultError();
}
private List<GraphQLError> createDefaultError() {
return Collections.singletonList(GraphqlErrorBuilder.newError()
.message("Subscription error")
.errorType(ErrorType.INTERNAL_ERROR)
.build());
}
private List<GraphQLError> createDefaultError() {
return Collections.singletonList(GraphqlErrorBuilder.newError()
.message("Subscription error")
.errorType(ErrorType.INTERNAL_ERROR)
.build());
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.execution;
import java.util.Collection;
@@ -67,7 +68,7 @@ public class ConnectionTypeDefinitionConfigurer implements TypeDefinitionConfigu
.fieldDefinition(initFieldDefinition("endCursor", STRING_TYPE))
.build());
typeNames.forEach(typeName -> {
typeNames.forEach((typeName) -> {
String connectionTypeName = typeName + "Connection";
String edgeTypeName = typeName + "Edge";
@@ -90,19 +91,19 @@ public class ConnectionTypeDefinitionConfigurer implements TypeDefinitionConfigu
return Stream.concat(
registry.types().values().stream(),
registry.objectTypeExtensions().values().stream().flatMap(Collection::stream))
.filter(definition -> definition instanceof ImplementingTypeDefinition)
.flatMap(definition -> {
.filter((definition) -> definition instanceof ImplementingTypeDefinition)
.flatMap((definition) -> {
ImplementingTypeDefinition<?> typeDefinition = (ImplementingTypeDefinition<?>) definition;
return typeDefinition.getFieldDefinitions().stream()
.map(fieldDefinition -> {
.map((fieldDefinition) -> {
Type<?> type = fieldDefinition.getType();
return (type instanceof NonNullType ? ((NonNullType) type).getType() : type);
return (type instanceof NonNullType) ? ((NonNullType) type).getType() : type;
})
.filter(type -> type instanceof TypeName)
.map(type -> ((TypeName) type).getName())
.filter(name -> name.endsWith("Connection"))
.filter(name -> registry.getType(name).isEmpty())
.map(name -> name.substring(0, name.length() - "Connection".length()));
.filter((type) -> type instanceof TypeName)
.map((type) -> ((TypeName) type).getName())
.filter((name) -> name.endsWith("Connection"))
.filter((name) -> registry.getType(name).isEmpty())
.map((name) -> name.substring(0, name.length() - "Connection".length()));
})
.collect(Collectors.toCollection(LinkedHashSet::new));
}

View File

@@ -88,13 +88,13 @@ final class ContextDataFetcherDecorator implements DataFetcher<Object> {
if (this.subscription) {
Assert.state(value instanceof Publisher, "Expected Publisher for a subscription");
Flux<?> flux = Flux.from((Publisher<?>) value).onErrorResume(exception -> {
Flux<?> flux = Flux.from((Publisher<?>) value).onErrorResume((exception) -> {
// Already handled, e.g. controller methods?
if (exception instanceof SubscriptionPublisherException) {
return Mono.error(exception);
}
return this.subscriptionExceptionResolver.resolveException(exception)
.flatMap(errors -> Mono.error(new SubscriptionPublisherException(errors, exception)));
.flatMap((errors) -> Mono.error(new SubscriptionPublisherException(errors, exception)));
});
return flux.contextWrite(snapshot::updateContext);
}
@@ -123,7 +123,7 @@ final class ContextDataFetcherDecorator implements DataFetcher<Object> {
/**
* Type visitor to apply {@link ContextDataFetcherDecorator}.
*/
private static class ContextTypeVisitor extends GraphQLTypeVisitorStub {
private static final class ContextTypeVisitor extends GraphQLTypeVisitorStub {
private final SubscriptionExceptionResolver exceptionResolver;
@@ -143,7 +143,7 @@ final class ContextDataFetcherDecorator implements DataFetcher<Object> {
if (applyDecorator(dataFetcher)) {
boolean handlesSubscription = visitorHelper.isSubscriptionType(parent);
dataFetcher = new ContextDataFetcherDecorator(dataFetcher, handlesSubscription, exceptionResolver);
dataFetcher = new ContextDataFetcherDecorator(dataFetcher, handlesSubscription, this.exceptionResolver);
codeRegistry.dataFetcher(parent, fieldDefinition, dataFetcher);
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.execution;
import java.util.Collections;
@@ -104,7 +105,7 @@ public abstract class DataFetcherExceptionResolverAdapter implements DataFetcher
.call();
}
catch (Exception ex2) {
logger.warn("Failed to resolve " + exception, ex2);
this.logger.warn("Failed to resolve " + exception, ex2);
return null;
}
}
@@ -118,7 +119,7 @@ public abstract class DataFetcherExceptionResolverAdapter implements DataFetcher
@Nullable
protected List<GraphQLError> resolveToMultipleErrors(Throwable ex, DataFetchingEnvironment env) {
GraphQLError error = resolveToSingleError(ex, env);
return (error != null ? Collections.singletonList(error) : null);
return (error != null) ? Collections.singletonList(error) : null;
}
/**
@@ -140,7 +141,7 @@ public abstract class DataFetcherExceptionResolverAdapter implements DataFetcher
* @return the created instance
* @deprecated as of 1.0.1, please use {@link DataFetcherExceptionResolver#forSingleError(BiFunction)}
*/
@Deprecated
@Deprecated(since = "1.0.1", forRemoval = true)
public static DataFetcherExceptionResolverAdapter from(
BiFunction<Throwable, DataFetchingEnvironment, GraphQLError> resolver) {

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.execution;
import graphql.ExecutionInput;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.execution;
import java.util.ArrayList;
@@ -52,9 +53,9 @@ import org.springframework.util.StringUtils;
*/
public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry {
private final List<ReactorBatchLoader<?,?>> loaders = new ArrayList<>();
private final List<ReactorBatchLoader<?, ?>> loaders = new ArrayList<>();
private final List<ReactorMappedBatchLoader<?,?>> mappedLoaders = new ArrayList<>();
private final List<ReactorMappedBatchLoader<?, ?>> mappedLoaders = new ArrayList<>();
private final Supplier<DataLoaderOptions> defaultOptionsSupplier;
@@ -69,6 +70,7 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry {
/**
* Constructor with a default {@link DataLoaderOptions} supplier to use as
* a starting point for batch loader registrations.
* @param defaultOptionsSupplier the supplier for data loader options
* @since 1.1.0
*/
public DefaultBatchLoaderRegistry(Supplier<DataLoaderOptions> defaultOptionsSupplier) {
@@ -126,11 +128,11 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry {
@Nullable
private Consumer<DataLoaderOptions> optionsConsumer;
public DefaultRegistrationSpec(Class<V> valueType) {
DefaultRegistrationSpec(Class<V> valueType) {
this.valueType = valueType;
}
public DefaultRegistrationSpec(String name) {
DefaultRegistrationSpec(String name) {
this.name = name;
this.valueType = null;
}
@@ -143,8 +145,8 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry {
@Override
public RegistrationSpec<K, V> withOptions(Consumer<DataLoaderOptions> optionsConsumer) {
this.optionsConsumer = (this.optionsConsumer != null ?
this.optionsConsumer.andThen(optionsConsumer) : optionsConsumer);
this.optionsConsumer = (this.optionsConsumer != null) ?
this.optionsConsumer.andThen(optionsConsumer) : optionsConsumer;
return this;
}
@@ -177,7 +179,7 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry {
private Supplier<DataLoaderOptions> initOptionsSupplier() {
Supplier<DataLoaderOptions> optionsSupplier = () ->
new DataLoaderOptions(this.options != null ?
new DataLoaderOptions((this.options != null) ?
this.options : DefaultBatchLoaderRegistry.this.defaultOptionsSupplier.get());
if (this.optionsConsumer == null) {
@@ -197,7 +199,7 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry {
* {@link BatchLoaderWithContext} that delegates to a {@link Flux} batch
* loading function and exposes Reactor context to it.
*/
private static class ReactorBatchLoader<K, V> implements BatchLoaderWithContext<K, V> {
private static final class ReactorBatchLoader<K, V> implements BatchLoaderWithContext<K, V> {
private final String name;
@@ -214,11 +216,11 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry {
this.optionsSupplier = optionsSupplier;
}
public String getName() {
String getName() {
return this.name;
}
public DataLoaderOptions getOptions() {
DataLoaderOptions getOptions() {
return this.optionsSupplier.get();
}
@@ -246,7 +248,7 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry {
* {@link MappedBatchLoaderWithContext} that delegates to a {@link Mono}
* batch loading function and exposes Reactor context to it.
*/
private static class ReactorMappedBatchLoader<K, V> implements MappedBatchLoaderWithContext<K, V> {
private static final class ReactorMappedBatchLoader<K, V> implements MappedBatchLoaderWithContext<K, V> {
private final String name;
@@ -263,11 +265,11 @@ public class DefaultBatchLoaderRegistry implements BatchLoaderRegistry {
this.optionsSupplier = optionsSupplier;
}
public String getName() {
String getName() {
return this.name;
}
public DataLoaderOptions getOptions() {
DataLoaderOptions getOptions() {
return this.optionsSupplier.get();
}

View File

@@ -97,7 +97,7 @@ public class DefaultExecutionGraphQlService implements ExecutionGraphQlService {
(this.hasDataLoaderRegistrations ? registerDataLoaders(executionInput) : executionInput);
return Mono.fromFuture(this.graphQlSource.graphQl().executeAsync(updatedExecutionInput))
.map(result -> new DefaultExecutionGraphQlResponse(updatedExecutionInput, result));
.map((result) -> new DefaultExecutionGraphQlResponse(updatedExecutionInput, result));
});
}
@@ -107,7 +107,7 @@ public class DefaultExecutionGraphQlService implements ExecutionGraphQlService {
if (existingRegistry == DataLoaderDispatcherInstrumentationState.EMPTY_DATALOADER_REGISTRY) {
DataLoaderRegistry newRegistry = DataLoaderRegistry.newRegistry().build();
applyDataLoaderRegistrars(newRegistry, graphQLContext);
executionInput = executionInput.transform(builder -> builder.dataLoaderRegistry(newRegistry));
executionInput = executionInput.transform((builder) -> builder.dataLoaderRegistry(newRegistry));
}
else {
applyDataLoaderRegistrars(existingRegistry, graphQLContext);
@@ -116,7 +116,7 @@ public class DefaultExecutionGraphQlService implements ExecutionGraphQlService {
}
private void applyDataLoaderRegistrars(DataLoaderRegistry registry, GraphQLContext graphQLContext) {
this.dataLoaderRegistrars.forEach(registrar -> registrar.registerDataLoaders(registry, graphQLContext));
this.dataLoaderRegistrars.forEach((registrar) -> registrar.registerDataLoaders(registry, graphQLContext));
}
}

Some files were not shown because too many files have changed in this diff Show More