diff --git a/samza-api/src/main/java/org/apache/samza/application/StreamApplication.java b/samza-api/src/main/java/org/apache/samza/application/StreamApplication.java
index eeece1007f89a..a26c5af7f38d0 100644
--- a/samza-api/src/main/java/org/apache/samza/application/StreamApplication.java
+++ b/samza-api/src/main/java/org/apache/samza/application/StreamApplication.java
@@ -24,11 +24,43 @@
/**
- * This interface defines a template for stream application that user will implement to create operator DAG in {@link StreamGraph}.
+ * This interface defines a template for stream application that user will implement to initialize operator DAG in {@link StreamGraph}.
+ *
+ *
+ * User program implements {@link StreamApplication#init(StreamGraph, Config)} method to initialize the transformation logic
+ * from all input streams to output streams. A simple user code example is shown below:
+ *
+ *
+ * {@code
+ * public class PageViewCounterExample implements StreamApplication {
+ * // max timeout is 60 seconds
+ * private static final MAX_TIMEOUT = 60000;
+ *
+ * public void init(StreamGraph graph, Config config) {
+ * MessageStream pageViewEvents = graph.getInputStream("pageViewEventStream", (k, m) -> (PageViewEvent) m);
+ * OutputStream pageViewEventFilteredStream = graph
+ * .getOutputStream("pageViewEventFiltered", m -> m.memberId, m -> m);
+ *
+ * pageViewEvents
+ * .filter(m -> !(m.getMessage().getEventTime() < System.currentTimeMillis() - MAX_TIMEOUT))
+ * .sendTo(pageViewEventFilteredStream);
+ * }
+ *
+ * // local execution mode
+ * public static void main(String[] args) {
+ * CommandLine cmdLine = new CommandLine();
+ * Config config = cmdLine.loadConfig(cmdLine.parser().parse(args));
+ * PageViewCounterExample userApp = new PageViewCounterExample();
+ * ApplicationRunner localRunner = ApplicationRunner.getLocalRunner(config);
+ * localRunner.run(userApp);
+ * }
+ *
+ * }
+ * }
+ *
*/
@InterfaceStability.Unstable
public interface StreamApplication {
- static final String APP_CLASS_CONFIG = "app.class";
/**
* Users are required to implement this abstract method to initialize the processing logic of the application, in terms
@@ -38,4 +70,5 @@ public interface StreamApplication {
* @param config the {@link Config} of the application
*/
void init(StreamGraph graph, Config config);
+
}
diff --git a/samza-api/src/main/java/org/apache/samza/operators/MessageStream.java b/samza-api/src/main/java/org/apache/samza/operators/MessageStream.java
index 345bff02a205a..c406a933e354c 100644
--- a/samza-api/src/main/java/org/apache/samza/operators/MessageStream.java
+++ b/samza-api/src/main/java/org/apache/samza/operators/MessageStream.java
@@ -50,7 +50,7 @@ public interface MessageStream {
* @param the type of messages in the transformed {@link MessageStream}
* @return the transformed {@link MessageStream}
*/
- MessageStream map(MapFunction mapFn);
+ MessageStream map(MapFunction super M, ? extends TM> mapFn);
/**
* Applies the provided 1:n function to transform a message in this {@link MessageStream}
@@ -60,7 +60,7 @@ public interface MessageStream {
* @param the type of messages in the transformed {@link MessageStream}
* @return the transformed {@link MessageStream}
*/
- MessageStream flatMap(FlatMapFunction flatMapFn);
+ MessageStream flatMap(FlatMapFunction super M, ? extends TM> flatMapFn);
/**
* Applies the provided function to messages in this {@link MessageStream} and returns the
@@ -72,7 +72,7 @@ public interface MessageStream {
* @param filterFn the predicate to filter messages from this {@link MessageStream}
* @return the transformed {@link MessageStream}
*/
- MessageStream filter(FilterFunction filterFn);
+ MessageStream filter(FilterFunction super M> filterFn);
/**
* Allows sending messages in this {@link MessageStream} to an output system using the provided {@link SinkFunction}.
@@ -83,7 +83,7 @@ public interface MessageStream {
*
* @param sinkFn the function to send messages in this stream to an external system
*/
- void sink(SinkFunction sinkFn);
+ void sink(SinkFunction super M> sinkFn);
/**
* Allows sending messages in this {@link MessageStream} to an output {@link MessageStream}.
@@ -120,10 +120,10 @@ public interface MessageStream {
* @param ttl the ttl for messages in each stream
* @param the type of join key
* @param the type of messages in the other stream
- * @param the type of messages resulting from the {@code joinFn}
+ * @param the type of messages resulting from the {@code joinFn}
* @return the joined {@link MessageStream}
*/
- MessageStream join(MessageStream otherStream, JoinFunction joinFn, Duration ttl);
+ MessageStream join(MessageStream otherStream, JoinFunction extends K, ? super M, ? super OM, ? extends TM> joinFn, Duration ttl);
/**
* Merge all {@code otherStreams} with this {@link MessageStream}.
@@ -133,7 +133,7 @@ public interface MessageStream {
* @param otherStreams other {@link MessageStream}s to be merged with this {@link MessageStream}
* @return the merged {@link MessageStream}
*/
- MessageStream merge(Collection> otherStreams);
+ MessageStream merge(Collection> otherStreams);
/**
* Sends the messages of type {@code M}in this {@link MessageStream} to a repartitioned output stream and consumes
@@ -144,6 +144,6 @@ public interface MessageStream {
* @param the type of output message key and partition key
* @return the repartitioned {@link MessageStream}
*/
- MessageStream partitionBy(Function keyExtractor);
+ MessageStream partitionBy(Function super M, ? extends K> keyExtractor);
}
diff --git a/samza-api/src/main/java/org/apache/samza/operators/StreamGraph.java b/samza-api/src/main/java/org/apache/samza/operators/StreamGraph.java
index ff1c58060a163..a03f7c32079c0 100644
--- a/samza-api/src/main/java/org/apache/samza/operators/StreamGraph.java
+++ b/samza-api/src/main/java/org/apache/samza/operators/StreamGraph.java
@@ -40,7 +40,7 @@ public interface StreamGraph {
* @param the type of message in the input {@link MessageStream}
* @return the input {@link MessageStream}
*/
- MessageStream getInputStream(String streamId, BiFunction msgBuilder);
+ MessageStream getInputStream(String streamId, BiFunction super K, ? super V, ? extends M> msgBuilder);
/**
* Gets the {@link OutputStream} corresponding to the logical {@code streamId}.
@@ -54,7 +54,7 @@ public interface StreamGraph {
* @return the output {@link MessageStream}
*/
OutputStream getOutputStream(String streamId,
- Function keyExtractor, Function msgExtractor);
+ Function super M, ? extends K> keyExtractor, Function super M, ? extends V> msgExtractor);
/**
* Sets the {@link ContextManager} for this {@link StreamGraph}.
diff --git a/samza-api/src/main/java/org/apache/samza/operators/windows/Windows.java b/samza-api/src/main/java/org/apache/samza/operators/windows/Windows.java
index 9192fc1890b18..721b4c07389f5 100644
--- a/samza-api/src/main/java/org/apache/samza/operators/windows/Windows.java
+++ b/samza-api/src/main/java/org/apache/samza/operators/windows/Windows.java
@@ -119,11 +119,12 @@ private Windows() { }
* @param the type of the key in the {@link Window}
* @return the created {@link Window} function.
*/
- public static Window keyedTumblingWindow(Function keyFn, Duration interval,
- Supplier initialValue, FoldLeftFunction foldFn) {
+ public static Window keyedTumblingWindow(Function super M, ? extends K> keyFn, Duration interval,
+ Supplier extends WV> initialValue, FoldLeftFunction super M, WV> foldFn) {
Trigger defaultTrigger = new TimeTrigger<>(interval);
- return new WindowInternal(defaultTrigger, initialValue, foldFn, keyFn, null, WindowType.TUMBLING);
+ return new WindowInternal<>(defaultTrigger, (Supplier) initialValue, (FoldLeftFunction) foldFn,
+ (Function) keyFn, null, WindowType.TUMBLING);
}
@@ -147,10 +148,10 @@ public static Window keyedTumblingWindow(Function key
* @param the type of the key in the {@link Window}
* @return the created {@link Window} function
*/
- public static Window> keyedTumblingWindow(Function keyFn, Duration interval) {
+ public static Window> keyedTumblingWindow(Function super M, ? extends K> keyFn, Duration interval) {
FoldLeftFunction> aggregator = createAggregator();
- Supplier> initialValue = () -> new ArrayList<>();
+ Supplier> initialValue = ArrayList::new;
return keyedTumblingWindow(keyFn, interval, initialValue, aggregator);
}
@@ -175,10 +176,11 @@ public static Window> keyedTumblingWindow(Function the type of the {@link WindowPane} output value
* @return the created {@link Window} function
*/
- public static Window tumblingWindow(Duration duration, Supplier initialValue,
- FoldLeftFunction foldFn) {
+ public static Window tumblingWindow(Duration duration, Supplier extends WV> initialValue,
+ FoldLeftFunction super M, WV> foldFn) {
Trigger defaultTrigger = Triggers.repeat(new TimeTrigger<>(duration));
- return new WindowInternal<>(defaultTrigger, initialValue, foldFn, null, null, WindowType.TUMBLING);
+ return new WindowInternal<>(defaultTrigger, (Supplier) initialValue, (FoldLeftFunction) foldFn,
+ null, null, WindowType.TUMBLING);
}
/**
@@ -203,7 +205,7 @@ public static Window tumblingWindow(Duration duration, Supp
public static Window> tumblingWindow(Duration duration) {
FoldLeftFunction> aggregator = createAggregator();
- Supplier> initialValue = () -> new ArrayList<>();
+ Supplier> initialValue = ArrayList::new;
return tumblingWindow(duration, initialValue, aggregator);
}
@@ -235,10 +237,11 @@ public static Window> tumblingWindow(Duration duratio
* @param the type of the output value in the {@link WindowPane}
* @return the created {@link Window} function
*/
- public static Window keyedSessionWindow(Function keyFn, Duration sessionGap,
- Supplier initialValue, FoldLeftFunction foldFn) {
+ public static Window keyedSessionWindow(Function super M, ? extends K> keyFn, Duration sessionGap,
+ Supplier extends WV> initialValue, FoldLeftFunction super M, WV> foldFn) {
Trigger defaultTrigger = Triggers.timeSinceLastMessage(sessionGap);
- return new WindowInternal<>(defaultTrigger, initialValue, foldFn, keyFn, null, WindowType.SESSION);
+ return new WindowInternal<>(defaultTrigger, (Supplier) initialValue, (FoldLeftFunction) foldFn, (Function) keyFn,
+ null, WindowType.SESSION);
}
/**
@@ -265,11 +268,11 @@ public static Window keyedSessionWindow(Function keyF
* @param the type of the key in the {@link Window}
* @return the created {@link Window} function
*/
- public static Window> keyedSessionWindow(Function keyFn, Duration sessionGap) {
+ public static Window> keyedSessionWindow(Function super M, ? extends K> keyFn, Duration sessionGap) {
FoldLeftFunction> aggregator = createAggregator();
- Supplier> initialValue = () -> new ArrayList<>();
+ Supplier> initialValue = ArrayList::new;
return keyedSessionWindow(keyFn, sessionGap, initialValue, aggregator);
}
diff --git a/samza-api/src/main/java/org/apache/samza/task/TaskContext.java b/samza-api/src/main/java/org/apache/samza/task/TaskContext.java
index 128cff1468e7e..dc5742f641679 100644
--- a/samza-api/src/main/java/org/apache/samza/task/TaskContext.java
+++ b/samza-api/src/main/java/org/apache/samza/task/TaskContext.java
@@ -58,10 +58,9 @@ public interface TaskContext {
/**
* Method to allow user to return customized context
*
- * @param the type of user-defined task context
* @return user-defined task context object
*/
- default T getUserDefinedContext() {
+ default Object getUserDefinedContext() {
return null;
};
}
diff --git a/samza-core/src/main/java/org/apache/samza/config/ApplicationConfig.java b/samza-core/src/main/java/org/apache/samza/config/ApplicationConfig.java
index 1c0073535557e..9eb4161617e70 100644
--- a/samza-core/src/main/java/org/apache/samza/config/ApplicationConfig.java
+++ b/samza-core/src/main/java/org/apache/samza/config/ApplicationConfig.java
@@ -46,6 +46,7 @@ public class ApplicationConfig extends MapConfig {
public static final String APP_COORDINATION_SERVICE_FACTORY_CLASS = "app.coordination.service.factory.class";
public static final String APP_NAME = "app.name";
public static final String APP_ID = "app.id";
+ public static final String APP_CLASS = "app.class";
public ApplicationConfig(Config config) {
super(config);
@@ -67,6 +68,10 @@ public String getAppId() {
return get(APP_ID, get(JobConfig.JOB_ID(), "1"));
}
+ public String getAppClass() {
+ return get(APP_CLASS, null);
+ }
+
@Deprecated
public String getProcessorId() {
return get(PROCESSOR_ID, null);
diff --git a/samza-core/src/main/java/org/apache/samza/operators/MessageStreamImpl.java b/samza-core/src/main/java/org/apache/samza/operators/MessageStreamImpl.java
index dfe231ead6f91..69a41dbd7db6f 100644
--- a/samza-core/src/main/java/org/apache/samza/operators/MessageStreamImpl.java
+++ b/samza-core/src/main/java/org/apache/samza/operators/MessageStreamImpl.java
@@ -72,7 +72,7 @@ public MessageStreamImpl(StreamGraphImpl graph) {
}
@Override
- public MessageStream map(MapFunction mapFn) {
+ public MessageStream map(MapFunction super M, ? extends TM> mapFn) {
OperatorSpec op = OperatorSpecs.createMapOperatorSpec(
mapFn, new MessageStreamImpl<>(this.graph), this.graph.getNextOpId());
this.registeredOperatorSpecs.add(op);
@@ -80,7 +80,7 @@ public MessageStream map(MapFunction mapFn) {
}
@Override
- public MessageStream filter(FilterFunction filterFn) {
+ public MessageStream filter(FilterFunction super M> filterFn) {
OperatorSpec op = OperatorSpecs.createFilterOperatorSpec(
filterFn, new MessageStreamImpl<>(this.graph), this.graph.getNextOpId());
this.registeredOperatorSpecs.add(op);
@@ -88,7 +88,7 @@ public MessageStream filter(FilterFunction filterFn) {
}
@Override
- public MessageStream flatMap(FlatMapFunction flatMapFn) {
+ public MessageStream flatMap(FlatMapFunction super M, ? extends TM> flatMapFn) {
OperatorSpec op = OperatorSpecs.createStreamOperatorSpec(
flatMapFn, new MessageStreamImpl<>(this.graph), this.graph.getNextOpId());
this.registeredOperatorSpecs.add(op);
@@ -96,7 +96,7 @@ public MessageStream flatMap(FlatMapFunction flatMapFn) {
}
@Override
- public void sink(SinkFunction sinkFn) {
+ public void sink(SinkFunction super M> sinkFn) {
SinkOperatorSpec op = OperatorSpecs.createSinkOperatorSpec(sinkFn, this.graph.getNextOpId());
this.registeredOperatorSpecs.add(op);
}
@@ -110,22 +110,22 @@ public void sendTo(OutputStream outputStream) {
@Override
public MessageStream> window(Window window) {
- OperatorSpec> wndOp = OperatorSpecs.createWindowOperatorSpec((WindowInternal) window,
- new MessageStreamImpl<>(this.graph), this.graph.getNextOpId());
+ OperatorSpec> wndOp = OperatorSpecs.createWindowOperatorSpec(
+ (WindowInternal) window, new MessageStreamImpl<>(this.graph), this.graph.getNextOpId());
this.registeredOperatorSpecs.add(wndOp);
return wndOp.getNextStream();
}
@Override
- public MessageStream join(
- MessageStream otherStream, JoinFunction joinFn, Duration ttl) {
- MessageStreamImpl nextStream = new MessageStreamImpl<>(this.graph);
+ public MessageStream join(
+ MessageStream otherStream, JoinFunction extends K, ? super M, ? super OM, ? extends TM> joinFn, Duration ttl) {
+ MessageStreamImpl nextStream = new MessageStreamImpl<>(this.graph);
- PartialJoinFunction thisPartialJoinFn = new PartialJoinFunction() {
- private KeyValueStore> thisStreamState;
+ PartialJoinFunction thisPartialJoinFn = new PartialJoinFunction() {
+ private KeyValueStore> thisStreamState;
@Override
- public RM apply(M m, JM jm) {
+ public TM apply(M m, OM jm) {
return joinFn.apply(m, jm);
}
@@ -148,21 +148,21 @@ public void init(Config config, TaskContext context) {
}
};
- PartialJoinFunction otherPartialJoinFn = new PartialJoinFunction() {
- private KeyValueStore> otherStreamState;
+ PartialJoinFunction otherPartialJoinFn = new PartialJoinFunction() {
+ private KeyValueStore> otherStreamState;
@Override
- public RM apply(JM om, M m) {
+ public TM apply(OM om, M m) {
return joinFn.apply(m, om);
}
@Override
- public K getKey(JM message) {
+ public K getKey(OM message) {
return joinFn.getSecondKey(message);
}
@Override
- public KeyValueStore> getState() {
+ public KeyValueStore> getState() {
return otherStreamState;
}
@@ -175,7 +175,7 @@ public void init(Config config, TaskContext taskContext) {
this.registeredOperatorSpecs.add(OperatorSpecs.createPartialJoinOperatorSpec(
thisPartialJoinFn, otherPartialJoinFn, ttl.toMillis(), nextStream, this.graph.getNextOpId()));
- ((MessageStreamImpl) otherStream).registeredOperatorSpecs
+ ((MessageStreamImpl) otherStream).registeredOperatorSpecs
.add(OperatorSpecs.createPartialJoinOperatorSpec(
otherPartialJoinFn, thisPartialJoinFn, ttl.toMillis(), nextStream, this.graph.getNextOpId()));
@@ -183,7 +183,7 @@ public void init(Config config, TaskContext taskContext) {
}
@Override
- public MessageStream merge(Collection> otherStreams) {
+ public MessageStream merge(Collection> otherStreams) {
MessageStreamImpl nextStream = new MessageStreamImpl<>(this.graph);
otherStreams.add(this);
@@ -193,7 +193,7 @@ public MessageStream merge(Collection> otherStreams) {
}
@Override
- public MessageStream partitionBy(Function keyExtractor) {
+ public MessageStream partitionBy(Function super M, ? extends K> keyExtractor) {
int opId = this.graph.getNextOpId();
String opName = String.format("%s-%s", OperatorSpec.OpCode.PARTITION_BY.name().toLowerCase(), opId);
MessageStreamImpl intermediateStream =
diff --git a/samza-core/src/main/java/org/apache/samza/operators/StreamGraphImpl.java b/samza-core/src/main/java/org/apache/samza/operators/StreamGraphImpl.java
index a49b68ebd2551..86ce6a4868eba 100644
--- a/samza-core/src/main/java/org/apache/samza/operators/StreamGraphImpl.java
+++ b/samza-core/src/main/java/org/apache/samza/operators/StreamGraphImpl.java
@@ -61,16 +61,25 @@ public StreamGraphImpl(ApplicationRunner runner, Config config) {
}
@Override
- public MessageStream getInputStream(String streamId, BiFunction msgBuilder) {
+ public MessageStream getInputStream(String streamId, BiFunction super K, ? super V, ? extends M> msgBuilder) {
+ if (msgBuilder == null) {
+ throw new IllegalArgumentException("msgBuilder can't be null for an input stream");
+ }
return inStreams.computeIfAbsent(runner.getStreamSpec(streamId),
- streamSpec -> new InputStreamInternalImpl<>(this, streamSpec, msgBuilder));
+ streamSpec -> new InputStreamInternalImpl<>(this, streamSpec, (BiFunction) msgBuilder));
}
@Override
public OutputStream getOutputStream(String streamId,
- Function keyExtractor, Function msgExtractor) {
+ Function super M, ? extends K> keyExtractor, Function super M, ? extends V> msgExtractor) {
+ if (keyExtractor == null) {
+ throw new IllegalArgumentException("keyExtractor can't be null for an output stream.");
+ }
+ if (msgExtractor == null) {
+ throw new IllegalArgumentException("msgExtractor can't be null for an output stream.");
+ }
return outStreams.computeIfAbsent(runner.getStreamSpec(streamId),
- streamSpec -> new OutputStreamInternalImpl<>(this, streamSpec, keyExtractor, msgExtractor));
+ streamSpec -> new OutputStreamInternalImpl<>(this, streamSpec, (Function) keyExtractor, (Function) msgExtractor));
}
@Override
@@ -95,16 +104,28 @@ public StreamGraph withContextManager(ContextManager contextManager) {
* @return the intermediate {@link MessageStreamImpl}
*/
MessageStreamImpl getIntermediateStream(String streamName,
- Function keyExtractor, Function msgExtractor, BiFunction msgBuilder) {
+ Function super M, ? extends K> keyExtractor, Function super M, ? extends V> msgExtractor, BiFunction super K, ? super V, ? extends M> msgBuilder) {
String streamId = String.format("%s-%s-%s",
config.get(JobConfig.JOB_NAME()),
config.get(JobConfig.JOB_ID(), "1"),
streamName);
+ if (msgBuilder == null) {
+ throw new IllegalArgumentException("msgBuilder cannot be null for an intermediate stream");
+ }
+
+ if (keyExtractor == null) {
+ throw new IllegalArgumentException("keyExtractor can't be null for an output stream.");
+ }
+ if (msgExtractor == null) {
+ throw new IllegalArgumentException("msgExtractor can't be null for an output stream.");
+ }
+
StreamSpec streamSpec = runner.getStreamSpec(streamId);
IntermediateStreamInternalImpl intStream =
(IntermediateStreamInternalImpl) inStreams
.computeIfAbsent(streamSpec,
- k -> new IntermediateStreamInternalImpl<>(this, streamSpec, keyExtractor, msgExtractor, msgBuilder));
+ k -> new IntermediateStreamInternalImpl<>(this, streamSpec, (Function) keyExtractor,
+ (Function) msgExtractor, (BiFunction) msgBuilder));
outStreams.putIfAbsent(streamSpec, intStream);
return intStream;
}
diff --git a/samza-core/src/main/java/org/apache/samza/operators/spec/OperatorSpecs.java b/samza-core/src/main/java/org/apache/samza/operators/spec/OperatorSpecs.java
index e2c4b9aeb94d3..0b93bbe1c1ad0 100644
--- a/samza-core/src/main/java/org/apache/samza/operators/spec/OperatorSpecs.java
+++ b/samza-core/src/main/java/org/apache/samza/operators/spec/OperatorSpecs.java
@@ -53,7 +53,7 @@ private OperatorSpecs() {}
* @return the {@link StreamOperatorSpec}
*/
public static StreamOperatorSpec createMapOperatorSpec(
- MapFunction mapFn, MessageStreamImpl nextStream, int opId) {
+ MapFunction super M, ? extends OM> mapFn, MessageStreamImpl nextStream, int opId) {
return new StreamOperatorSpec<>(new FlatMapFunction() {
@Override
public Collection apply(M message) {
@@ -84,7 +84,7 @@ public void init(Config config, TaskContext context) {
* @return the {@link StreamOperatorSpec}
*/
public static StreamOperatorSpec createFilterOperatorSpec(
- FilterFunction filterFn, MessageStreamImpl nextStream, int opId) {
+ FilterFunction super M> filterFn, MessageStreamImpl nextStream, int opId) {
return new StreamOperatorSpec<>(new FlatMapFunction() {
@Override
public Collection apply(M message) {
@@ -115,8 +115,8 @@ public void init(Config config, TaskContext context) {
* @return the {@link StreamOperatorSpec}
*/
public static StreamOperatorSpec createStreamOperatorSpec(
- FlatMapFunction transformFn, MessageStreamImpl nextStream, int opId) {
- return new StreamOperatorSpec<>(transformFn, nextStream, OperatorSpec.OpCode.FLAT_MAP, opId);
+ FlatMapFunction super M, ? extends OM> transformFn, MessageStreamImpl nextStream, int opId) {
+ return new StreamOperatorSpec<>((FlatMapFunction) transformFn, nextStream, OperatorSpec.OpCode.FLAT_MAP, opId);
}
/**
@@ -127,8 +127,8 @@ public static StreamOperatorSpec createStreamOperatorSpec(
* @param type of input message
* @return the {@link SinkOperatorSpec} for the sink operator
*/
- public static SinkOperatorSpec createSinkOperatorSpec(SinkFunction sinkFn, int opId) {
- return new SinkOperatorSpec<>(sinkFn, OperatorSpec.OpCode.SINK, opId);
+ public static SinkOperatorSpec createSinkOperatorSpec(SinkFunction super M> sinkFn, int opId) {
+ return new SinkOperatorSpec<>((SinkFunction) sinkFn, OperatorSpec.OpCode.SINK, opId);
}
/**
@@ -195,7 +195,7 @@ public static WindowOperatorSpec createWindowOperatorSpec
public static PartialJoinOperatorSpec