This is an automated email from the ASF dual-hosted git repository.
Abacn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git
The following commit(s) were added to refs/heads/master by this push:
new 0b90e18f396 Remove obsolete ConsumerSpEL and ProducerSpEL reflection
shims in KafkaIO (#40839)
0b90e18f396 is described below
commit 0b90e18f396c157054c568b39eb4cce8ac9b0ac4
Author: Steven van Rossum <[email protected]>
AuthorDate: Tue Oct 27 17:40:34 2026 +0100
Remove obsolete ConsumerSpEL and ProducerSpEL reflection shims in KafkaIO
(#40839)
---
.../org/apache/beam/sdk/io/kafka/ConsumerSpEL.java | 169 ---------------------
.../beam/sdk/io/kafka/KafkaExactlyOnceSink.java | 44 +++---
.../java/org/apache/beam/sdk/io/kafka/KafkaIO.java | 48 +-----
.../org/apache/beam/sdk/io/kafka/KafkaIOUtils.java | 25 +++
.../org/apache/beam/sdk/io/kafka/KafkaRecord.java | 5 -
.../apache/beam/sdk/io/kafka/KafkaRecordCoder.java | 32 ++--
.../beam/sdk/io/kafka/KafkaUnboundedReader.java | 14 +-
.../beam/sdk/io/kafka/ProducerRecordCoder.java | 49 ++----
.../org/apache/beam/sdk/io/kafka/ProducerSpEL.java | 157 -------------------
.../beam/sdk/io/kafka/ReadFromKafkaDoFn.java | 12 +-
.../org/apache/beam/sdk/io/kafka/KafkaIOTest.java | 36 +----
.../beam/sdk/io/kafka/KafkaRecordCoderTest.java | 4 +-
.../beam/sdk/io/kafka/ProducerRecordCoderTest.java | 24 +--
13 files changed, 93 insertions(+), 526 deletions(-)
diff --git
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ConsumerSpEL.java
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ConsumerSpEL.java
deleted file mode 100644
index 5045afb53be..00000000000
---
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ConsumerSpEL.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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
- *
- * http://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 org.apache.beam.sdk.io.kafka;
-
-import static
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.base.Preconditions.checkArgument;
-
-import java.util.Map;
-import
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.ImmutableMap;
-import
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.Iterables;
-import org.apache.kafka.clients.consumer.Consumer;
-import org.apache.kafka.clients.consumer.ConsumerRecord;
-import org.apache.kafka.clients.consumer.OffsetAndTimestamp;
-import org.apache.kafka.common.TopicPartition;
-import org.apache.kafka.common.header.Headers;
-import org.apache.kafka.common.serialization.Deserializer;
-import org.joda.time.Instant;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * ConsumerSpEL to handle multiple of versions of Consumer API between Kafka
0.9 and 2.1.0 onwards.
- * It auto detects the input type List/Collection/Varargs, to eliminate the
method definition
- * differences.
- */
-class ConsumerSpEL {
-
- private static final Logger LOG =
LoggerFactory.getLogger(ConsumerSpEL.class);
-
- private static boolean hasRecordTimestamp;
- private static boolean hasHeaders;
- private static boolean hasOffsetsForTimes;
- private static boolean deserializerSupportsHeaders;
-
- static {
- try {
- // It is supported by Kafka Client 0.10.0.0 onwards.
- hasRecordTimestamp =
- ConsumerRecord.class
- .getMethod("timestamp", (Class<?>[]) null)
- .getReturnType()
- .equals(Long.TYPE);
- } catch (NoSuchMethodException | SecurityException e) {
- LOG.debug("Timestamp for Kafka message is not available.");
- }
-
- try {
- // It is supported by Kafka Client 0.11.0.0 onwards.
- hasHeaders =
- "org.apache.kafka.common.header.Headers"
- .equals(
- ConsumerRecord.class
- .getMethod("headers", (Class<?>[]) null)
- .getReturnType()
- .getName());
- } catch (NoSuchMethodException | SecurityException e) {
- LOG.debug("Headers is not available");
- }
-
- try {
- // It is supported by Kafka Client 0.10.1.0 onwards.
- hasOffsetsForTimes =
- Consumer.class.getMethod("offsetsForTimes",
Map.class).getReturnType().equals(Map.class);
- } catch (NoSuchMethodException | SecurityException e) {
- LOG.debug("OffsetsForTimes is not available.");
- }
-
- try {
- // It is supported by Kafka Client 2.1.0 onwards.
- deserializerSupportsHeaders =
- "T"
- .equals(
- Deserializer.class
- .getDeclaredMethod("deserialize", String.class,
Headers.class, byte[].class)
- .getGenericReturnType()
- .getTypeName());
- } catch (NoSuchMethodException | SecurityException e) {
- LOG.debug("Deserializer interface does not support Kafka headers");
- }
- }
-
- public static long getRecordTimestamp(ConsumerRecord<byte[], byte[]>
rawRecord) {
- if (hasRecordTimestamp) {
- return rawRecord.timestamp();
- }
- return -1L; // This is the timestamp used in Kafka for older messages
without timestamps.
- }
-
- public static KafkaTimestampType getRecordTimestampType(
- ConsumerRecord<byte[], byte[]> rawRecord) {
- if (hasRecordTimestamp) {
- return
KafkaTimestampType.forOrdinal(rawRecord.timestampType().ordinal());
- } else {
- return KafkaTimestampType.NO_TIMESTAMP_TYPE;
- }
- }
-
- public static boolean hasOffsetsForTimes() {
- return hasOffsetsForTimes;
- }
-
- public static boolean hasHeaders() {
- return hasHeaders;
- }
-
- public static boolean deserializerSupportsHeaders() {
- return deserializerSupportsHeaders;
- }
-
- public static <T> T deserializeKey(
- Deserializer<T> deserializer, ConsumerRecord<byte[], byte[]> rawRecord) {
- if (deserializerSupportsHeaders) {
- // Kafka API 2.1.0 onwards
- return deserializer.deserialize(rawRecord.topic(), rawRecord.headers(),
rawRecord.key());
- } else {
- return deserializer.deserialize(rawRecord.topic(), rawRecord.key());
- }
- }
-
- public static <T> T deserializeValue(
- Deserializer<T> deserializer, ConsumerRecord<byte[], byte[]> rawRecord) {
- if (deserializerSupportsHeaders) {
- // Kafka API 2.1.0 onwards
- return deserializer.deserialize(rawRecord.topic(), rawRecord.headers(),
rawRecord.value());
- } else {
- return deserializer.deserialize(rawRecord.topic(), rawRecord.value());
- }
- }
-
- /**
- * Look up the offset for the given partition by timestamp. Throws
RuntimeException if there are
- * no messages later than timestamp or if this partition does not support
timestamp based offset.
- */
- @SuppressWarnings("unchecked")
- public static long offsetForTime(
- Consumer<?, ?> consumer, TopicPartition topicPartition, Instant time) {
-
- checkArgument(hasOffsetsForTimes, "This Kafka Client must support
Consumer.OffsetsForTimes().");
-
- // 'value' in the map returned by offsetFoTime() is null if there is no
offset for the time.
- OffsetAndTimestamp offsetAndTimestamp =
- Iterables.getOnlyElement(
- consumer.offsetsForTimes(ImmutableMap.of(topicPartition,
time.getMillis())).values());
-
- if (offsetAndTimestamp == null) {
- throw new RuntimeException(
- "There are no messages has a timestamp that is greater than or "
- + "equals to the target time or the message format version in
this partition is "
- + "before 0.10.0, topicPartition is: "
- + topicPartition);
- } else {
- return offsetAndTimestamp.offset();
- }
- }
-}
diff --git
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaExactlyOnceSink.java
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaExactlyOnceSink.java
index c6b7761a9a6..6a811bc2e8f 100644
---
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaExactlyOnceSink.java
+++
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaExactlyOnceSink.java
@@ -17,7 +17,6 @@
*/
package org.apache.beam.sdk.io.kafka;
-import static
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.base.Preconditions.checkArgument;
import static
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.base.Preconditions.checkNotNull;
import static
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.base.Preconditions.checkState;
@@ -83,6 +82,9 @@ import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.apache.kafka.common.KafkaException;
import org.apache.kafka.common.TopicPartition;
+import org.apache.kafka.common.errors.AuthorizationException;
+import org.apache.kafka.common.errors.OutOfOrderSequenceException;
+import org.apache.kafka.common.errors.ProducerFencedException;
import org.apache.kafka.common.serialization.ByteArrayDeserializer;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.joda.time.DateTimeUtils;
@@ -148,14 +150,6 @@ class KafkaExactlyOnceSink<K, V>
private final WriteRecords<K, V> spec;
- static void ensureEOSSupport() {
- checkArgument(
- ProducerSpEL.supportsTransactions(),
- "%s %s",
- "This version of Kafka client does not support transactions required
to support",
- "exactly-once semantics. Please use Kafka client version 0.11 or
newer.");
- }
-
KafkaExactlyOnceSink(WriteRecords<K, V> spec) {
this.spec = spec;
}
@@ -301,12 +295,6 @@ class KafkaExactlyOnceSink<K, V>
StateSpecs.bag(KvCoder.of(BigEndianLongCoder.of(),
TimestampedValueCoder.of(elemCoder)));
}
- @Setup
- public void setup() {
- // This is on the worker. Ensure the runtime version is till compatible.
- KafkaExactlyOnceSink.ensureEOSSupport();
- }
-
// Futures ignored as exceptions will be flushed out in the commitTxn
@SuppressWarnings("FutureReturnValueIgnored")
@RequiresStableInput
@@ -428,7 +416,7 @@ class KafkaExactlyOnceSink<K, V>
writer.commitTxn(nextId - 1, numTransactions);
nextIdState.write(nextId);
- } catch (ProducerSpEL.UnrecoverableProducerException e) {
+ } catch (ProducerFencedException | OutOfOrderSequenceException |
AuthorizationException e) {
// Producer JavaDoc says these are not recoverable errors and producer
should be closed.
// Close the producer and a new producer will be initialized in retry.
@@ -501,7 +489,7 @@ class KafkaExactlyOnceSink<K, V>
}
void beginTxn() {
- ProducerSpEL.beginTransaction(producer);
+ producer.beginTransaction();
}
Future<RecordMetadata> sendRecord(
@@ -526,12 +514,15 @@ class KafkaExactlyOnceSink<K, V>
record.getValue().value()));
sendCounter.inc();
return result;
+ } catch (ProducerFencedException | OutOfOrderSequenceException |
AuthorizationException e) {
+ throw e;
} catch (KafkaException e) {
- ProducerSpEL.abortTransaction(producer);
+ producer.abortTransaction();
throw e;
}
}
+ @SuppressWarnings("deprecation")
void commitTxn(long lastRecordId, Counter numTransactions) throws
IOException {
String topic = Preconditions.checkStateNotNull(spec.getTopic());
try {
@@ -539,15 +530,14 @@ class KafkaExactlyOnceSink<K, V>
// NOTE: Kafka keeps this metadata for 24 hours since the last
update. This limits
// how long the pipeline could be down before resuming it. It does
not look like
// this TTL can be adjusted (asked about it on Kafka users list).
- ProducerSpEL.sendOffsetsToTransaction(
- producer,
+ producer.sendOffsetsToTransaction(
ImmutableMap.of(
new TopicPartition(topic, shard),
new OffsetAndMetadata(
0L,
JSON_MAPPER.writeValueAsString(new
ShardMetadata(lastRecordId, writerId)))),
- spec.getSinkGroupId());
- ProducerSpEL.commitTransaction(producer);
+ Preconditions.checkStateNotNull(spec.getSinkGroupId()));
+ producer.commitTransaction();
numTransactions.inc();
if (!reportedLineage) {
@@ -567,8 +557,10 @@ class KafkaExactlyOnceSink<K, V>
LOG.debug("{} : committed {} records", shard, lastRecordId -
committedId);
committedId = lastRecordId;
+ } catch (ProducerFencedException | OutOfOrderSequenceException |
AuthorizationException e) {
+ throw e;
} catch (KafkaException e) {
- ProducerSpEL.abortTransaction(producer);
+ producer.abortTransaction();
throw e;
}
}
@@ -767,15 +759,15 @@ class KafkaExactlyOnceSink<K, V>
if (spec.getValueSerializer() != null) {
producerConfig.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
spec.getValueSerializer());
}
- producerConfig.put(ProducerSpEL.ENABLE_IDEMPOTENCE_CONFIG, true);
- producerConfig.put(ProducerSpEL.TRANSACTIONAL_ID_CONFIG, producerName);
+ producerConfig.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true);
+ producerConfig.put(ProducerConfig.TRANSACTIONAL_ID_CONFIG, producerName);
Producer<K, V> producer =
spec.getProducerFactoryFn() != null
? spec.getProducerFactoryFn().apply(producerConfig)
: new KafkaProducer<>(producerConfig);
- ProducerSpEL.initTransactions(producer);
+ producer.initTransactions();
return producer;
}
}
diff --git
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaIO.java
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaIO.java
index a41db9fbeaf..e5a7ce9e883 100644
--- a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaIO.java
+++ b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaIO.java
@@ -142,7 +142,6 @@ import
org.apache.kafka.common.serialization.ByteArrayDeserializer;
import org.apache.kafka.common.serialization.Deserializer;
import org.apache.kafka.common.serialization.Serializer;
import org.apache.kafka.common.serialization.StringSerializer;
-import org.apache.kafka.common.utils.AppInfoParser;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.dataflow.qual.Pure;
@@ -1664,31 +1663,6 @@ public class KafkaIO {
checkArgument(getKeyDeserializerProvider() != null,
"withKeyDeserializer() is required");
checkArgument(getValueDeserializerProvider() != null,
"withValueDeserializer() is required");
- if (!ConsumerSpEL.hasOffsetsForTimes()) {
- LOG.warn(
- "Kafka client version {} is too old. Versions before 0.10.1.0 are
deprecated and "
- + "may not be supported in next release of Apache Beam. "
- + "Please upgrade your Kafka client version.",
- AppInfoParser.getVersion());
- }
- if (getStartReadTime() != null) {
- checkArgument(
- ConsumerSpEL.hasOffsetsForTimes(),
- "Consumer.offsetsForTimes is only supported by Kafka Client
0.10.1.0 onwards, "
- + "current version of Kafka Client is "
- + AppInfoParser.getVersion()
- + ". If you are building with maven, set
\"kafka.clients.version\" "
- + "maven property to 0.10.1.0 or newer.");
- }
- if (getStopReadTime() != null) {
- checkArgument(
- ConsumerSpEL.hasOffsetsForTimes(),
- "Consumer.offsetsForTimes is only supported by Kafka Client
0.10.1.0 onwards, "
- + "current version of Kafka Client is "
- + AppInfoParser.getVersion()
- + ". If you are building with maven, set
\"kafka.clients.version\" "
- + "maven property to 0.10.1.0 or newer.");
- }
if (isCommitOffsetsInFinalizeEnabled()) {
checkArgument(
getConsumerConfig().get(ConsumerConfig.GROUP_ID_CONFIG) != null,
@@ -3123,14 +3097,6 @@ public class KafkaIO {
checkArgument(getKeyDeserializerProvider() != null,
"withKeyDeserializer() is required");
checkArgument(getValueDeserializerProvider() != null,
"withValueDeserializer() is required");
- if (!ConsumerSpEL.hasOffsetsForTimes()) {
- LOG.warn(
- "Kafka client version {} is too old. Versions before 0.10.1.0 are
deprecated and "
- + "may not be supported in next release of Apache Beam. "
- + "Please upgrade your Kafka client version.",
- AppInfoParser.getVersion());
- }
-
if (isCommitOffsetEnabled()) {
if (configuredKafkaCommit()) {
LOG.info(
@@ -3529,7 +3495,6 @@ public class KafkaIO {
* written by the same job.
*/
public WriteRecords<K, V> withEOS(int numShards, String sinkGroupId) {
- KafkaExactlyOnceSink.ensureEOSSupport();
checkArgument(numShards >= 1, "numShards should be >= 1");
checkArgument(sinkGroupId != null, "sinkGroupId is required for
exactly-once sink");
return
toBuilder().setEOS(true).setNumShards(numShards).setSinkGroupId(sinkGroupId).build();
@@ -3581,7 +3546,6 @@ public class KafkaIO {
checkArgument(
getBadRecordErrorHandler() instanceof DefaultErrorHandler,
"BadRecordErrorHandling isn't supported with Kafka Exactly Once
writing");
- KafkaExactlyOnceSink.ensureEOSSupport();
// TODO: Verify that the group_id does not have existing state stored
on Kafka unless
// this is an upgrade. This avoids issues with simple mistake of
reusing group_id
@@ -4132,9 +4096,8 @@ public class KafkaIO {
Long timestamp =
row.getSchema().hasField(FIELD_TIMESTAMP) ?
row.getInt64(FIELD_TIMESTAMP) : null;
- boolean hasHeaders = ConsumerSpEL.hasHeaders();
Iterable<Header> headers = Collections.emptyList();
- if (hasHeaders && row.getSchema().hasField(FIELD_HEADERS)) {
+ if (row.getSchema().hasField(FIELD_HEADERS)) {
Iterable<Row> headerRows = row.getArray(FIELD_HEADERS);
if (headerRows != null) {
List<Header> headerList = new ArrayList<>();
@@ -4146,16 +4109,9 @@ public class KafkaIO {
}
headers = headerList;
}
- } else if (!hasHeaders && row.getSchema().hasField(FIELD_HEADERS)) {
- // Log warning when headers are present but Kafka client doesn't
support them
- LOG.warn(
- "Dropping headers from Kafka record because the Kafka client
version "
- + "does not support headers (requires Kafka 0.11+).");
}
- return hasHeaders
- ? new ProducerRecord<>(topic, partition, timestamp, key, value,
headers)
- : new ProducerRecord<>(topic, partition, timestamp, key, value);
+ return new ProducerRecord<>(topic, partition, timestamp, key, value,
headers);
}
}
diff --git
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaIOUtils.java
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaIOUtils.java
index 91aa8557795..656eabfb52a 100644
---
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaIOUtils.java
+++
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaIOUtils.java
@@ -27,12 +27,16 @@ import java.util.Random;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import org.apache.beam.sdk.transforms.SerializableFunction;
import
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.ImmutableMap;
+import
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.Iterables;
import
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.primitives.Longs;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.KafkaConsumer;
+import org.apache.kafka.clients.consumer.OffsetAndTimestamp;
+import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.serialization.ByteArrayDeserializer;
import org.checkerframework.checker.nullness.qual.Nullable;
+import org.joda.time.Instant;
/**
* Common utility functions and default configurations for {@link
KafkaIO.Read} and {@link
@@ -148,6 +152,27 @@ public final class KafkaIOUtils {
return config;
}
+ /**
+ * Look up the offset for the given partition by timestamp. Throws
RuntimeException if there are
+ * no messages later than timestamp or if this partition does not support
timestamp based offset.
+ */
+ static long offsetForTime(Consumer<?, ?> consumer, TopicPartition
topicPartition, Instant time) {
+ // 'value' in the map returned by offsetsForTimes() is null if there is no
offset for the time.
+ OffsetAndTimestamp offsetAndTimestamp =
+ Iterables.getOnlyElement(
+ consumer.offsetsForTimes(ImmutableMap.of(topicPartition,
time.getMillis())).values());
+
+ if (offsetAndTimestamp == null) {
+ throw new RuntimeException(
+ "There are no messages has a timestamp that is greater than or "
+ + "equals to the target time or the message format version in
this partition is "
+ + "before 0.10.0, topicPartition is: "
+ + topicPartition);
+ } else {
+ return offsetAndTimestamp.offset();
+ }
+ }
+
/*
* Maintains approximate average over last 1000 elements.
* Usage is only thread-safe for a single producer and multiple consumers.
diff --git
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaRecord.java
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaRecord.java
index 60aa68e0129..e31333fc7e4 100644
---
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaRecord.java
+++
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaRecord.java
@@ -84,11 +84,6 @@ public class KafkaRecord<K, V> {
@Pure
public @Nullable Headers getHeaders() {
- if (!ConsumerSpEL.hasHeaders()) {
- throw new RuntimeException(
- "The version kafka-clients does not support record headers, "
- + "please use version 0.11.0.0 or newer");
- }
return headers;
}
diff --git
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaRecordCoder.java
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaRecordCoder.java
index dbb3a053099..cfccfe3674c 100644
---
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaRecordCoder.java
+++
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaRecordCoder.java
@@ -21,7 +21,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import org.apache.beam.sdk.coders.ByteArrayCoder;
import org.apache.beam.sdk.coders.Coder;
@@ -33,10 +32,9 @@ import org.apache.beam.sdk.coders.StructuredCoder;
import org.apache.beam.sdk.coders.VarIntCoder;
import org.apache.beam.sdk.coders.VarLongCoder;
import org.apache.beam.sdk.values.KV;
-import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.common.header.Header;
import org.apache.kafka.common.header.Headers;
-import org.checkerframework.checker.nullness.qual.Nullable;
+import org.apache.kafka.common.header.internals.RecordHeaders;
/** {@link Coder} for {@link KafkaRecord}. */
public class KafkaRecordCoder<K, V> extends StructuredCoder<KafkaRecord<K, V>>
{
@@ -76,29 +74,21 @@ public class KafkaRecordCoder<K, V> extends
StructuredCoder<KafkaRecord<K, V>> {
longCoder.decode(inStream),
longCoder.decode(inStream),
KafkaTimestampType.forOrdinal(intCoder.decode(inStream)),
- (Headers) toHeaders(headerCoder.decode(inStream)),
+ toHeaders(headerCoder.decode(inStream)),
kvCoder.decode(inStream));
}
- private @Nullable Object toHeaders(Iterable<KV<String, byte[]>> records) {
- if (!ConsumerSpEL.hasHeaders()) {
- return null;
- }
-
- // ConsumerRecord is used to simply create a list of headers
- ConsumerRecord<String, String> consumerRecord = new ConsumerRecord<>("",
0, 0L, "", "");
- records.forEach(kv -> consumerRecord.headers().add(kv.getKey(),
kv.getValue()));
- return consumerRecord.headers();
+ private static Headers toHeaders(Iterable<KV<String, byte[]>> records) {
+ RecordHeaders headers = new RecordHeaders();
+ records.forEach(kv -> headers.add(kv.getKey(), kv.getValue()));
+ return headers;
}
- private Iterable<KV<String, byte[]>> toIterable(KafkaRecord<K, V> record) {
- if (!ConsumerSpEL.hasHeaders()) {
- return Collections.emptyList();
- }
-
+ private static Iterable<KV<String, byte[]>> toIterable(KafkaRecord<?, ?>
record) {
List<KV<String, byte[]>> vals = new ArrayList<>();
- if (record.getHeaders() != null) {
- for (Header header : record.getHeaders()) {
+ Headers headers = record.getHeaders();
+ if (headers != null) {
+ for (Header header : headers) {
vals.add(KV.of(header.key(), header.value()));
}
}
@@ -133,7 +123,7 @@ public class KafkaRecordCoder<K, V> extends
StructuredCoder<KafkaRecord<K, V>> {
value.getOffset(),
value.getTimestamp(),
value.getTimestampType(),
- !ConsumerSpEL.hasHeaders() ? null : value.getHeaders(),
+ value.getHeaders(),
(KV<Object, Object>) kvCoder.structuralValue(value.getKV()));
}
}
diff --git
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaUnboundedReader.java
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaUnboundedReader.java
index 5e18ad83e2a..bd79fad56e6 100644
---
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaUnboundedReader.java
+++
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/KafkaUnboundedReader.java
@@ -187,11 +187,13 @@ class KafkaUnboundedReader<K, V> extends
UnboundedReader<KafkaRecord<K, V>> {
rawRecord.topic(),
rawRecord.partition(),
rawRecord.offset(),
- ConsumerSpEL.getRecordTimestamp(rawRecord),
- ConsumerSpEL.getRecordTimestampType(rawRecord),
- ConsumerSpEL.hasHeaders() ? rawRecord.headers() : null,
- ConsumerSpEL.deserializeKey(keyDeserializerInstance,
rawRecord),
- ConsumerSpEL.deserializeValue(valueDeserializerInstance,
rawRecord));
+ rawRecord.timestamp(),
+
KafkaTimestampType.forOrdinal(rawRecord.timestampType().ordinal()),
+ rawRecord.headers(),
+ keyDeserializerInstance.deserialize(
+ rawRecord.topic(), rawRecord.headers(), rawRecord.key()),
+ valueDeserializerInstance.deserialize(
+ rawRecord.topic(), rawRecord.headers(),
rawRecord.value()));
curTimestamp =
pState.timestampPolicy.getTimestampForRecord(pState.mkTimestampPolicyContext(),
record);
@@ -828,7 +830,7 @@ class KafkaUnboundedReader<K, V> extends
UnboundedReader<KafkaRecord<K, V>> {
Instant startReadTime = spec.getStartReadTime();
if (startReadTime != null) {
pState.nextOffset =
- ConsumerSpEL.offsetForTime(consumer, pState.topicPartition,
startReadTime);
+ KafkaIOUtils.offsetForTime(consumer, pState.topicPartition,
startReadTime);
consumer.seek(pState.topicPartition, pState.nextOffset);
} else {
pState.nextOffset = consumer.position(pState.topicPartition);
diff --git
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ProducerRecordCoder.java
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ProducerRecordCoder.java
index f04868fa082..63175546a32 100644
---
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ProducerRecordCoder.java
+++
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ProducerRecordCoder.java
@@ -21,7 +21,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import org.apache.beam.sdk.coders.ByteArrayCoder;
import org.apache.beam.sdk.coders.Coder;
@@ -32,10 +31,10 @@ import org.apache.beam.sdk.coders.StructuredCoder;
import org.apache.beam.sdk.coders.VarIntCoder;
import org.apache.beam.sdk.coders.VarLongCoder;
import org.apache.beam.sdk.values.KV;
-import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.header.Header;
import org.apache.kafka.common.header.Headers;
+import org.apache.kafka.common.header.internals.RecordHeaders;
import org.checkerframework.checker.nullness.qual.Nullable;
/** {@link Coder} for {@link ProducerRecord}. */
@@ -78,33 +77,23 @@ public class ProducerRecordCoder<K, V> extends
StructuredCoder<ProducerRecord<K,
timestamp = null;
}
- Headers headers = (Headers) toHeaders(headerCoder.decode(inStream));
+ Headers headers = toHeaders(headerCoder.decode(inStream));
KV<K, V> kv = kvCoder.decode(inStream);
- @SuppressWarnings("nullness") // kakfa library not annotated
+ @SuppressWarnings("nullness") // kafka library not annotated
ProducerRecord<K, V> result =
- ConsumerSpEL.hasHeaders()
- ? new ProducerRecord<>(topic, partition, timestamp, kv.getKey(),
kv.getValue(), headers)
- : new ProducerRecord<>(topic, partition, timestamp, kv.getKey(),
kv.getValue());
+ new ProducerRecord<>(topic, partition, timestamp, kv.getKey(),
kv.getValue(), headers);
return result;
}
- private @Nullable Object toHeaders(Iterable<KV<String, byte[]>> records) {
- if (!ConsumerSpEL.hasHeaders()) {
- return null;
- }
-
- // ConsumerRecord is used to simply create a list of headers
- ConsumerRecord<String, String> consumerRecord = new ConsumerRecord<>("",
0, 0L, "", "");
- records.forEach(kv -> consumerRecord.headers().add(kv.getKey(),
kv.getValue()));
- return consumerRecord.headers();
+ private static Headers toHeaders(Iterable<KV<String, byte[]>> records) {
+ RecordHeaders headers = new RecordHeaders();
+ records.forEach(kv -> headers.add(kv.getKey(), kv.getValue()));
+ return headers;
}
- private Iterable<KV<String, byte[]>> toIterable(ProducerRecord<K, V> record)
{
- if (!ConsumerSpEL.hasHeaders()) {
- return Collections.emptyList();
- }
+ private static Iterable<KV<String, byte[]>> toIterable(ProducerRecord<?, ?>
record) {
List<KV<String, byte[]>> vals = new ArrayList<>();
for (Header header : record.headers()) {
vals.add(KV.of(header.key(), header.value()));
@@ -127,24 +116,18 @@ public class ProducerRecordCoder<K, V> extends
StructuredCoder<ProducerRecord<K,
return kvCoder.isRegisterByteSizeObserverCheap(KV.of(value.key(),
value.value()));
}
- @SuppressWarnings("unchecked")
@Override
public Object structuralValue(ProducerRecord<K, V> value) {
if (consistentWithEquals()) {
return value;
} else {
- if (!ConsumerSpEL.hasHeaders()) {
- return new ProducerRecord<>(
- value.topic(), value.partition(), value.timestamp(), value.key(),
value.value());
- } else {
- return new ProducerRecord<>(
- value.topic(),
- value.partition(),
- value.timestamp(),
- value.key(),
- value.value(),
- value.headers());
- }
+ return new ProducerRecord<>(
+ value.topic(),
+ value.partition(),
+ value.timestamp(),
+ value.key(),
+ value.value(),
+ value.headers());
}
}
diff --git
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ProducerSpEL.java
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ProducerSpEL.java
deleted file mode 100644
index c993f41421a..00000000000
---
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ProducerSpEL.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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
- *
- * http://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 org.apache.beam.sdk.io.kafka;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Map;
-import org.apache.beam.sdk.util.Preconditions;
-import org.apache.kafka.clients.consumer.OffsetAndMetadata;
-import org.apache.kafka.clients.producer.Producer;
-import org.apache.kafka.common.TopicPartition;
-import org.apache.kafka.common.errors.ApiException;
-import org.apache.kafka.common.errors.AuthorizationException;
-import org.checkerframework.checker.nullness.qual.Nullable;
-
-/**
- * ProducerSpEL to handle newer versions Producer API. The API is updated in
Kafka 0.11 to support
- * exactly-once semantics.
- */
-class ProducerSpEL {
-
- private static final class TransactionsImplementation {
- private Method initTransactionsMethod;
- private Method beginTransactionMethod;
- private Method commitTransactionMethod;
- private Method abortTransactionMethod;
- private Method sendOffsetsToTransactionMethod;
- private Class<?> producerFencedExceptionClass;
- private Class<?> outOfOrderSequenceExceptionClass;
-
- private TransactionsImplementation() throws NoSuchMethodException,
ClassNotFoundException {
- initTransactionsMethod = Producer.class.getMethod("initTransactions");
- beginTransactionMethod = Producer.class.getMethod("beginTransaction");
- commitTransactionMethod = Producer.class.getMethod("commitTransaction");
- abortTransactionMethod = Producer.class.getMethod("abortTransaction");
- sendOffsetsToTransactionMethod =
- Producer.class.getMethod("sendOffsetsToTransaction", Map.class,
String.class);
- producerFencedExceptionClass =
-
Class.forName("org.apache.kafka.common.errors.ProducerFencedException");
- outOfOrderSequenceExceptionClass =
-
Class.forName("org.apache.kafka.common.errors.OutOfOrderSequenceException");
- }
-
- private void initTransactions(Producer<?, ?> producer) {
- invoke(initTransactionsMethod, producer);
- }
-
- private void beginTransaction(Producer<?, ?> producer) {
- invoke(beginTransactionMethod, producer);
- }
-
- private void commitTransaction(Producer<?, ?> producer) {
- invoke(commitTransactionMethod, producer);
- }
-
- private void abortTransaction(Producer<?, ?> producer) {
- invoke(abortTransactionMethod, producer);
- }
-
- private void sendOffsetsToTransaction(
- Producer<?, ?> producer,
- Map<TopicPartition, OffsetAndMetadata> offsets,
- @Nullable String consumerGroupId) {
- invoke(sendOffsetsToTransactionMethod, producer, offsets,
consumerGroupId);
- }
-
- private void invoke(Method method, Object obj, @Nullable Object... args) {
- try {
- @SuppressWarnings({"nullness", "unused"}) // JDK annotation does not
allow the nulls
- Object ignored = method.invoke(obj, args);
- } catch (IllegalAccessException | InvocationTargetException e) {
- throw new RuntimeException(e);
- } catch (ApiException e) {
- Class<?> eClass = e.getClass();
- if (producerFencedExceptionClass.isAssignableFrom(eClass)
- || outOfOrderSequenceExceptionClass.isAssignableFrom(eClass)
- || AuthorizationException.class.isAssignableFrom(eClass)) {
- throw new UnrecoverableProducerException(e);
- }
- throw e;
- }
- }
- }
-
- private static @Nullable TransactionsImplementation
transactionsImplementation;
-
- static final String ENABLE_IDEMPOTENCE_CONFIG = "enable.idempotence";
- static final String TRANSACTIONAL_ID_CONFIG = "transactional.id";
-
- static {
- try {
- transactionsImplementation = new TransactionsImplementation();
- } catch (ClassNotFoundException | NoSuchMethodException e) {
- transactionsImplementation = null;
- }
- }
-
- /**
- * Wraps an unrecoverable producer exceptions, including the ones related
transactions introduced
- * in 0.11 (as described in documentation for {@link Producer}). The calller
should close the
- * producer when this exception is thrown.
- */
- static class UnrecoverableProducerException extends ApiException {
- UnrecoverableProducerException(ApiException cause) {
- super(cause);
- }
- }
-
- static boolean supportsTransactions() {
- return transactionsImplementation != null;
- }
-
- private static TransactionsImplementation getTransactionsImplementation() {
- return Preconditions.checkStateNotNull(
- transactionsImplementation,
- "This version of Kafka client library does not support transactions."
- + " Please used version 0.11 or later.");
- }
-
- static void initTransactions(Producer<?, ?> producer) {
- getTransactionsImplementation().initTransactions(producer);
- }
-
- static void beginTransaction(Producer<?, ?> producer) {
- getTransactionsImplementation().beginTransaction(producer);
- }
-
- static void commitTransaction(Producer<?, ?> producer) {
- getTransactionsImplementation().commitTransaction(producer);
- }
-
- static void abortTransaction(Producer<?, ?> producer) {
- getTransactionsImplementation().abortTransaction(producer);
- }
-
- static void sendOffsetsToTransaction(
- Producer<?, ?> producer,
- Map<TopicPartition, OffsetAndMetadata> offsets,
- @Nullable String consumerGroupId) {
- getTransactionsImplementation().sendOffsetsToTransaction(producer,
offsets, consumerGroupId);
- }
-}
diff --git
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ReadFromKafkaDoFn.java
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ReadFromKafkaDoFn.java
index 68453443475..223548225c1 100644
---
a/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ReadFromKafkaDoFn.java
+++
b/sdks/java/io/kafka/src/main/java/org/apache/beam/sdk/io/kafka/ReadFromKafkaDoFn.java
@@ -578,11 +578,13 @@ abstract class ReadFromKafkaDoFn<K, V>
rawRecord.topic(),
rawRecord.partition(),
rawRecord.offset(),
- ConsumerSpEL.getRecordTimestamp(rawRecord),
- ConsumerSpEL.getRecordTimestampType(rawRecord),
- ConsumerSpEL.hasHeaders() ? rawRecord.headers() : null,
- ConsumerSpEL.deserializeKey(keyDeserializerInstance,
rawRecord),
- ConsumerSpEL.deserializeValue(valueDeserializerInstance,
rawRecord));
+ rawRecord.timestamp(),
+
KafkaTimestampType.forOrdinal(rawRecord.timestampType().ordinal()),
+ rawRecord.headers(),
+ keyDeserializerInstance.deserialize(
+ rawRecord.topic(), rawRecord.headers(),
rawRecord.key()),
+ valueDeserializerInstance.deserialize(
+ rawRecord.topic(), rawRecord.headers(),
rawRecord.value()));
int recordSize =
(rawRecord.key() == null ? 0 : rawRecord.key().length)
+ (rawRecord.value() == null ? 0 :
rawRecord.value().length);
diff --git
a/sdks/java/io/kafka/src/test/java/org/apache/beam/sdk/io/kafka/KafkaIOTest.java
b/sdks/java/io/kafka/src/test/java/org/apache/beam/sdk/io/kafka/KafkaIOTest.java
index 8e56f08f7a1..b3865162484 100644
---
a/sdks/java/io/kafka/src/test/java/org/apache/beam/sdk/io/kafka/KafkaIOTest.java
+++
b/sdks/java/io/kafka/src/test/java/org/apache/beam/sdk/io/kafka/KafkaIOTest.java
@@ -34,7 +34,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause;
import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage;
@@ -178,8 +177,6 @@ import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Tests of {@link KafkaIO}. Run with 'mvn test
-Dkafka.clients.version=0.10.1.1', to test with a
@@ -189,8 +186,6 @@ import org.slf4j.LoggerFactory;
@RunWith(JUnit4.class)
public class KafkaIOTest {
- private static final Logger LOG = LoggerFactory.getLogger(KafkaIOTest.class);
-
/*
* The tests below borrow code and structure from CountingSourceTest. In
addition verifies
* the reader interleaves the records from multiple partitions.
@@ -645,14 +640,12 @@ public class KafkaIOTest {
@Override
public Integer deserialize(String topic, byte[] data) {
- assertEquals(false, ConsumerSpEL.deserializerSupportsHeaders());
- return super.deserialize(topic, data);
+ throw new UnsupportedOperationException(
+ "Expected deserialize(String, Headers, byte[]) to be called");
}
@Override
public Integer deserialize(String topic, Headers headers, byte[] data) {
- // Overriding the default should trigger header evaluation and this to
be called.
- assertEquals(true, ConsumerSpEL.deserializerSupportsHeaders());
return super.deserialize(topic, data);
}
}
@@ -662,14 +655,12 @@ public class KafkaIOTest {
@Override
public Long deserialize(String topic, byte[] data) {
- assertEquals(false, ConsumerSpEL.deserializerSupportsHeaders());
- return super.deserialize(topic, data);
+ throw new UnsupportedOperationException(
+ "Expected deserialize(String, Headers, byte[]) to be called");
}
@Override
public Long deserialize(String topic, Headers headers, byte[] data) {
- // Overriding the default should trigger header evaluation and this to
be called.
- assertEquals(true, ConsumerSpEL.deserializerSupportsHeaders());
return super.deserialize(topic, data);
}
}
@@ -2082,12 +2073,6 @@ public class KafkaIOTest {
// It is not feasible to test such retries with direct runner. When
DoFnTester supports
// state, we can test ExactlyOnceWriter DoFn directly to ensure it handles
retries correctly.
- if (!ProducerSpEL.supportsTransactions()) {
- LOG.warn(
- "testExactlyOnceSink() is disabled as Kafka client version does not
support transactions.");
- return;
- }
-
int numElements = 1000;
try (MockProducerWrapper producerWrapper = new MockProducerWrapper(new
LongSerializer())) {
@@ -2125,13 +2110,6 @@ public class KafkaIOTest {
@Test
public void testExactlyOnceSinkWithSendException() throws Throwable {
-
- if (!ProducerSpEL.supportsTransactions()) {
- LOG.warn(
- "testExactlyOnceSink() is disabled as Kafka client version does not
support transactions.");
- return;
- }
-
thrown.expect(KafkaException.class);
thrown.expectMessage("fakeException");
@@ -2201,9 +2179,6 @@ public class KafkaIOTest {
@Test
public void testUnboundedSourceStartReadTime() {
-
- assumeTrue(ConsumerSpEL.hasOffsetsForTimes());
-
int numElements = 1000;
// In this MockConsumer, we let the elements of the time and offset equal
and there are 20
// partitions. So set this startTime can read half elements.
@@ -2278,9 +2253,6 @@ public class KafkaIOTest {
@Test
public void testUnboundedSourceStartReadTimeException() {
-
- assumeTrue(ConsumerSpEL.hasOffsetsForTimes());
-
noMessagesException.expect(RuntimeException.class);
int numElements = 1000;
diff --git
a/sdks/java/io/kafka/src/test/java/org/apache/beam/sdk/io/kafka/KafkaRecordCoderTest.java
b/sdks/java/io/kafka/src/test/java/org/apache/beam/sdk/io/kafka/KafkaRecordCoderTest.java
index 84d8cedb895..50a5abddbdb 100644
---
a/sdks/java/io/kafka/src/test/java/org/apache/beam/sdk/io/kafka/KafkaRecordCoderTest.java
+++
b/sdks/java/io/kafka/src/test/java/org/apache/beam/sdk/io/kafka/KafkaRecordCoderTest.java
@@ -26,7 +26,6 @@ import java.nio.charset.StandardCharsets;
import org.apache.beam.sdk.coders.StringUtf8Coder;
import org.apache.beam.sdk.testing.CoderProperties;
import org.apache.beam.sdk.transforms.windowing.GlobalWindow;
-import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.common.header.Headers;
import org.apache.kafka.common.header.internals.RecordHeaders;
import org.junit.Test;
@@ -51,8 +50,7 @@ public class KafkaRecordCoderTest {
@Test
public void testKafkaRecordSerializableWithoutHeaders() throws IOException {
- ConsumerRecord<String, String> consumerRecord = new ConsumerRecord<>("",
0, 0L, "", "");
- verifySerialization(consumerRecord.headers());
+ verifySerialization(new RecordHeaders());
}
@Test
diff --git
a/sdks/java/io/kafka/src/test/java/org/apache/beam/sdk/io/kafka/ProducerRecordCoderTest.java
b/sdks/java/io/kafka/src/test/java/org/apache/beam/sdk/io/kafka/ProducerRecordCoderTest.java
index 6bc3fbaf02a..47a3a5c3c4c 100644
---
a/sdks/java/io/kafka/src/test/java/org/apache/beam/sdk/io/kafka/ProducerRecordCoderTest.java
+++
b/sdks/java/io/kafka/src/test/java/org/apache/beam/sdk/io/kafka/ProducerRecordCoderTest.java
@@ -20,7 +20,6 @@ package org.apache.beam.sdk.io.kafka;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
-import static org.mockito.Mockito.mockStatic;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -29,14 +28,12 @@ import org.apache.beam.sdk.coders.ByteArrayCoder;
import org.apache.beam.sdk.coders.StringUtf8Coder;
import org.apache.beam.sdk.testing.CoderProperties;
import org.apache.beam.sdk.transforms.windowing.GlobalWindow;
-import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.header.Headers;
import org.apache.kafka.common.header.internals.RecordHeaders;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import org.mockito.MockedStatic;
/** Tests for {@link ProducerRecordCoder}. */
@RunWith(JUnit4.class)
@@ -56,8 +53,7 @@ public class ProducerRecordCoderTest {
@Test
public void testProducerRecordSerializableWithoutHeaders() throws
IOException {
- ConsumerRecord<String, String> consumerRecord = new ConsumerRecord<>("",
0, 0L, "", "");
- verifySerialization(consumerRecord.headers(), 0,
System.currentTimeMillis());
+ verifySerialization(new RecordHeaders(), 0, System.currentTimeMillis());
}
@Test
@@ -102,24 +98,6 @@ public class ProducerRecordCoderTest {
assertEquals(testProducerRecord.headers(), headers);
}
- @Test
- public void testProducerRecordStructuralValueWithoutHeadersApi() throws
IOException {
- RecordHeaders headers = new RecordHeaders();
- headers.add("headerKey", "headerVal".getBytes(UTF_8));
- ProducerRecordCoder<byte[], byte[]> producerRecordCoder =
- ProducerRecordCoder.of(ByteArrayCoder.of(), ByteArrayCoder.of());
- ProducerRecord<byte[], byte[]> producerRecord =
- new ProducerRecord<>(
- "topic", 1, null, "key".getBytes(UTF_8), "value".getBytes(UTF_8),
headers);
- try (MockedStatic<ConsumerSpEL> staticMock =
mockStatic(ConsumerSpEL.class)) {
- staticMock.when(ConsumerSpEL::hasHeaders).thenReturn(false);
- ProducerRecord<byte[], byte[]> testProducerRecord =
- (ProducerRecord<byte[], byte[]>)
producerRecordCoder.structuralValue(producerRecord);
-
- assertEquals(testProducerRecord.headers(), new RecordHeaders());
- }
- }
-
private ProducerRecord<String, String> verifySerialization(Integer
partition, Long timestamp)
throws IOException {
return verifySerialization(null, partition, timestamp);