29
29
import org .apache .kafka .clients .consumer .ConsumerRecord ;
30
30
import org .apache .kafka .clients .producer .ProducerRecord ;
31
31
import org .apache .kafka .common .header .Headers ;
32
+ import org .apache .kafka .common .record .TimestampType ;
32
33
import org .apache .kafka .common .utils .Bytes ;
33
34
34
35
import org .springframework .core .log .LogAccessor ;
36
+ import org .springframework .core .log .LogMessage ;
35
37
import org .springframework .kafka .support .Acknowledgment ;
36
38
import org .springframework .kafka .support .DefaultKafkaHeaderMapper ;
37
39
import org .springframework .kafka .support .JacksonPresent ;
54
56
* <p>
55
57
* If a {@link RecordMessageConverter} is provided, and the batch type is a {@link ParameterizedType}
56
58
* with a single generic type parameter, each record will be passed to the converter, thus supporting
57
- * a method signature {@code List<Foo> foos }.
59
+ * a method signature {@code List<MyType> myObjects }.
58
60
*
59
61
* @author Marius Bogoevici
60
62
* @author Gary Russell
63
65
* @author Sanghyeok An
64
66
* @author Hope Kim
65
67
* @author Borahm Lee
68
+ * @author Artem Bilan
69
+ *
66
70
* @since 1.1
67
71
*/
68
72
public class BatchMessagingMessageConverter implements BatchMessageConverter {
69
73
70
- protected final LogAccessor logger = new LogAccessor (LogFactory . getLog ( getClass () )); // NOSONAR
74
+ protected final LogAccessor logger = new LogAccessor (getClass ()); // NOSONAR
71
75
72
76
@ Nullable
73
77
private final RecordMessageConverter recordConverter ;
@@ -102,7 +106,7 @@ public BatchMessagingMessageConverter(@Nullable RecordMessageConverter recordCon
102
106
103
107
/**
104
108
* Generate {@link Message} {@code ids} for produced messages. If set to {@code false},
105
- * will try to use a default value. By default set to {@code false}.
109
+ * will try to use a default value. By default, set to {@code false}.
106
110
* @param generateMessageId true if a message id should be generated
107
111
*/
108
112
public void setGenerateMessageId (boolean generateMessageId ) {
@@ -111,7 +115,7 @@ public void setGenerateMessageId(boolean generateMessageId) {
111
115
112
116
/**
113
117
* Generate {@code timestamp} for produced messages. If set to {@code false}, -1 is
114
- * used instead. By default set to {@code false}.
118
+ * used instead. By default, set to {@code false}.
115
119
* @param generateTimestamp true if a timestamp should be generated
116
120
*/
117
121
public void setGenerateTimestamp (boolean generateTimestamp ) {
@@ -147,8 +151,8 @@ public void setRawRecordHeader(boolean rawRecordHeader) {
147
151
public Message <?> toMessage (List <ConsumerRecord <?, ?>> records , @ Nullable Acknowledgment acknowledgment ,
148
152
Consumer <?, ?> consumer , Type type ) {
149
153
150
- KafkaMessageHeaders kafkaMessageHeaders = new KafkaMessageHeaders ( this . generateMessageId ,
151
- this .generateTimestamp );
154
+ KafkaMessageHeaders kafkaMessageHeaders =
155
+ new KafkaMessageHeaders ( this . generateMessageId , this .generateTimestamp );
152
156
153
157
Map <String , Object > rawHeaders = kafkaMessageHeaders .getRawHeaders ();
154
158
List <Object > payloads = new ArrayList <>();
@@ -169,16 +173,18 @@ public Message<?> toMessage(List<ConsumerRecord<?, ?>> records, @Nullable Acknow
169
173
170
174
String listenerInfo = null ;
171
175
for (ConsumerRecord <?, ?> record : records ) {
172
- addRecordInfo (record , type , payloads , keys , topics , partitions , offsets , timestampTypes , timestamps , conversionFailures );
173
- if (this .headerMapper != null && record .headers () != null ) {
174
- Map <String , Object > converted = convertHeaders (record .headers (), convertedHeaders );
176
+ addRecordInfo (record , type , payloads , keys , topics , partitions , offsets , timestampTypes , timestamps ,
177
+ conversionFailures );
178
+ Headers recordHeaders = record .headers ();
179
+ if (this .headerMapper != null && recordHeaders != null ) {
180
+ Map <String , Object > converted = convertHeaders (recordHeaders , convertedHeaders );
175
181
Object obj = converted .get (KafkaHeaders .LISTENER_INFO );
176
- if (obj instanceof String ) {
177
- listenerInfo = ( String ) obj ;
182
+ if (obj instanceof String info ) {
183
+ listenerInfo = info ;
178
184
}
179
185
}
180
186
else {
181
- natives .add (record . headers () );
187
+ natives .add (recordHeaders );
182
188
}
183
189
if (this .rawRecordHeader ) {
184
190
raws .add (record );
@@ -198,6 +204,7 @@ public Message<?> toMessage(List<ConsumerRecord<?, ?>> records, @Nullable Acknow
198
204
199
205
private void addToRawHeaders (Map <String , Object > rawHeaders , List <Map <String , Object >> convertedHeaders ,
200
206
List <Headers > natives , List <ConsumerRecord <?, ?>> raws , List <ConversionException > conversionFailures ) {
207
+
201
208
if (this .headerMapper != null ) {
202
209
rawHeaders .put (KafkaHeaders .BATCH_CONVERTED_HEADERS , convertedHeaders );
203
210
}
@@ -211,16 +218,18 @@ private void addToRawHeaders(Map<String, Object> rawHeaders, List<Map<String, Ob
211
218
}
212
219
213
220
private void addRecordInfo (ConsumerRecord <?, ?> record , Type type , List <Object > payloads , List <Object > keys ,
214
- List <String > topics , List <Integer > partitions , List <Long > offsets , List <String > timestampTypes ,
215
- List <Long > timestamps , List <ConversionException > conversionFailures ) {
221
+ List <String > topics , List <Integer > partitions , List <Long > offsets , List <String > timestampTypes ,
222
+ List <Long > timestamps , List <ConversionException > conversionFailures ) {
223
+
216
224
payloads .add (obtainPayload (type , record , conversionFailures ));
217
225
keys .add (record .key ());
218
226
topics .add (record .topic ());
219
227
partitions .add (record .partition ());
220
228
offsets .add (record .offset ());
221
229
timestamps .add (record .timestamp ());
222
- if (record .timestampType () != null ) {
223
- timestampTypes .add (record .timestampType ().name ());
230
+ TimestampType timestampType = record .timestampType ();
231
+ if (timestampType != null ) {
232
+ timestampTypes .add (timestampType .name ());
224
233
}
225
234
}
226
235
@@ -264,24 +273,29 @@ protected Object extractAndConvertValue(ConsumerRecord<?, ?> record, Type type)
264
273
protected Object convert (ConsumerRecord <?, ?> record , Type type , List <ConversionException > conversionFailures ) {
265
274
try {
266
275
Object payload = this .recordConverter
267
- .toMessage (record , null , null , ((ParameterizedType ) type ).getActualTypeArguments ()[0 ]).getPayload ();
276
+ .toMessage (record , null , null , ((ParameterizedType ) type ).getActualTypeArguments ()[0 ]).getPayload ();
268
277
conversionFailures .add (null );
269
278
return payload ;
270
279
}
271
280
catch (ConversionException ex ) {
272
281
byte [] original = null ;
273
- if (record .value () instanceof byte []) {
274
- original = ( byte []) record . value () ;
282
+ if (record .value () instanceof byte [] bytes ) {
283
+ original = bytes ;
275
284
}
276
- else if (record .value () instanceof Bytes ) {
277
- original = (( Bytes ) record . value ()) .get ();
285
+ else if (record .value () instanceof Bytes bytes ) {
286
+ original = bytes .get ();
278
287
}
279
- else if (record .value () instanceof String ) {
280
- original = (( String ) record . value ()) .getBytes (StandardCharsets .UTF_8 );
288
+ else if (record .value () instanceof String string ) {
289
+ original = string .getBytes (StandardCharsets .UTF_8 );
281
290
}
282
291
if (original != null ) {
283
292
SerializationUtils .deserializationException (record .headers (), original , ex , false );
284
293
conversionFailures .add (ex );
294
+ logger .warn (ex ,
295
+ LogMessage .format ("Could not convert message for topic=%s, partition=%d, offset=%d" ,
296
+ record .topic (),
297
+ record .partition (),
298
+ record .offset ()));
285
299
return null ;
286
300
}
287
301
throw new ConversionException ("The batch converter can only report conversion failures to the listener "
@@ -296,8 +310,8 @@ else if (record.value() instanceof String) {
296
310
* @return true if the conditions are met.
297
311
*/
298
312
private boolean containerType (Type type ) {
299
- return type instanceof ParameterizedType
300
- && (( ParameterizedType ) type ) .getActualTypeArguments ().length == 1 ;
313
+ return type instanceof ParameterizedType parameterizedType
314
+ && parameterizedType .getActualTypeArguments ().length == 1 ;
301
315
}
302
316
303
317
}
0 commit comments