From f5e710372b35a71b895356bfae66570cab47bea4 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Tue, 30 Aug 2022 08:51:15 +0100 Subject: [PATCH] Remove built-in ThreadLocalAccessor The ThreadLocalAccessor in 1.0 was intended as a temporary solution that is now replaced by a similar contract in the `io.micrometer:context-propagation` library. Unfortunately, there is no way to adapt one to the other, but it is trivial to implement the new contract and register it either with `ContextRegistry#getInstance` on startup or through the `ServiceLoader` mechanism. See gh-459 --- .../CompositeThreadLocalAccessor.java | 55 ------------- .../SecurityContextThreadLocalAccessor.java | 27 +------ .../execution/ThreadLocalAccessor.java | 80 ------------------- .../DefaultWebGraphQlHandlerBuilder.java | 38 --------- .../graphql/server/WebGraphQlHandler.java | 33 -------- .../springframework/graphql/GraphQlSetup.java | 13 --- .../graphql/server/WebGraphQlSetup.java | 4 - 7 files changed, 1 insertion(+), 249 deletions(-) delete mode 100644 spring-graphql/src/main/java/org/springframework/graphql/execution/CompositeThreadLocalAccessor.java delete mode 100644 spring-graphql/src/main/java/org/springframework/graphql/execution/ThreadLocalAccessor.java diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/CompositeThreadLocalAccessor.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/CompositeThreadLocalAccessor.java deleted file mode 100644 index a946968f..00000000 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/CompositeThreadLocalAccessor.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.graphql.execution; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - - -/** - * Default implementation of a composite accessor that is returned from - * {@link ThreadLocalAccessor#composite(List)}. - * - * @author Rossen Stoyanchev - * @since 1.0.0 - */ -@SuppressWarnings("deprecation") -class CompositeThreadLocalAccessor implements ThreadLocalAccessor { - - private final List accessors; - - CompositeThreadLocalAccessor(List accessors) { - this.accessors = new ArrayList<>(accessors); - } - - @Override - public void extractValues(Map container) { - this.accessors.forEach((accessor) -> accessor.extractValues(container)); - } - - @Override - public void restoreValues(Map values) { - this.accessors.forEach((accessor) -> accessor.restoreValues(values)); - } - - @Override - public void resetValues(Map values) { - this.accessors.forEach((accessor) -> accessor.resetValues(values)); - } - -} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityContextThreadLocalAccessor.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityContextThreadLocalAccessor.java index ade37e06..158238bc 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityContextThreadLocalAccessor.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityContextThreadLocalAccessor.java @@ -15,8 +15,6 @@ */ package org.springframework.graphql.execution; -import java.util.Map; - import io.micrometer.context.ThreadLocalAccessor; import org.springframework.security.core.context.SecurityContext; @@ -33,9 +31,7 @@ import org.springframework.util.ClassUtils; * @author Rossen Stoyanchev * @since 1.0.0 */ -@SuppressWarnings("deprecation") -public class SecurityContextThreadLocalAccessor implements ThreadLocalAccessor, - org.springframework.graphql.execution.ThreadLocalAccessor { +public class SecurityContextThreadLocalAccessor implements ThreadLocalAccessor { private final static boolean springSecurityPresent = ClassUtils.isPresent( "org.springframework.security.core.context.SecurityContext", @@ -81,27 +77,6 @@ public class SecurityContextThreadLocalAccessor implements ThreadLocalAccessor container) { - container.put((String) key(), SecurityContextHolder.getContext()); - } - - @Override - public void restoreValues(Map values) { - if (values.containsKey((String) key())) { - SecurityContextHolder.setContext((SecurityContext) values.get((String) key())); - } - } - - @Override - public void resetValues(Map values) { - SecurityContextHolder.clearContext(); - } - - private static class DelegateAccessor implements ThreadLocalAccessor { @Override diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/ThreadLocalAccessor.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/ThreadLocalAccessor.java deleted file mode 100644 index 8a66a864..00000000 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/ThreadLocalAccessor.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.graphql.execution; - -import java.util.List; -import java.util.Map; - -import org.springframework.beans.factory.ObjectProvider; - -/** - * Interface to be implemented to assist with the extraction of ThreadLocal - * values at the start of GraphQL request execution, e.g. in the web layer. - * Those values are saved in {@link graphql.ExecutionInput} and restored later - * around the invocation of data fetchers and exception resolvers which may be - * in a different thread. - * - *

Implementations of this interface are typically declared as beans in - * Spring configuration and are invoked in order as defined in - * {@link ObjectProvider#orderedStream()}. - * - *

Currently supported for GraphQL requests over HTTP and WebSocket in - * Spring MVC applications. - * - * @author Rossen Stoyanchev - * @since 1.0.0 - * @deprecated as of 1.1.0 in favor of using - * {@link io.micrometer.context.ThreadLocalAccessor} from the - * {@code "io.micrometer:context-propagation"} library. - * @see org.springframework.graphql.server.WebGraphQlHandler.Builder#threadLocalAccessor(ThreadLocalAccessor...) - */ -@Deprecated -public interface ThreadLocalAccessor { - - /** - * Extract ThreadLocal values and add them to the given Map, so they can be - * saved and subsequently {@link #restoreValues(Map) restored} around the - * invocation of data fetchers and exception resolvers. - * @param container to add extracted ThreadLocal values to - */ - void extractValues(Map container); - - /** - * Restore ThreadLocal context by looking up previously - * {@link #extractValues(Map) extracted} values. - * @param values previously extracted saved ThreadLocal values - */ - void restoreValues(Map values); - - /** - * Reset ThreadLocal context for the given, previously - * {@link #extractValues(Map) extracted} and then - * {@link #restoreValues(Map) restored} values. - * @param values previously extracted saved ThreadLocal values - */ - void resetValues(Map values); - - /** - * Create a composite accessor that applies all of the given ThreadLocal accessors. - * @param accessors the accessors to apply - * @return the composite accessor - */ - static ThreadLocalAccessor composite(List accessors) { - return new CompositeThreadLocalAccessor(accessors); - } - -} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/DefaultWebGraphQlHandlerBuilder.java b/spring-graphql/src/main/java/org/springframework/graphql/server/DefaultWebGraphQlHandlerBuilder.java index 68bfd146..cef049cd 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/DefaultWebGraphQlHandlerBuilder.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/DefaultWebGraphQlHandlerBuilder.java @@ -21,16 +21,12 @@ import java.util.Arrays; import java.util.List; import io.micrometer.context.ContextSnapshot; - -import org.springframework.graphql.execution.SecurityContextThreadLocalAccessor; -import org.springframework.graphql.execution.ThreadLocalAccessor; import reactor.core.publisher.Mono; import org.springframework.graphql.ExecutionGraphQlService; import org.springframework.graphql.server.WebGraphQlInterceptor.Chain; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import org.springframework.util.CollectionUtils; /** @@ -38,7 +34,6 @@ import org.springframework.util.CollectionUtils; * * @author Rossen Stoyanchev */ -@SuppressWarnings("deprecation") class DefaultWebGraphQlHandlerBuilder implements WebGraphQlHandler.Builder { private final ExecutionGraphQlService service; @@ -48,9 +43,6 @@ class DefaultWebGraphQlHandlerBuilder implements WebGraphQlHandler.Builder { @Nullable private WebSocketGraphQlInterceptor webSocketInterceptor; - @Nullable - private List accessors; - DefaultWebGraphQlHandlerBuilder(ExecutionGraphQlService service) { Assert.notNull(service, "GraphQlService is required"); @@ -75,30 +67,6 @@ class DefaultWebGraphQlHandlerBuilder implements WebGraphQlHandler.Builder { return this; } - @SuppressWarnings("deprecation") - @Override - public WebGraphQlHandler.Builder threadLocalAccessor(ThreadLocalAccessor... accessors) { - return threadLocalAccessors(Arrays.asList(accessors)); - } - - @SuppressWarnings("deprecation") - @Override - public WebGraphQlHandler.Builder threadLocalAccessors(List accessors) { - - // Filter out SecurityContextThreadLocalAccessor which is registered as a ThreadLocalAccessor - // from the micrometer-metrics/context-propagatation library. This code can be removed when - // SecurityContextThreadLocalAccessor no longer implements the deprecated ThreadLocalAccessor. - accessors = accessors.stream() - .filter(a -> !(a instanceof SecurityContextThreadLocalAccessor)) - .toList(); - - if (!CollectionUtils.isEmpty(accessors)) { - this.accessors = (this.accessors != null) ? this.accessors : new ArrayList<>(); - this.accessors.addAll(accessors); - } - return this; - } - @Override public WebGraphQlHandler build() { @@ -117,12 +85,6 @@ class DefaultWebGraphQlHandlerBuilder implements WebGraphQlHandler.Builder { webSocketInterceptor : new WebSocketGraphQlInterceptor() {}); } - @Nullable - @Override - public ThreadLocalAccessor getThreadLocalAccessor() { - return (CollectionUtils.isEmpty(accessors) ? null : ThreadLocalAccessor.composite(accessors)); - } - @Override public Mono handleRequest(WebGraphQlRequest request) { ContextSnapshot snapshot = ContextSnapshot.capture(); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/WebGraphQlHandler.java b/spring-graphql/src/main/java/org/springframework/graphql/server/WebGraphQlHandler.java index a3a7e9e1..fbdfaf85 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/WebGraphQlHandler.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/WebGraphQlHandler.java @@ -21,8 +21,6 @@ import java.util.List; import reactor.core.publisher.Mono; import org.springframework.graphql.ExecutionGraphQlService; -import org.springframework.graphql.execution.ThreadLocalAccessor; -import org.springframework.lang.Nullable; /** @@ -41,15 +39,6 @@ public interface WebGraphQlHandler { */ WebSocketGraphQlInterceptor getWebSocketInterceptor(); - /** - * Return the composite {@link ThreadLocalAccessor} that the handler is - * configured with. - * @deprecated as of 1.1.0, together with {@link ThreadLocalAccessor}. - */ - @Deprecated - @Nullable - ThreadLocalAccessor getThreadLocalAccessor(); - /** * Execute the given request and return the response. * @param request the request to execute @@ -97,28 +86,6 @@ public interface WebGraphQlHandler { */ Builder interceptors(List interceptors); - /** - * Configure accessors for ThreadLocal variables to use to extract - * ThreadLocal values at the start of GraphQL execution in the web layer, - * and have those saved, and restored around the invocation of data - * fetchers and exception resolvers. - * @param accessors the accessors to add - * @return this builder - * @deprecated as of 1.1.0 together with {@link ThreadLocalAccessor}. - */ - @Deprecated - Builder threadLocalAccessor(ThreadLocalAccessor... accessors); - - /** - * Alternative to {@link #threadLocalAccessor(ThreadLocalAccessor...)} with a - * List. - * @param accessors the list of accessors to add - * @return this builder - * @deprecated as of 1.1.0 together with {@link ThreadLocalAccessor}. - */ - @Deprecated - Builder threadLocalAccessors(List accessors); - /** * Build the {@link WebGraphQlHandler} instance. * @return the built WebGraphQlHandler diff --git a/spring-graphql/src/testFixtures/java/org/springframework/graphql/GraphQlSetup.java b/spring-graphql/src/testFixtures/java/org/springframework/graphql/GraphQlSetup.java index 7df4c787..7f30b8de 100644 --- a/spring-graphql/src/testFixtures/java/org/springframework/graphql/GraphQlSetup.java +++ b/spring-graphql/src/testFixtures/java/org/springframework/graphql/GraphQlSetup.java @@ -35,12 +35,10 @@ import org.springframework.graphql.execution.DefaultExecutionGraphQlService; import org.springframework.graphql.execution.GraphQlSource; import org.springframework.graphql.execution.RuntimeWiringConfigurer; import org.springframework.graphql.execution.SubscriptionExceptionResolver; -import org.springframework.graphql.execution.ThreadLocalAccessor; import org.springframework.graphql.server.WebGraphQlHandler; import org.springframework.graphql.server.WebGraphQlInterceptor; import org.springframework.graphql.server.WebGraphQlSetup; import org.springframework.graphql.server.webflux.GraphQlHttpHandler; -import org.springframework.lang.Nullable; /** * Workflow for GraphQL tests setup that starts with {@link GraphQlSource.Builder} @@ -58,8 +56,6 @@ public class GraphQlSetup implements GraphQlServiceSetup { private final List interceptors = new ArrayList<>(); - private final List accessors = new ArrayList<>(); - private GraphQlSetup(Resource... schemaResources) { this.graphQlSourceBuilder = GraphQlSource.schemaResourceBuilder().schemaResources(schemaResources); @@ -147,19 +143,10 @@ public class GraphQlSetup implements GraphQlServiceSetup { return this; } - @Override - public WebGraphQlSetup threadLocalAccessor(@Nullable ThreadLocalAccessor accessor) { - if (accessor != null) { - this.accessors.add(accessor); - } - return this; - } - public WebGraphQlHandler toWebGraphQlHandler() { ExecutionGraphQlService service = toGraphQlService(); return WebGraphQlHandler.builder(service) .interceptors(this.interceptors) - .threadLocalAccessors(this.accessors) .build(); } diff --git a/spring-graphql/src/testFixtures/java/org/springframework/graphql/server/WebGraphQlSetup.java b/spring-graphql/src/testFixtures/java/org/springframework/graphql/server/WebGraphQlSetup.java index 5f198252..8073683a 100644 --- a/spring-graphql/src/testFixtures/java/org/springframework/graphql/server/WebGraphQlSetup.java +++ b/spring-graphql/src/testFixtures/java/org/springframework/graphql/server/WebGraphQlSetup.java @@ -15,9 +15,7 @@ */ package org.springframework.graphql.server; -import org.springframework.graphql.execution.ThreadLocalAccessor; import org.springframework.graphql.server.webflux.GraphQlHttpHandler; -import org.springframework.lang.Nullable; /** * Workflow that results in the creation of a {@link WebGraphQlHandler} or @@ -29,8 +27,6 @@ public interface WebGraphQlSetup { WebGraphQlSetup interceptor(WebGraphQlInterceptor... interceptors); - WebGraphQlSetup threadLocalAccessor(@Nullable ThreadLocalAccessor accessor); - WebGraphQlHandler toWebGraphQlHandler(); org.springframework.graphql.server.webmvc.GraphQlHttpHandler toHttpHandler();