[
https://issues.apache.org/jira/browse/FLINK-33949?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17800913#comment-17800913
]
Wencong Liu edited comment on FLINK-33949 at 12/28/23 3:45 AM:
---
Suppose we have two completely independent interfaces, I and J, both declaring
a default method M with the same signature. Now, if there is a class T that
implements both interfaces I and J but *does not override* the conflicting
method M, the compiler would not know which interface's default method
implementation to use, as they both have equal priority. If the code containing
class T tries to invoke this method at runtime, the JVM would throw an
{{IncompatibleClassChangeError}} because it is faced with an impossible
decision: it does not know which interface’s default implementation to call.
However, if M is abstract in I or J, the implementation class T *must* provides
an explicit implementation of the method. So no matter how interfaces I or J
change (as long as the signature of their method M does not change), it will
not affect the behavior of the implementation class T or cause an
{{{}IncompatibleClassChangeError{}}}. Class T will continue to use its own
method M implementation, disregarding any default implementations from the two
interfaces.
I have create a test case, where the StreamingRuntimeContext will be added a
method return TestObject:
{code:java}
public class TestObject implements TestInterface1, TestInterface2 {
@Override
public String getResult() {
return "777";
}
}
public interface TestInterface1 {
String getResult();
}
public interface TestInterface2 {
default String getResult() {
return "666";
}
}{code}
The job code is in the follows. The job is compiled with the modifiled
StreamingRuntimeContext in Flink.
{code:java}
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment executionEnvironment =
StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource source =
executionEnvironment.fromData(3, 2, 1, 4, 5, 6, 7, 8);
SingleOutputStreamOperator result = source.map(new
RichMapFunction() {
@Override
public String map(Integer integer) {
StreamingRuntimeContext runtimeContext =
(StreamingRuntimeContext)getRuntimeContext();
return runtimeContext.getTestObject().getResult();
}
});
CloseableIterator jobResult = result.executeAndCollect();
while (jobResult.hasNext())
System.out.println(jobResult.next());
} {code}
When I change the abstract method getResult into default in TestInterface1 and
recompiled Flink. The job is still able to finish without any code changes and
exceptions.
Therefore, I think the METHOD_ABSTRACT_NOW_DEFAULT doesn't break source
compatibility. WDYT? [~martijnvisser]
was (Author: JIRAUSER281639):
Suppose we have two completely independent interfaces, I and J, both declaring
a default method M with the same signature. Now, if there is a class T that
implements both interfaces I and J but *does not override* the conflicting
method M, the compiler would not know which interface's default method
implementation to use, as they both have equal priority. If the code containing
class T tries to invoke this method at runtime, the JVM would throw an
{{IncompatibleClassChangeError}} because it is faced with an impossible
decision: it does not know which interface’s default implementation to call.
However, if M is abstract in I or J, the implementation class T *must* provides
an explicit implementation of the method. So no matter how interfaces I or J
change (as long as the signature of their method M does not change), it will
not affect the behavior of the implementation class T or cause an
{{{}IncompatibleClassChangeError{}}}. Class T will continue to use its own
method M implementation, disregarding any default implementations from the two
interfaces.
I have create a test case, where the StreamingRuntimeContext will be added a
method return TestObject:
{code:java}
public class TestObject implements TestInterface1, TestInterface2 {
@Override
public String getResult() {
return "777";
}
}
public interface TestInterface1 {
String getResult();
}
public interface TestInterface2 {
default String getResult() {
return "666";
}
}{code}
The job code is in the follows. The job is compiled with the modifiled
StreamingRuntimeContext in Flink.
{code:java}
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment executionEnvironment =
StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource source =
executionEnvironment.fromData(3, 2, 1, 4, 5, 6, 7, 8);
SingleOutputStreamOperator result = source.map(new
RichMapFunction() {
@Override
public String map(Integer integer)