@@ -293,7 +293,7 @@ sealed trait EmbeddedKafkaSupport {
293293
294294 def consumeFirstStringMessageFrom (topic : String , autoCommit : Boolean = false )(
295295 implicit config : EmbeddedKafkaConfig ): String =
296- consumeFirstMessageFrom (topic, autoCommit)(config, new StringDeserializer ())
296+ consumeNumberStringMessagesFrom (topic, 1 , autoCommit)(config).head
297297
298298 def consumeNumberStringMessagesFrom (topic : String ,
299299 number : Int ,
@@ -304,7 +304,7 @@ sealed trait EmbeddedKafkaSupport {
304304 new StringDeserializer ())
305305
306306 /**
307- * Consumes the first message available in a given topic, deserializing it as type [[T ]].
307+ * Consumes the first message available in a given topic, deserializing it as type [[V ]].
308308 *
309309 * Only the message that is returned is committed if autoCommit is false.
310310 * If autoCommit is true then all messages that were polled will be committed.
@@ -314,30 +314,62 @@ sealed trait EmbeddedKafkaSupport {
314314 * if true, the offset for the last polled message will be committed instead.
315315 * Defaulted to false.
316316 * @param config an implicit [[EmbeddedKafkaConfig ]]
317- * @param deserializer an implicit [[org.apache.kafka.common.serialization.Deserializer ]] for the type [[T ]]
318- * @return the first message consumed from the given topic, with a type [[T ]]
317+ * @param valueDeserializer an implicit [[org.apache.kafka.common.serialization.Deserializer ]] for the type [[V ]]
318+ * @return the first message consumed from the given topic, with a type [[V ]]
319319 * @throws TimeoutException if unable to consume a message within 5 seconds
320320 * @throws KafkaUnavailableException if unable to connect to Kafka
321321 */
322322 @ throws(classOf [TimeoutException ])
323323 @ throws(classOf [KafkaUnavailableException ])
324- def consumeFirstMessageFrom [T ](topic : String , autoCommit : Boolean = false )(
324+ def consumeFirstMessageFrom [V ](topic : String , autoCommit : Boolean = false )(
325+ implicit config : EmbeddedKafkaConfig ,
326+ valueDeserializer : Deserializer [V ]): V =
327+ consumeNumberMessagesFrom[V ](topic, 1 , autoCommit)(config, valueDeserializer).head
328+
329+ /**
330+ * Consumes the first message available in a given topic, deserializing it as type [[(K, V) ]].
331+ *
332+ * Only the message that is returned is committed if autoCommit is false.
333+ * If autoCommit is true then all messages that were polled will be committed.
334+ *
335+ * @param topic the topic to consume a message from
336+ * @param autoCommit if false, only the offset for the consumed message will be commited.
337+ * if true, the offset for the last polled message will be committed instead.
338+ * Defaulted to false.
339+ * @param config an implicit [[EmbeddedKafkaConfig ]]
340+ * @param keyDeserializer an implicit [[org.apache.kafka.common.serialization.Deserializer ]] for the type [[K ]]
341+ * @param valueDeserializer an implicit [[org.apache.kafka.common.serialization.Deserializer ]] for the type [[V ]]
342+ * @return the first message consumed from the given topic, with a type [[(K, V) ]]
343+ * @throws TimeoutException if unable to consume a message within 5 seconds
344+ * @throws KafkaUnavailableException if unable to connect to Kafka
345+ */
346+ @ throws(classOf [TimeoutException ])
347+ @ throws(classOf [KafkaUnavailableException ])
348+ def consumeFirstKeyedMessageFrom [K , V ](topic : String , autoCommit : Boolean = false )(
325349 implicit config : EmbeddedKafkaConfig ,
326- deserializer : Deserializer [T ]): T =
327- consumeNumberMessagesFrom(topic, 1 , autoCommit)(config, deserializer).head
350+ keyDeserializer : Deserializer [K ],
351+ valueDeserializer : Deserializer [V ]): (K , V ) =
352+ consumeNumberKeyedMessagesFrom[K , V ](topic, 1 , autoCommit)(config, keyDeserializer, valueDeserializer).head
328353
329- def consumeNumberMessagesFrom [T ](topic : String ,
354+ def consumeNumberMessagesFrom [V ](topic : String ,
330355 number : Int ,
331356 autoCommit : Boolean = false )(
357+ implicit config : EmbeddedKafkaConfig ,
358+ valueDeserializer : Deserializer [V ]): List [V ] =
359+ consumeNumberMessagesFromTopics(Set (topic), number, autoCommit)(config, valueDeserializer)(topic)
360+
361+ def consumeNumberKeyedMessagesFrom [K , V ](topic : String ,
362+ number : Int ,
363+ autoCommit : Boolean = false )(
332364 implicit config : EmbeddedKafkaConfig ,
333- deserializer : Deserializer [T ]) : List [ T ] =
334- consumeNumberMessagesFromTopics( Set (topic), number, autoCommit)(
335- config,
336- deserializer )(topic)
365+ keyDeserializer : Deserializer [K ],
366+ valueDeserializer : Deserializer [ V ]) : List [( K , V )] =
367+ consumeNumberKeyedMessagesFromTopics( Set (topic), number, autoCommit)( config, keyDeserializer ,
368+ valueDeserializer )(topic)
337369
338370 /**
339- * Consumes the first n messages available in given topics, deserializes them as type [[T ]], and returns
340- * the n messages in a Map from topic name to List[T ].
371+ * Consumes the first n messages available in given topics, deserializes them as type [[V ]], and returns
372+ * the n messages in a Map from topic name to List[V ].
341373 *
342374 * Only the messages that are returned are committed if autoCommit is false.
343375 * If autoCommit is true then all messages that were polled will be committed.
@@ -353,19 +385,57 @@ sealed trait EmbeddedKafkaSupport {
353385 * throw TimeoutException after the timeout interval if we
354386 * haven't received all of the expected messages
355387 * @param config an implicit [[EmbeddedKafkaConfig ]]
356- * @param deserializer an implicit [[org.apache.kafka.common.serialization.Deserializer ]] for the type [[T ]]
357- * @return the List of messages consumed from the given topics, each with a type [[T ]]
388+ * @param valueDeserializer an implicit [[org.apache.kafka.common.serialization.Deserializer ]]
389+ * for the type [[V ]]
390+ * @return the List of messages consumed from the given topics, each with a type [[V ]]
358391 * @throws TimeoutException if unable to consume messages within specified timeout
359392 * @throws KafkaUnavailableException if unable to connect to Kafka
360393 */
361- def consumeNumberMessagesFromTopics [T ](topics : Set [String ],
394+ def consumeNumberMessagesFromTopics [V ](topics : Set [String ],
362395 number : Int ,
363396 autoCommit : Boolean = false ,
364397 timeout : Duration = 5 .seconds,
365398 resetTimeoutOnEachMessage : Boolean =
366399 true )(
367400 implicit config : EmbeddedKafkaConfig ,
368- deserializer : Deserializer [T ]): Map [String , List [T ]] = {
401+ valueDeserializer : Deserializer [V ]): Map [String , List [V ]] = {
402+ consumeNumberKeyedMessagesFromTopics(topics, number, autoCommit, timeout,
403+ resetTimeoutOnEachMessage)(config, new StringDeserializer (), valueDeserializer)
404+ .mapValues(_.map(_._2))
405+ }
406+
407+ /**
408+ * Consumes the first n messages available in given topics, deserializes them as type [[(K, V) ]], and returns
409+ * the n messages in a Map from topic name to List[(K, V)].
410+ *
411+ * Only the messages that are returned are committed if autoCommit is false.
412+ * If autoCommit is true then all messages that were polled will be committed.
413+ *
414+ * @param topics the topics to consume messages from
415+ * @param number the number of messages to consume in a batch
416+ * @param autoCommit if false, only the offset for the consumed messages will be commited.
417+ * if true, the offset for the last polled message will be committed instead.
418+ * Defaulted to false.
419+ * @param timeout the interval to wait for messages before throwing TimeoutException
420+ * @param resetTimeoutOnEachMessage when true, throw TimeoutException if we have a silent period
421+ * (no incoming messages) for the timeout interval; when false,
422+ * throw TimeoutException after the timeout interval if we
423+ * haven't received all of the expected messages
424+ * @param config an implicit [[EmbeddedKafkaConfig ]]
425+ * @param keyDeserializer an implicit [[org.apache.kafka.common.serialization.Deserializer ]] for the type [[K ]]
426+ * @param valueDeserializer an implicit [[org.apache.kafka.common.serialization.Deserializer ]] for the type [[V ]]
427+ * @return the List of messages consumed from the given topics, each with a type [[(K, V) ]]
428+ * @throws TimeoutException if unable to consume messages within specified timeout
429+ * @throws KafkaUnavailableException if unable to connect to Kafka
430+ */
431+ def consumeNumberKeyedMessagesFromTopics [K , V ](topics : Set [String ],
432+ number : Int ,
433+ autoCommit : Boolean = false ,
434+ timeout : Duration = 5 .seconds,
435+ resetTimeoutOnEachMessage : Boolean = true )(
436+ implicit config : EmbeddedKafkaConfig ,
437+ keyDeserializer : Deserializer [K ],
438+ valueDeserializer : Deserializer [V ]): Map [String , List [(K , V )]] = {
369439
370440 import scala .collection .JavaConverters ._
371441
@@ -374,10 +444,10 @@ sealed trait EmbeddedKafkaSupport {
374444
375445 var timeoutNanoTime = System .nanoTime + timeout.toNanos
376446 val consumer =
377- new KafkaConsumer [String , T ](props, new StringDeserializer , deserializer )
447+ new KafkaConsumer [K , V ](props, keyDeserializer, valueDeserializer )
378448
379449 val messages = Try {
380- val messagesBuffers = topics.map(_ -> ListBuffer .empty[T ]).toMap
450+ val messagesBuffers = topics.map(_ -> ListBuffer .empty[( K , V ) ]).toMap
381451 var messagesRead = 0
382452 consumer.subscribe(topics.asJava)
383453 topics.foreach(consumer.partitionsFor)
@@ -391,7 +461,8 @@ sealed trait EmbeddedKafkaSupport {
391461 while (recordIter.hasNext && messagesRead < number) {
392462 val record = recordIter.next()
393463 val topic = record.topic()
394- messagesBuffers(topic) += record.value()
464+ val message = (record.key(), record.value())
465+ messagesBuffers(topic) += message
395466 val tp = new TopicPartition (topic, record.partition())
396467 val om = new OffsetAndMetadata (record.offset() + 1 )
397468 consumer.commitSync(Map (tp -> om).asJava)
0 commit comments