Skip to content

Commit 065bedc

Browse files
Addressing PR review
Signed-off-by: chickenchickenlove <ojt90902@naver.com>
1 parent 019efb7 commit 065bedc

File tree

7 files changed

+609
-238
lines changed

7 files changed

+609
-238
lines changed

spring-kafka/src/main/java/org/springframework/kafka/support/AbstractKafkaHeaderMapper.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ public abstract class AbstractKafkaHeaderMapper implements KafkaHeaderMapper {
6565

6666
private final List<HeaderMatcher> matchers = new ArrayList<>();
6767

68+
private final List<HeaderMatcher> headerMatchersForMultiValue = new ArrayList<>();
69+
6870
private final Map<String, Boolean> rawMappedHeaders = new HashMap<>();
6971

7072
{
@@ -191,6 +193,16 @@ public void addRawMappedHeader(String name, boolean toString) {
191193
this.rawMappedHeaders.put(name, toString);
192194
}
193195

196+
/**
197+
* Add patterns for matching multi-value headers under the same key.
198+
* @param patterns the patterns for header.
199+
*/
200+
public void addHeaderPatternsForMultiValue(String ... patterns) {
201+
for (String pattern : patterns) {
202+
this.headerMatchersForMultiValue.add(new SimplePatternBasedHeaderMatcher(pattern));
203+
}
204+
}
205+
194206
protected boolean matches(String header, Object value) {
195207
if (matches(header)) {
196208
if ((header.equals(MessageHeaders.REPLY_CHANNEL) || header.equals(MessageHeaders.ERROR_CHANNEL))
@@ -251,6 +263,20 @@ protected Object headerValueToAddOut(String key, Object value) {
251263
return valueToAdd;
252264
}
253265

266+
/**
267+
* Check whether the header value should be mapped to multiple values.
268+
* @param headerName the header name.
269+
* @return True for multiple values at the same key.
270+
*/
271+
protected boolean doesMatchMultiValueHeader(String headerName) {
272+
for (HeaderMatcher headerMatcher : this.headerMatchersForMultiValue) {
273+
if (headerMatcher.matchHeader(headerName)) {
274+
return true;
275+
}
276+
}
277+
return false;
278+
}
279+
254280
@SuppressWarnings("NullAway") // Dataflow analysis limitation
255281
@Nullable
256282
private byte[] mapRawOut(String header, Object value) {

spring-kafka/src/main/java/org/springframework/kafka/support/DefaultKafkaHeaderMapper.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2025 the original author or authors.
2+
* Copyright 2017-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
1919
import java.io.IOException;
2020
import java.nio.ByteBuffer;
2121
import java.nio.charset.StandardCharsets;
22+
import java.util.ArrayList;
2223
import java.util.Arrays;
2324
import java.util.Collections;
2425
import java.util.HashMap;
@@ -338,9 +339,22 @@ else if (!(headerName.equals(JSON_TYPES)) && matchesForInbound(headerName)) {
338339
* @param headers the target headers.
339340
* @since 4.0.0
340341
*/
341-
342342
protected void handleHeader(String headerName, Header header, final Map<String, Object> headers) {
343-
headers.put(headerName, headerValueToAddIn(header));
343+
if (!this.doesMatchMultiValueHeader(headerName)) {
344+
headers.put(headerName, headerValueToAddIn(header));
345+
}
346+
else {
347+
Object values = headers.getOrDefault(headerName, new ArrayList<>());
348+
if (values instanceof List) {
349+
@SuppressWarnings("unchecked")
350+
List<Object> castedValues = (List<Object>) values;
351+
castedValues.add(headerValueToAddIn(header));
352+
headers.put(headerName, castedValues);
353+
}
354+
else {
355+
headers.put(headerName, headerValueToAddIn(header));
356+
}
357+
}
344358
}
345359

346360
private void populateJsonValueHeader(Header header, String requestedType, Map<String, Object> headers) {

spring-kafka/src/main/java/org/springframework/kafka/support/MultiValueKafkaHeaderMapper.java

Lines changed: 0 additions & 129 deletions
This file was deleted.

spring-kafka/src/main/java/org/springframework/kafka/support/SimpleKafkaHeaderMapper.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2018-2022 the original author or authors.
2+
* Copyright 2018-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,7 +17,9 @@
1717
package org.springframework.kafka.support;
1818

1919
import java.nio.ByteBuffer;
20+
import java.util.ArrayList;
2021
import java.util.HashSet;
22+
import java.util.List;
2123
import java.util.Map;
2224
import java.util.Set;
2325

@@ -35,6 +37,7 @@
3537
* The exceptions are correlation and reply headers for request/reply
3638
*
3739
* @author Gary Russell
40+
* @author Sanghyeok An
3841
* @since 2.1.3
3942
*
4043
*/
@@ -111,7 +114,21 @@ public void toHeaders(Headers source, Map<String, Object> target) {
111114
target.put(headerName, ByteBuffer.wrap(header.value()).getInt());
112115
}
113116
else {
114-
target.put(headerName, headerValueToAddIn(header));
117+
if (!this.doesMatchMultiValueHeader(headerName)) {
118+
target.put(headerName, headerValueToAddIn(header));
119+
}
120+
else {
121+
Object values = target.getOrDefault(headerName, new ArrayList<>());
122+
if (values instanceof List) {
123+
@SuppressWarnings("unchecked")
124+
List<Object> castedValues = (List<Object>) values;
125+
castedValues.add(headerValueToAddIn(header));
126+
target.put(headerName, castedValues);
127+
}
128+
else {
129+
target.put(headerName, headerValueToAddIn(header));
130+
}
131+
}
115132
}
116133
}
117134
});

spring-kafka/src/main/java/org/springframework/kafka/support/converter/MessagingMessageConverter.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
* @author Gary Russell
5959
* @author Dariusz Szablinski
6060
* @author Biju Kunjummen
61-
* @author Sanghyeok An
6261
*/
6362
public class MessagingMessageConverter implements RecordMessageConverter {
6463

@@ -84,15 +83,6 @@ public MessagingMessageConverter() {
8483
this(msg -> msg.getHeaders().get(KafkaHeaders.PARTITION, Integer.class));
8584
}
8685

87-
/**
88-
* Construct an instance that uses given HeaderMapper.
89-
* @param headerMapper the Header mapper.
90-
* @since 4.0.0
91-
*/
92-
public MessagingMessageConverter(KafkaHeaderMapper headerMapper) {
93-
this(msg -> msg.getHeaders().get(KafkaHeaders.PARTITION, Integer.class), headerMapper);
94-
}
95-
9686
/**
9787
* Construct an instance that uses the supplied partition provider function. The
9888
* function can return null to delegate the partition selection to the kafka client.
@@ -110,18 +100,6 @@ public MessagingMessageConverter(Function<Message<?>, @Nullable Integer> partiti
110100
this.partitionProvider = partitionProvider;
111101
}
112102

113-
/**
114-
* Construct an instance that uses the supplied partition provider function and given HeaderMapper.
115-
* @param partitionProvider the provider.
116-
* @param headerMapper the Header mapper.
117-
* @since 4.0.0
118-
*/
119-
public MessagingMessageConverter(Function<Message<?>, @Nullable Integer> partitionProvider, KafkaHeaderMapper headerMapper) {
120-
Assert.notNull(partitionProvider, "'partitionProvider' cannot be null");
121-
this.headerMapper = headerMapper;
122-
this.partitionProvider = partitionProvider;
123-
}
124-
125103
/**
126104
* Generate {@link Message} {@code ids} for produced messages. If set to {@code false},
127105
* will try to use a default value. By default set to {@code false}.

0 commit comments

Comments
 (0)