Skip to content

Commit 2631db7

Browse files
committed
[FLINK-34996][Connectors/Kafka] Allow custom Serializer/Deserializer initialization and remove mockito.
1 parent 68da758 commit 2631db7

File tree

6 files changed

+131
-108
lines changed

6 files changed

+131
-108
lines changed

flink-connector-kafka/src/main/java/org/apache/flink/connector/kafka/sink/KafkaSerializerWrapper.java

+18-6
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,10 @@ class KafkaSerializerWrapper<IN> implements SerializationSchema<IN> {
6464
@SuppressWarnings("unchecked")
6565
@Override
6666
public void open(InitializationContext context) throws Exception {
67-
final ClassLoader userCodeClassLoader = context.getUserCodeClassLoader().asClassLoader();
67+
final ClassLoader userCodeClassLoader = selectClassLoader(context);
6868
try (TemporaryClassLoaderContext ignored =
6969
TemporaryClassLoaderContext.of(userCodeClassLoader)) {
70-
serializer =
71-
InstantiationUtil.instantiate(
72-
serializerClass.getName(),
73-
Serializer.class,
74-
userCodeClassLoader);
70+
initializeSerializer(userCodeClassLoader);
7571

7672
if (serializer instanceof Configurable) {
7773
((Configurable) serializer).configure(config);
@@ -88,4 +84,20 @@ public byte[] serialize(IN element) {
8884
checkState(serializer != null, "Call open() once before trying to serialize elements.");
8985
return serializer.serialize(topicSelector.apply(element), element);
9086
}
87+
88+
/**
89+
* Selects the class loader to be used when instantiating the serializer.
90+
* Using a class loader with user code allows users to customize the serializer.
91+
*/
92+
protected ClassLoader selectClassLoader(InitializationContext context) {
93+
return context.getUserCodeClassLoader().asClassLoader();
94+
}
95+
96+
protected void initializeSerializer(ClassLoader classLoader) throws Exception {
97+
serializer =
98+
InstantiationUtil.instantiate(
99+
serializerClass.getName(),
100+
Serializer.class,
101+
classLoader);
102+
}
91103
}

flink-connector-kafka/src/main/java/org/apache/flink/connector/kafka/source/reader/deserializer/KafkaValueOnlyDeserializerWrapper.java

+19-7
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,10 @@ class KafkaValueOnlyDeserializerWrapper<T> implements KafkaRecordDeserialization
5757
@Override
5858
@SuppressWarnings("unchecked")
5959
public void open(DeserializationSchema.InitializationContext context) throws Exception {
60-
ClassLoader userCodeClassLoader = context.getUserCodeClassLoader().asClassLoader();
60+
ClassLoader userCodeClassLoader = selectClassLoader(context);
6161
try (TemporaryClassLoaderContext ignored =
6262
TemporaryClassLoaderContext.of(userCodeClassLoader)) {
63-
deserializer =
64-
(Deserializer<T>)
65-
InstantiationUtil.instantiate(
66-
deserializerClass.getName(),
67-
Deserializer.class,
68-
userCodeClassLoader);
63+
initializeDeserializer(userCodeClassLoader);
6964

7065
if (deserializer instanceof Configurable) {
7166
((Configurable) deserializer).configure(config);
@@ -103,4 +98,21 @@ public void deserialize(ConsumerRecord<byte[], byte[]> record, Collector<T> coll
10398
public TypeInformation<T> getProducedType() {
10499
return TypeExtractor.createTypeInfo(Deserializer.class, deserializerClass, 0, null, null);
105100
}
101+
102+
/**
103+
* Selects the class loader to be used when instantiating the deserializer.
104+
* Using a class loader with user code allows users to customize the deserializer.
105+
*/
106+
protected ClassLoader selectClassLoader(DeserializationSchema.InitializationContext context) {
107+
return context.getUserCodeClassLoader().asClassLoader();
108+
}
109+
110+
protected void initializeDeserializer(ClassLoader classLoader) throws Exception {
111+
deserializer =
112+
(Deserializer<T>)
113+
InstantiationUtil.instantiate(
114+
deserializerClass.getName(),
115+
Deserializer.class,
116+
classLoader);
117+
}
106118
}
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,58 @@
11
package org.apache.flink.connector.kafka.sink;
22

3-
import org.apache.flink.streaming.connectors.kafka.testutils.SerializationTestBase;
3+
import org.apache.flink.api.common.serialization.SerializationSchema;
4+
import org.apache.flink.metrics.MetricGroup;
5+
import org.apache.flink.metrics.groups.UnregisteredMetricsGroup;
6+
import org.apache.flink.util.FlinkUserCodeClassLoaders;
7+
import org.apache.flink.util.SimpleUserCodeClassLoader;
8+
import org.apache.flink.util.UserCodeClassLoader;
9+
410
import org.apache.kafka.common.serialization.StringSerializer;
511
import org.junit.Test;
6-
import org.junit.runner.RunWith;
7-
import org.mockito.junit.MockitoJUnitRunner;
812

9-
import static org.mockito.Mockito.when;
13+
import java.net.URL;
1014

11-
@RunWith(MockitoJUnitRunner.class)
12-
public class KafkaSerializerWrapperTest extends SerializationTestBase {
13-
@Override
14-
protected void setupContext() {
15-
when(serializationContext.getUserCodeClassLoader()).thenReturn(userCodeClassLoader);
16-
}
15+
import static org.junit.Assert.assertEquals;
1716

17+
/**
18+
* Tests for {@link KafkaSerializerWrapper}.
19+
*/
20+
public class KafkaSerializerWrapperTest {
1821
@Test
1922
public void testUserCodeClassLoaderIsUsed() throws Exception {
20-
final KafkaSerializerWrapper<String> wrapper =
21-
new KafkaSerializerWrapper<>(StringSerializer.class, true, (value) -> "topic");
23+
final KafkaSerializerWrapperCaptureForTest wrapper = new KafkaSerializerWrapperCaptureForTest();
24+
final ClassLoader classLoader = FlinkUserCodeClassLoaders.childFirst(
25+
new URL[0], getClass().getClassLoader(), new String[0], throwable -> {}, true);
26+
wrapper.open(new SerializationSchema.InitializationContext() {
27+
@Override
28+
public MetricGroup getMetricGroup() {
29+
return new UnregisteredMetricsGroup();
30+
}
31+
32+
@Override
33+
public UserCodeClassLoader getUserCodeClassLoader() {
34+
return SimpleUserCodeClassLoader.create(classLoader);
35+
}
36+
});
37+
38+
assertEquals(classLoader, wrapper.getClassLoaderUsed());
39+
}
40+
41+
static class KafkaSerializerWrapperCaptureForTest extends KafkaSerializerWrapper<String> {
42+
private ClassLoader classLoaderUsed;
43+
44+
KafkaSerializerWrapperCaptureForTest() {
45+
super(StringSerializer.class, true, (value) -> "topic");
46+
}
47+
48+
public ClassLoader getClassLoaderUsed() {
49+
return classLoaderUsed;
50+
}
2251

23-
testUserClassLoaderIsUsedWhen(() -> {
24-
wrapper.open(serializationContext);
25-
return null;
26-
}, new StringSerializer());
52+
@Override
53+
protected void initializeSerializer(ClassLoader classLoader) throws Exception {
54+
classLoaderUsed = classLoader;
55+
super.initializeSerializer(classLoader);
56+
}
2757
}
2858
}
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,60 @@
11
package org.apache.flink.connector.kafka.source.reader.deserializer;
22

3-
import org.apache.flink.streaming.connectors.kafka.testutils.SerializationTestBase;
3+
import org.apache.flink.api.common.serialization.DeserializationSchema;
4+
import org.apache.flink.metrics.MetricGroup;
5+
import org.apache.flink.metrics.groups.UnregisteredMetricsGroup;
6+
import org.apache.flink.util.FlinkUserCodeClassLoaders;
7+
import org.apache.flink.util.SimpleUserCodeClassLoader;
8+
import org.apache.flink.util.UserCodeClassLoader;
9+
410
import org.apache.kafka.common.serialization.StringDeserializer;
511
import org.junit.Test;
6-
import org.junit.runner.RunWith;
7-
import org.mockito.junit.MockitoJUnitRunner;
812

13+
import java.net.URL;
914
import java.util.HashMap;
10-
import java.util.Map;
11-
12-
import static org.mockito.Mockito.when;
1315

14-
@RunWith(MockitoJUnitRunner.class)
15-
public class KafkaValueOnlyDeserializerWrapperTest extends SerializationTestBase {
16-
@Override
17-
protected void setupContext() {
18-
when(deserializationContext.getUserCodeClassLoader()).thenReturn(userCodeClassLoader);
19-
}
16+
import static org.junit.Assert.assertEquals;
2017

18+
/**
19+
* Tests for {@link KafkaValueOnlyDeserializerWrapper}.
20+
*/
21+
public class KafkaValueOnlyDeserializerWrapperTest {
2122
@Test
2223
public void testUserCodeClassLoaderIsUsed() throws Exception {
23-
final Map<String, String> config = new HashMap<>();
24-
final KafkaValueOnlyDeserializerWrapper<String> wrapper =
25-
new KafkaValueOnlyDeserializerWrapper<>(StringDeserializer.class, config);
26-
27-
testUserClassLoaderIsUsedWhen(() -> {
28-
wrapper.open(deserializationContext);
29-
return null;
30-
}, new StringDeserializer());
24+
final KafkaValueOnlyDeserializerWrapperCaptureForTest wrapper =
25+
new KafkaValueOnlyDeserializerWrapperCaptureForTest();
26+
final ClassLoader classLoader = FlinkUserCodeClassLoaders.childFirst(
27+
new URL[0], getClass().getClassLoader(), new String[0], throwable -> {}, true);
28+
wrapper.open(new DeserializationSchema.InitializationContext() {
29+
@Override
30+
public MetricGroup getMetricGroup() {
31+
return new UnregisteredMetricsGroup();
32+
}
33+
34+
@Override
35+
public UserCodeClassLoader getUserCodeClassLoader() {
36+
return SimpleUserCodeClassLoader.create(classLoader);
37+
}
38+
});
39+
40+
assertEquals(classLoader, wrapper.getClassLoaderUsed());
41+
}
42+
43+
static class KafkaValueOnlyDeserializerWrapperCaptureForTest extends KafkaValueOnlyDeserializerWrapper<String> {
44+
private ClassLoader classLoaderUsed;
45+
46+
KafkaValueOnlyDeserializerWrapperCaptureForTest() {
47+
super(StringDeserializer.class, new HashMap<>());
48+
}
49+
50+
public ClassLoader getClassLoaderUsed() {
51+
return classLoaderUsed;
52+
}
53+
54+
@Override
55+
protected void initializeDeserializer(ClassLoader classLoader) throws Exception {
56+
classLoaderUsed = classLoader;
57+
super.initializeDeserializer(classLoader);
58+
}
3159
}
3260
}

flink-connector-kafka/src/test/java/org/apache/flink/streaming/connectors/kafka/testutils/SerializationTestBase.java

-58
This file was deleted.

flink-connector-kafka/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker

-1
This file was deleted.

0 commit comments

Comments
 (0)