Skip to content

Commit

Permalink
Replace HttpAttributes with accessors (#11324)
Browse files Browse the repository at this point in the history
* Replace HttpAttributes with accessors
Attributes are a suboptimal way of adding metadata to requests and responses, both because they need a string lookup, and because they require conversion.

* migrate service id from #11309

* add since to deprecations

* spotless

* fix type pollution

* fix sonar

* merge

* checkstyle
  • Loading branch information
yawkat authored Jan 24, 2025
1 parent 7fe5f25 commit 466bfe1
Show file tree
Hide file tree
Showing 47 changed files with 511 additions and 132 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2017-2025 original 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 io.micronaut.http.client;

import io.micronaut.aop.MethodInvocationContext;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.http.HttpAttributes;
import io.micronaut.http.HttpRequest;

import java.util.Optional;

/**
* Client-related attribute accessors.
*
* @author Jonas Konrad
* @since 4.8.0
*/
@SuppressWarnings("removal")
public final class ClientAttributes {
private ClientAttributes() {
}

/**
* Set the client service ID.
*
* @param request The request
* @param serviceId The client service ID
* @see io.micronaut.http.BasicHttpAttributes#getServiceId(HttpRequest)
*/
public static void setServiceId(@NonNull HttpRequest<?> request, @NonNull String serviceId) {
request.setAttribute(HttpAttributes.SERVICE_ID, serviceId);
}

/**
* Get the invocation context.
*
* @param request The request
* @return The invocation context, if present
*/
@SuppressWarnings({"unchecked", "rawtypes"})
@NonNull
public static Optional<MethodInvocationContext<?, ?>> getInvocationContext(@NonNull HttpRequest<?> request) {
return (Optional) request.getAttribute(HttpAttributes.INVOCATION_CONTEXT, MethodInvocationContext.class);
}

/**
* Set the invocation context.
*
* @param request The request
* @param invocationContext The invocation context
*/
public static void setInvocationContext(@NonNull HttpRequest<?> request, @NonNull MethodInvocationContext<?, ?> invocationContext) {
request.setAttribute(HttpAttributes.INVOCATION_CONTEXT, invocationContext);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.core.util.StringUtils;
import io.micronaut.core.version.annotation.Version;
import io.micronaut.http.HttpAttributes;
import io.micronaut.http.BasicHttpAttributes;
import io.micronaut.http.HttpHeaders;
import io.micronaut.http.HttpMethod;
import io.micronaut.http.HttpRequest;
Expand All @@ -56,6 +56,7 @@
import io.micronaut.http.annotation.HttpMethodMapping;
import io.micronaut.http.annotation.Produces;
import io.micronaut.http.client.BlockingHttpClient;
import io.micronaut.http.client.ClientAttributes;
import io.micronaut.http.client.HttpClient;
import io.micronaut.http.client.HttpClientRegistry;
import io.micronaut.http.client.ReactiveClientResultTransformer;
Expand Down Expand Up @@ -435,9 +436,9 @@ private RequestBinderResult bindRequest(MethodInvocationContext<Object, Object>
}
}

request.setAttribute(HttpAttributes.INVOCATION_CONTEXT, context);
ClientAttributes.setInvocationContext(request, context);
// Set the URI template used to make the request for tracing purposes
request.setAttribute(HttpAttributes.URI_TEMPLATE, resolveTemplate(annotationMetadata, uriTemplate.toString()));
BasicHttpAttributes.setUriTemplate(request, resolveTemplate(annotationMetadata, uriTemplate.toString()));

return RequestBinderResult.withRequest(request);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@
import io.micronaut.core.propagation.PropagatedContext;
import io.micronaut.core.type.Argument;
import io.micronaut.core.util.StringUtils;
import io.micronaut.http.HttpAttributes;
import io.micronaut.http.BasicHttpAttributes;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.HttpStatus;
import io.micronaut.http.MutableHttpRequest;
import io.micronaut.http.bind.RequestBinderRegistry;
import io.micronaut.http.body.MessageBodyHandlerRegistry;
import io.micronaut.http.client.ClientAttributes;
import io.micronaut.http.client.HttpClientConfiguration;
import io.micronaut.http.client.HttpVersionSelection;
import io.micronaut.http.client.LoadBalancer;
Expand Down Expand Up @@ -431,8 +432,8 @@ protected <O> Publisher<io.micronaut.http.HttpResponse<O>> responsePublisher(
@NonNull io.micronaut.http.HttpRequest<?> request,
@Nullable Argument<O> bodyType
) {
if (clientId != null && request.getAttribute(HttpAttributes.SERVICE_ID).isEmpty()) {
request.setAttribute(HttpAttributes.SERVICE_ID, clientId);
if (clientId != null && BasicHttpAttributes.getServiceId(request).isEmpty()) {
ClientAttributes.setServiceId(request, clientId);
}

return Flux.defer(() -> mapToHttpRequest(request, bodyType)) // defered so any client filter changes are used
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import spock.lang.Specification
@Property(name = "micronaut.server.http-version", value = "HTTP_2_0")
@Property(name = "micronaut.server.ssl.build-self-signed", value = "true")
@Property(name = "micronaut.server.ssl.enabled", value = "true")
@Property(name = "micronaut.server.ssl.port", value = "0")
@Property(name = "micronaut.http.client.ssl.insecure-trust-all-certificates", value = "true")
@Property(name = "micronaut.server.max-request-size", value = "16384")
class Http2Spec extends Specification {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import io.micronaut.context.ApplicationContext
import io.micronaut.context.annotation.Requires
import io.micronaut.core.type.Argument
import io.micronaut.core.util.StringUtils
import io.micronaut.http.HttpAttributes
import io.micronaut.http.BasicHttpAttributes
import io.micronaut.http.HttpHeaders
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
Expand All @@ -18,9 +18,9 @@ import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.http.filter.HttpServerFilter
import io.micronaut.http.filter.ServerFilterChain
import io.micronaut.runtime.server.EmbeddedServer
import io.micronaut.web.router.RouteAttributes
import jakarta.inject.Singleton
import org.reactivestreams.Publisher
import org.spockframework.util.Assert
import spock.lang.Specification

class OptionsRequestAttributesSpec extends Specification {
Expand Down Expand Up @@ -98,9 +98,9 @@ class OptionsRequestAttributesSpec extends Specification {

@Override
Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
containsRouteMatch = request.getAttributes().contains(HttpAttributes.ROUTE_MATCH.toString())
containsRouteInfo = request.getAttributes().contains(HttpAttributes.ROUTE_INFO.toString())
containsUriTemplate = request.getAttributes().contains(HttpAttributes.URI_TEMPLATE.toString())
containsRouteMatch = RouteAttributes.getRouteMatch(request).isPresent()
containsRouteInfo = RouteAttributes.getRouteInfo(request).isPresent()
containsUriTemplate = BasicHttpAttributes.getUriTemplate(request).isPresent()
return chain.proceed(request)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package io.micronaut.http.client.jdk

import io.micronaut.context.ApplicationContext
import io.micronaut.context.annotation.Requires
import io.micronaut.http.HttpAttributes
import io.micronaut.http.BasicHttpAttributes
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
import io.micronaut.http.HttpVersion
Expand Down Expand Up @@ -80,7 +80,7 @@ class ServiceIdSpec extends Specification {

@Override
Publisher<? extends HttpResponse<?>> doFilter(MutableHttpRequest<?> request, ClientFilterChain chain) {
serviceId = request.getAttribute(HttpAttributes.SERVICE_ID).orElse(null)
serviceId = BasicHttpAttributes.getServiceId(request).orElse(null)
return chain.proceed(request)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
import io.micronaut.core.util.ObjectUtils;
import io.micronaut.core.util.StringUtils;
import io.micronaut.core.util.functional.ThrowingFunction;
import io.micronaut.http.HttpAttributes;
import io.micronaut.http.BasicHttpAttributes;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.HttpResponseWrapper;
import io.micronaut.http.HttpStatus;
Expand All @@ -60,6 +60,7 @@
import io.micronaut.http.body.MessageBodyReader;
import io.micronaut.http.body.stream.BodySizeLimits;
import io.micronaut.http.client.BlockingHttpClient;
import io.micronaut.http.client.ClientAttributes;
import io.micronaut.http.client.DefaultHttpClientConfiguration;
import io.micronaut.http.client.HttpClient;
import io.micronaut.http.client.HttpClientConfiguration;
Expand Down Expand Up @@ -1527,8 +1528,8 @@ private ExecutionFlow<HttpResponse<?>> sendRequestWithRedirects(
MutableHttpRequest<?> request,
BiFunction<MutableHttpRequest<?>, NettyClientByteBodyResponse, ? extends ExecutionFlow<? extends HttpResponse<?>>> readResponse
) {
if (informationalServiceId != null && request.getAttribute(HttpAttributes.SERVICE_ID).isEmpty()) {
request.setAttribute(HttpAttributes.SERVICE_ID, informationalServiceId);
if (informationalServiceId != null && BasicHttpAttributes.getServiceId(request).isEmpty()) {
ClientAttributes.setServiceId(request, informationalServiceId);
}

List<GenericHttpFilter> filters =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package io.micronaut.http.client

import io.micronaut.context.ApplicationContext
import io.micronaut.context.annotation.Requires
import io.micronaut.http.HttpAttributes
import io.micronaut.http.BasicHttpAttributes
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
import io.micronaut.http.HttpVersion
Expand Down Expand Up @@ -79,7 +79,7 @@ class ServiceIdSpec extends Specification {

@Override
Publisher<? extends HttpResponse<?>> doFilter(MutableHttpRequest<?> request, ClientFilterChain chain) {
serviceId = request.getAttribute(HttpAttributes.SERVICE_ID).orElse(null)
serviceId = BasicHttpAttributes.getServiceId(request).orElse(null)
return chain.proceed(request)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import io.micronaut.context.annotation.Property
import io.micronaut.context.annotation.Requires
import io.micronaut.http.HttpRequest
import io.micronaut.http.MediaType
import io.micronaut.http.annotation.*
import io.micronaut.http.annotation.Body
import io.micronaut.http.annotation.Consumes
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.annotation.Post
import io.micronaut.http.annotation.Produces
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.HttpVersionSelection
import io.micronaut.http.client.annotation.Client
Expand All @@ -17,6 +22,7 @@ import spock.lang.Specification
@Property(name = "micronaut.server.http-version", value = "HTTP_2_0")
@Property(name = "micronaut.server.ssl.build-self-signed", value = "true")
@Property(name = "micronaut.server.ssl.enabled", value = "true")
@Property(name = "micronaut.server.ssl.port", value = "0")
@Property(name = "micronaut.http.client.ssl.insecure-trust-all-certificates", value = "true")
@Property(name = "micronaut.server.max-request-size", value = "16384")
class Http2Spec extends Specification {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import io.micronaut.http.server.netty.handler.Http2ServerHandler;
import io.micronaut.http.server.netty.multipart.NettyCompletedFileUpload;
import io.micronaut.web.router.DefaultUriRouteMatch;
import io.micronaut.web.router.RouteAttributes;
import io.micronaut.web.router.RouteMatch;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
Expand Down Expand Up @@ -226,7 +227,7 @@ public ExecutionFlow<?> getRouteWaitsFor() {
public FormRouteCompleter formRouteCompleter() {
assert isFormOrMultipartData();
if (formRouteCompleter == null) {
formRouteCompleter = new FormRouteCompleter((RouteMatch<?>) getAttribute(HttpAttributes.ROUTE_MATCH).get(), getChannelHandlerContext().channel().eventLoop());
formRouteCompleter = new FormRouteCompleter(RouteAttributes.getRouteMatch(this).get(), getChannelHandlerContext().channel().eventLoop());
}
return formRouteCompleter;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import io.micronaut.core.io.buffer.ByteBuffer;
import io.micronaut.core.io.buffer.ReferenceCounted;
import io.micronaut.core.propagation.PropagatedContext;
import io.micronaut.http.HttpAttributes;
import io.micronaut.http.HttpHeaders;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.MediaType;
Expand All @@ -39,13 +38,14 @@
import io.micronaut.http.body.MessageBodyReader;
import io.micronaut.http.codec.CodecException;
import io.micronaut.http.context.ServerHttpRequestContext;
import io.micronaut.http.netty.body.AvailableNettyByteBody;
import io.micronaut.http.server.netty.FormDataHttpContentProcessor;
import io.micronaut.http.server.netty.FormRouteCompleter;
import io.micronaut.http.server.netty.MicronautHttpData;
import io.micronaut.http.server.netty.NettyHttpRequest;
import io.micronaut.http.netty.body.AvailableNettyByteBody;
import io.micronaut.http.server.netty.configuration.NettyHttpServerConfiguration;
import io.micronaut.http.server.netty.converters.NettyConverters;
import io.micronaut.web.router.RouteAttributes;
import io.micronaut.web.router.RouteInfo;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
Expand Down Expand Up @@ -149,7 +149,7 @@ public List<ConversionError> getConversionErrors() {

Optional<T> transform(NettyHttpRequest<?> nhr, ArgumentConversionContext<T> context, AvailableByteBody imm) throws Throwable {
MessageBodyReader<T> reader = null;
final RouteInfo<?> routeInfo = nhr.getAttribute(HttpAttributes.ROUTE_INFO, RouteInfo.class).orElse(null);
final RouteInfo<?> routeInfo = RouteAttributes.getRouteInfo(nhr).orElse(null);
if (routeInfo != null) {
reader = (MessageBodyReader<T>) routeInfo.getMessageBodyReader();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import io.micronaut.inject.MethodExecutionHandle;
import io.micronaut.scheduling.executor.ExecutorSelector;
import io.micronaut.scheduling.executor.ThreadSelection;
import io.micronaut.web.router.RouteAttributes;
import io.micronaut.web.router.UriRouteMatch;
import io.micronaut.websocket.CloseReason;
import io.micronaut.websocket.WebSocketPongMessage;
Expand Down Expand Up @@ -182,7 +183,7 @@ public class NettyServerWebSocketHandler extends AbstractNettyWebSocketHandler {

this.nettyEmbeddedServices = nettyEmbeddedServices;
this.coroutineHelper = coroutineHelper;
request.setAttribute(HttpAttributes.ROUTE_MATCH, routeMatch);
RouteAttributes.setRouteMatch(request, routeMatch);

Flux.from(callOpenMethod(ctx)).subscribe(v -> { }, t -> {
forwardErrorToUser(ctx, e -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import io.micronaut.core.execution.ExecutionFlow;
import io.micronaut.core.propagation.PropagatedContext;
import io.micronaut.core.util.StringUtils;
import io.micronaut.http.HttpAttributes;
import io.micronaut.http.HttpMethod;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
Expand All @@ -43,6 +42,7 @@
import io.micronaut.http.server.netty.configuration.NettyHttpServerConfiguration;
import io.micronaut.http.server.netty.handler.OutboundAccess;
import io.micronaut.http.server.netty.handler.RequestHandler;
import io.micronaut.web.router.RouteAttributes;
import io.micronaut.web.router.RouteMatch;
import io.micronaut.web.router.Router;
import io.micronaut.web.router.UriRouteMatch;
Expand Down Expand Up @@ -180,7 +180,8 @@ private void writeResponse(ChannelHandlerContext ctx,
}

if (shouldProceedNormally) {
UriRouteMatch<Object, Object> routeMatch = actualResponse.getAttribute(HttpAttributes.ROUTE_MATCH, UriRouteMatch.class)
UriRouteMatch<Object, Object> routeMatch = RouteAttributes.getRouteMatch(actualResponse)
.map(rm -> (UriRouteMatch<Object, Object>) rm)
.orElseThrow(() -> new IllegalStateException("Route match is required!"));
//Adding new handler to the existing pipeline to handle WebSocket Messages
WebSocketBean<?> webSocketBean = webSocketBeanRegistry.getWebSocket(routeMatch.getTarget().getClass());
Expand Down Expand Up @@ -306,10 +307,10 @@ ExecutionFlow<HttpResponse<?>> handle(HttpRequest<?> request) {
MutableHttpResponse<?> proceed = HttpResponse.ok();

if (route != null) {
request.setAttribute(HttpAttributes.ROUTE_MATCH, route);
request.setAttribute(HttpAttributes.ROUTE_INFO, route);
proceed.setAttribute(HttpAttributes.ROUTE_MATCH, route);
proceed.setAttribute(HttpAttributes.ROUTE_INFO, route);
RouteAttributes.setRouteMatch(request, route);
RouteAttributes.setRouteInfo(request, route.getRouteInfo());
RouteAttributes.setRouteMatch(proceed, route);
RouteAttributes.setRouteInfo(proceed, route.getRouteInfo());
}

ExecutionFlow<HttpResponse<?>> response;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import io.micronaut.context.ApplicationContext
import io.micronaut.context.annotation.Requires
import io.micronaut.core.type.Argument
import io.micronaut.core.util.StringUtils
import io.micronaut.http.HttpAttributes
import io.micronaut.http.BasicHttpAttributes
import io.micronaut.http.HttpHeaders
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
Expand All @@ -18,9 +18,9 @@ import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.http.filter.HttpServerFilter
import io.micronaut.http.filter.ServerFilterChain
import io.micronaut.runtime.server.EmbeddedServer
import io.micronaut.web.router.RouteAttributes
import jakarta.inject.Singleton
import org.reactivestreams.Publisher
import org.spockframework.util.Assert
import spock.lang.Specification

class OptionsRequestAttributesSpec extends Specification {
Expand Down Expand Up @@ -97,9 +97,9 @@ class OptionsRequestAttributesSpec extends Specification {

@Override
Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
containsRouteMatch = request.getAttributes().contains(HttpAttributes.ROUTE_MATCH.toString())
containsRouteInfo = request.getAttributes().contains(HttpAttributes.ROUTE_INFO.toString())
containsUriTemplate = request.getAttributes().contains(HttpAttributes.URI_TEMPLATE.toString())
containsRouteMatch = RouteAttributes.getRouteMatch(request).isPresent()
containsRouteInfo = RouteAttributes.getRouteInfo(request).isPresent()
containsUriTemplate = BasicHttpAttributes.getUriTemplate(request).isPresent()
return chain.proceed(request)
}
}
Expand Down
Loading

0 comments on commit 466bfe1

Please sign in to comment.