Skip to content

Commit 9f77f40

Browse files
committed
Complete Propagator.Getter implementation
As of Micrometer Tracing 1.6.0, the `Propagator.Getter` interface adds a new `getAll` method with a default implementation return a singleton collection. This commit adds the missing implementation override in both Servlet and Reactor web server contexts. Fixes gh-35965
1 parent f19f1a6 commit 9f77f40

File tree

4 files changed

+125
-2
lines changed

4 files changed

+125
-2
lines changed

spring-web/src/main/java/org/springframework/http/server/observation/ServerRequestObservationContext.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package org.springframework.http.server.observation;
1818

19+
import java.util.Collections;
20+
21+
import io.micrometer.observation.transport.Propagator;
1922
import io.micrometer.observation.transport.RequestReplyReceiverContext;
2023
import jakarta.servlet.http.HttpServletRequest;
2124
import jakarta.servlet.http.HttpServletResponse;
@@ -32,10 +35,12 @@
3235
*/
3336
public class ServerRequestObservationContext extends RequestReplyReceiverContext<HttpServletRequest, HttpServletResponse> {
3437

38+
private static final HeaderGetter GETTER = new HeaderGetter();
39+
3540
private @Nullable String pathPattern;
3641

3742
public ServerRequestObservationContext(HttpServletRequest request, HttpServletResponse response) {
38-
super(HttpServletRequest::getHeader);
43+
super(GETTER);
3944
setCarrier(request);
4045
setResponse(response);
4146
}
@@ -47,4 +52,17 @@ public ServerRequestObservationContext(HttpServletRequest request, HttpServletRe
4752
public void setPathPattern(@Nullable String pathPattern) {
4853
this.pathPattern = pathPattern;
4954
}
55+
56+
static final class HeaderGetter implements Propagator.Getter<HttpServletRequest> {
57+
@Override
58+
public String get(HttpServletRequest carrier, String key) {
59+
return carrier.getHeader(key);
60+
}
61+
62+
@Override
63+
public Iterable<String> getAll(HttpServletRequest carrier, String key) {
64+
return Collections.list(carrier.getHeaders(key));
65+
}
66+
}
67+
5068
}

spring-web/src/main/java/org/springframework/http/server/reactive/observation/ServerRequestObservationContext.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Map;
2121
import java.util.Optional;
2222

23+
import io.micrometer.observation.transport.Propagator;
2324
import io.micrometer.observation.transport.RequestReplyReceiverContext;
2425
import org.jspecify.annotations.Nullable;
2526

@@ -46,6 +47,7 @@ public class ServerRequestObservationContext extends RequestReplyReceiverContext
4647
*/
4748
public static final String CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE = ServerRequestObservationContext.class.getName();
4849

50+
private static final HeaderGetter GETTER = new HeaderGetter();
4951

5052
private final Map<String, Object> attributes;
5153

@@ -63,7 +65,7 @@ public class ServerRequestObservationContext extends RequestReplyReceiverContext
6365
public ServerRequestObservationContext(
6466
ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> attributes) {
6567

66-
super((req, key) -> req.getHeaders().getFirst(key));
68+
super(GETTER);
6769
setCarrier(request);
6870
setResponse(response);
6971
this.attributes = Collections.unmodifiableMap(attributes);
@@ -129,4 +131,17 @@ public static Optional<ServerRequestObservationContext> findCurrent(Map<String,
129131
(ServerRequestObservationContext) attributes.get(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE));
130132
}
131133

134+
static final class HeaderGetter implements Propagator.Getter<ServerHttpRequest> {
135+
136+
@Override
137+
public @Nullable String get(ServerHttpRequest carrier, String key) {
138+
return carrier.getHeaders().getFirst(key);
139+
}
140+
141+
@Override
142+
public Iterable<String> getAll(ServerHttpRequest carrier, String key) {
143+
return carrier.getHeaders().getOrEmpty(key);
144+
}
145+
}
146+
132147
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2025-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.http.server.observation;
18+
19+
20+
import java.util.List;
21+
22+
import org.junit.jupiter.api.Test;
23+
24+
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
25+
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
26+
27+
import static org.assertj.core.api.Assertions.assertThat;
28+
29+
/**
30+
* Tests for {@link ServerRequestObservationContext}.
31+
*/
32+
class ServerRequestObservationContextTests {
33+
34+
private MockHttpServletRequest request = new MockHttpServletRequest();
35+
36+
private MockHttpServletResponse response = new MockHttpServletResponse();
37+
38+
private ServerRequestObservationContext context = new ServerRequestObservationContext(request, response);
39+
40+
@Test
41+
void shouldGetMultipleHeaderValues() {
42+
request.addHeader("test", List.of("spring", "framework"));
43+
assertThat(context.getGetter().getAll(request, "test")).contains("spring", "framework");
44+
}
45+
46+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2025-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.http.server.reactive.observation;
18+
19+
import java.util.Map;
20+
21+
import org.junit.jupiter.api.Test;
22+
23+
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
24+
import org.springframework.web.testfixture.server.MockServerWebExchange;
25+
26+
import static org.assertj.core.api.Assertions.assertThat;
27+
28+
/**
29+
* Tests for {@link ServerRequestObservationContext}.
30+
*/
31+
class ServerRequestObservationContextTests {
32+
33+
34+
@Test
35+
void shouldGetMultipleHeaderValues() {
36+
MockServerHttpRequest request = MockServerHttpRequest.get("/")
37+
.header("test", "spring", "framework").build();
38+
MockServerWebExchange exchange = MockServerWebExchange.builder(request).build();
39+
40+
ServerRequestObservationContext context = new ServerRequestObservationContext(request, exchange.getResponse(), Map.of());
41+
assertThat(context.getGetter().getAll(request, "test")).contains("spring", "framework");
42+
}
43+
44+
}

0 commit comments

Comments
 (0)