user462455
user462455

Reputation: 13588

Replace/override method of an object which is an implementation of an interface in Java

I have an interface which has only one method. I have a static function which receives objects (these objects implement the interface), and I want to override/replace implementation of the method, that is defined in the interface, in objects. What is the best way to do this in Java

public class MyClass {

    public interface MyInterface {
         Object myMethod (Object blah);
    }

    public static MyInterface decorator(MyInterface obj) { 
          //I want to return a version of obj
          //with a different implementation of myMethod
          //everything else in obj should be same, except myMethod 
    } 
}

Upvotes: 3

Views: 1897

Answers (5)

Mattias Isegran Bergander
Mattias Isegran Bergander

Reputation: 11909

You are looking for a dynamic proxy if we can restrict it to interfaces (any number of them).

So your problem: If you call the method in that interface first without calling the decorator and then with the decorator you want different behavior, so given this interface implementation:

MyInterface o = new MyInterface() {
    public Object myMethod(Object blah) {
        return "bar";
    }
};

This should do different things, for example alter the return value (and/or something else):

System.out.println(o.myMethod(null));
o = decorator(o);
System.out.println(o.myMethod(null));

Output:

bar
foo

This can be done with a dynamic proxy in java:

public static MyInterface decorator(final MyInterface obj) { 
  InvocationHandler handler = new InvocationHandler() {

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      if (method.getName().equals("myMethod")) {
        //do something special
        return "foo";
      }
      return method.invoke(obj, args);
    }
  };


  MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
                            MyInterface.class.getClassLoader(),
                            obj.getClass().getInterfaces(), //all or limit it to just one or a few
                            handler);
  return proxy;
}

Update: If you want to involve more interfaces (updated proxy instance code above to get the interfaces implemented instead of hard coding it):

Now makes this work:

 public static void main(String[] args) {
        A o = new A();
        System.out.println(o.myMethod(null));
        System.out.println(o.myOtherMethod(1));
        Object o2 = decorator(o);
        System.out.println(((MyInterface) o2).myMethod(null));
        System.out.println(((MyInterface2) o2).myOtherMethod(1));
 }

With output:

bar
2
foo <-- changed
2 <- the same behavior

Given:

class A implements MyInterface, MyInterface2 {
  @Override
  public Object myMethod(Object blah) {
    return "bar";
  }

  @Override
  public int myOtherMethod(int a) {
    return a+1;
  }
}

Upvotes: 0

Henry
Henry

Reputation: 43728

Such kind of dynamic behavior is not directly supported in Java. But you can achieve something like this when the object cooperates. I.e. it could provide a method to change the implementation of myMethod:

void changeMethod(MyInterface other) {
    realImpl = other;
}
Object myMethod (Object obj) {
    return realImpl.myMethod(obj);
}

Upvotes: 1

Subhrajyoti Majumder
Subhrajyoti Majumder

Reputation: 41200

Using CGLib you can implements interfaces at runtime.

Example -

public class KeySample {
      private interface MyFactory {
         public Object newInstance(int a, char[] b, String d);
      }
      public static void main(String[] args) {
          MyFactory f = (MyFactory)KeyFactory.create(MyFactory.class);
          Object key1 = f.newInstance(20, new char[]{ 'a', 'b' }, "hello");
          Object key2 = f.newInstance(20, new char[]{ 'a', 'b' }, "hello");
          Object key3 = f.newInstance(20, new char[]{ 'a', '_' }, "hello");
          System.out.println(key1.equals(key2));
          System.out.println(key2.equals(key3));
      }
  }

Upvotes: 0

Marko Topolnik
Marko Topolnik

Reputation: 200138

You can't do that generally, without the knowledge of the exact object type you are decorating. If you know it, then you can create a subclass of that particular class with the implementation changed. Java's type system just isn't flexible enough to mix and match interface implementation like you need.

You could resort to dynamic class definition techniques, which would create a dynamic proxy for every object you pass into your decorate method, but there's an order of magnitude more complexity in such an approach.

Upvotes: 1

Aviram Segal
Aviram Segal

Reputation: 11120

You can create a class with the same interface that delegates all the methods calls yo your object, then you create an anonymous class extending it and override whatever you want

Intercace:

Interface MyInterface {
    void m1();
    void m2();
}

Delegating class:

class MyDelegate implements MyInterface {
    private MyInterface delegate;

    MyDelegate(MyInterface delegate) {
        this.delegate = delegate;
    }

    void m1() {
        delegate.m1();
    }

    void m2() {
       delegate.m2();
    }
}

In the static method you create an instance of an anonymous class extending MyDelegate and override whatever you want, the rest will be run by obj

static MyInterface wrap(MyInterface obj) {
    return new MyDelegate(obj) {
        void m1() {
            // overrided m1
        }

        // my will eventually get to obj
    };
}

Upvotes: 2

Related Questions