4

I am creating a java library that will access web services, but the library will be called in different platforms, so we are using ksoap2 and ksoap2-android to generate helper classes for the different platforms. The problem is that we then have two sets of generated classes/methods whose signatures are equivalent, but which do not overtly share a Java Interface - so I can't figure a way to call them from my main code.

A simplified example:

//generated for Android
class A {
  public String sayHi() {
    return "Hi A";
  }
}

//generated for j2se
class B {
  public String sayHi() {
    return "Hi B";
  }
}

//main code - don't know how to do this
XXX talker = TalkerFactory.getInstance()
String greeting = talker.sayHi()

Of course, that last part is pseudo-code. Specifically, how can I call sayHi() on an instance of an object which I don't know the type of at compile time, and which does not conform to a specific interface? My hope is that there is some way to do this without hand editing all of the generated classes to add an "implements iTalker".

Mike Hedman
  • 1,391
  • 1
  • 11
  • 30

1 Answers1

9

The straightforward way is to use an adapter.

interface Hi {
    void sayHi();
}

public static Hi asHi(final A target) {
    return new Hi() { public void sayHi() { // More concise from Java SE 8...
        target.sayHi();
    }};
}
public static Hi asHi(final B target) {
    return new Hi() { public void sayHi() { // More concise from Java SE 8...
        target.sayHi();
    }};
}

In some circumstance it may be possible, but probably a bad idea and certainly less flexible, to subclass and add in the interface.

public class HiA extends A implements Hi {
}
public class HiB extends B implements Hi {
}
Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • He specifically asked: "Is there some way to do this without hand editing all of the generated classes ?" – Nir Alfasi May 30 '13 at 18:59
  • @OliCharlesworth no they aren't indeed - but there's manual work that needs to be done for each class - there's no way to avoid it, and I think that that's something that should be emphasized. – Nir Alfasi May 30 '13 at 19:02
  • @OliCharlesworth `at`alfasin Well, the second piece I added later doesn't work if you only have access to already constructed instances. – Tom Hawtin - tackline May 30 '13 at 19:02
  • If someone suggests reflection I'll get angry. :) – Tom Hawtin - tackline May 30 '13 at 19:03
  • @TomHawtin-tackline: Oh I just did in a comment to the original question :( – Oliver Charlesworth May 30 '13 at 19:03
  • @OliCharlesworth - it does work, I've just hacked up an example, and it does work. – Mike Hedman May 30 '13 at 19:06
  • @TomHawtin-tackline - Tom, why do you say it's less flexible? I have to write the interface for each generated class, but that's OK, since I would only have to expose the methods that I call. I guess I should also ask, why is this a "bad idea"? Thanks – Mike Hedman May 30 '13 at 19:08
  • @OliCharlesworth - here's what I did: `public interface Talker { public String sayHi(); } class A { public String sayHi() { return "Hi A"; } } class B { public String sayHi() { return "Hi B"; } } class HiA extends A implements Talker {} class HiB extends B implements Talker {}` then in a junit test: `HiA a = new HiA(); assertEquals("Hi A", a.sayHi());` – Mike Hedman May 30 '13 at 19:10
  • @MikeHedman If `TalkerFactory.getInstance()` has a return type of, say, `A` (or you cast - eurgh), then you can't use `HiA` without going in and changing the implementation of `getInstance` which may not be available to you. – Tom Hawtin - tackline May 30 '13 at 20:01
  • @TomHawtin-tackline - The good news is that I "get" to write the factory myself, so it will be able to return objects which are instances of the correct object, and which implement the requested interface. So my factory would have methods like `TalkerFactory.getTalker()`, which has a specified return type of Talker, and for android would return an instance of HiA. Actually looking at what I typed earlier, the proper unit test example would be: `Talker a = new HiA(); assertEquals("Hi A", a.sayHi());' In my real code, instead of newing the HiA, the factory would return it. Thanks – Mike Hedman May 30 '13 at 21:42