views:

156

answers:

2

Hello!

Can I take a foreign class in Java which conforms to one of my custom interfaces and "cast" it to that interface?

Example:

public class YouCanNotChangeMe_IAmNotYours{
    public void doSomethingSpecial();
}

public interface MyInterface{
    void doSomethingSpecial();
}

Can I use that foreign class in places where my interface is expected?

Why do I need this at all?

I want to dynamically reload newer versions of some JAR at runtime, as I've mentioned here.

Now, the server knows all interfaces (knowing the former version of the JAR at compile time). The problem is, after loading classes from newer versions of that JAR at runtime, these "new" classes act as if they don't "know" the compile-time known interface.

Example: An old class, named HelloClass (known at compile time) does implement the interface HelloInterface, but the newly loaded class HelloClass does not implement that same interface!

+1  A: 

You could extend the foreign class (assuming it's non-final) and make that class implement the interface.

Alternatively you could implement your own wrapper around that interface:

public class ForeignClassWrapper implements MyInterface {
  private final YouCanNotChangeMe_IAmNotYours delegate;

  public ForeignClassWrapper(YouCanNotChangeMe_IAmNotYours delegate) {
    this.delegate = delegate;
  }

  public void doSomethingSpecial() {
    delegate.doSomethingSpecial();
  }
}

More generally you could get the same effect using reflection (so you wouldn't need to hardcode YouCanNotChangeMe_IAmNotYours in your wrapper class).

Joachim Sauer
I think it wouldn't to it. I need the whole thing for reloading a JAR.The problem is: after being reloaded, a class "is not itself" anymore. So, subclassing the original class would either have nothing in common with the reloaded class.
ivan_ivanovich_ivanoff
< ...wouldn't DO it...
ivan_ivanovich_ivanoff
If you reload your wrapper class at the same time that the external JAR reloads, and your wrapper class is ABI compatible with both the old class and the new class, then this would work fine.
Guss
@ivan: right, but either reload the wrapper class at the same time or go the reflection-route.
Joachim Sauer
A: 

Unless I'm mistaken, it sounds like you need to rethink your container and ClassLoader design. You're trying to achieve the same sort of functionality that your average servlet container supports, so it might be an idea to look at that for inspiration.

As to the specific problem: instance x of type A is only an instance of class A if x.getClass().getClassLoader() == A.class.getClassLoader(). So, even though two or more objects might be of class A, Java treats them as different types if they have different ClassLoaders.

It sounds like the interface you're trying to cast to should be in a common base (or the system) ClassLoader.

McDowell
The problem is even worse: asume classes C1 and C2 of same type, but loaded with different calssloaders. Now, "C1 instanceof MyInterface" is true but "C2 instanceof MyInterface" is false!
ivan_ivanovich_ivanoff
That was what I was trying to point out - I just wasn't sure you knew this. MyInterface has to move to a common ClassLoader, the parent of any ClassLoader you use to load the different implementation versions, much like there is only one javax.servlet.Servlet loaded in an app server.
McDowell
If you are determined to do this the hard way, you can generate the interface implementation on the fly. Have a look at Dennis Sosnoski's articles on ClassLoaders and bytecode manipulation on developerWorks.
McDowell