3

I have two contracts (interfaces) both have default method with same name but different return type.

I have to create a Class which should implement both the contract. If I am trying to do it then it is giving me the compilation error.

I can't change the default method of Cotract1 as many classes are implementing Contract1 and the same with Contract2.

Is there anyway by which I can write the class which should have the implementation of both the interfaces, without changing anything in the interface.

Below is the piece of code:

interface Contract1 {
    default String getVersion() {
       return "Beta_10.2.3";
    }
    //....
}
interface Contract2 {
    default Double getVersion() {
        return 11.2;
    }
    //....
}
public class ContractsImplementation implements Contract1, Contract2{

}
Mark
  • 5,994
  • 5
  • 42
  • 55
Sanjay Madnani
  • 803
  • 7
  • 16
  • Method signature doesn't include the return type, so invoking `getVersion` is ambiguous. – zlakad Oct 17 '18 at 06:29
  • 1
    Suppose you could do that. Which method would you expect `ContractsImplementation c = new ContractsImplementation (); c.getVersion()` to call? – Eran Oct 17 '18 at 06:29
  • I don't want any of the default method in my ContractsImplementation class. Even if I have to override the getVersion() method then I'll return null – Sanjay Madnani Oct 17 '18 at 06:31
  • Its not just ambiguous for java, its also ambiguous for the caller of the getVersion() . You could define two methods within the class and have the implementations of the contracts provided via constructor or a setter. You could then delegate the calls to the interface implementation. – kishore Oct 17 '18 at 06:34
  • What does the compilation error say? – khelwood Oct 17 '18 at 06:35
  • 1
    I don't think it is possible to implement both of the interfaces this way. Is it possible to wrap one of the interfaces into another? Like a contract3 interface wich implements contract2 and calls this by default in an other method? – MPhil Oct 17 '18 at 06:36
  • 1
    Possible duplicate of [Java - Method name collision in interface implementation](https://stackoverflow.com/questions/2598009/java-method-name-collision-in-interface-implementation) – Alex Taylor Oct 17 '18 at 06:36
  • 1
    @Kishore I agree with you. But at this point I can't change `Contract1` and `Contract2` interfaces as many classes are using it. Also the purpose of `ContractsImplementation` class is to implement all abstract methods of `Contract1` and `Contract2`. There is no use of `getVersion()` method in `ContractsImplementation` class as we are not going to use it. – Sanjay Madnani Oct 17 '18 at 06:47
  • 2
    @Pshemo But it doesn't change the fact that Java considers such methods with different return types as having the same signature. Also, if I have a variable of type `ContractsImplementation`, and i called `getVersion()` method, then what return type should the compiler assume at compile-time? Of course, these *can* be solved if the designers way back thought this out *very very* well, but it's too hard to change this now. – Jai Oct 17 '18 at 06:56
  • @Jai Oops, you are right. Don't know why I included return type in method signature. Comment removed. – Pshemo Oct 17 '18 at 07:03
  • 1
    @Mphil I Can't wrap `Contract1` into `Contract2` or vise versa as it will impact on other implementation classes of `Contract1` and `Contract2`. If I create `Contract3` by extending `Contract1` and `Contract2` then also the same issue is occurring by default method. – Sanjay Madnani Oct 17 '18 at 07:20
  • 2
    @Pshemo well, on the bytecode level, the return type is part of the method signature, so you could solve this problem when using a different JVM language. However, for the Java programming language, there is no solution. – Holger Oct 17 '18 at 08:03

1 Answers1

4

Suggestion:

Sanjay, if you do not want to have any default methods in your class like you said, use composition over inheritance.

interface Contract1 {
   default String getVersion() {
      return "Beta_10.2.3";
   }
   //....
}
interface Contract2 {
    default Double getVersion() {
        return 11.2;
    }
    //....
}
public class ContractsImp {

    private class Contract1Imp implements Contract1 {}
    private class Contract2Imp implements Contract2 {}

    private Contract1 contract1 = new Contract1Imp();
    private Contract2 contract2 = new Contract2Imp();
    // Here you can do with contracts whatever you want
    // ...
}
Mark
  • 5,994
  • 5
  • 42
  • 55
  • 1
    This solution looks good but only the problem I'll face is that I will not be able to use `Contract1` or `Contract2` ref to hold `ContractsImp` object: `Contract1 obj = new ContractsImp () ` – Sanjay Madnani Oct 17 '18 at 09:35