Overriding a method in an instantiated Java object

43,720

Solution 1

Since Java uses class-based OO, this is impossible. What you can do is use the decorator pattern, i.e. write a wrapper for the object that returns the wrapped streams.

Solution 2

I think there is a way to achieve the effect you want. I saw it orriginally used in swing with buttons to allow the programmer to make the button do something when it is clicked.

Say you have your Foo class:

public class Foo {
  public Bar doBar() {
    // Some activity
  }
}

Then you have a runner class or something similar. You can override the doBar() method at the point of instantiation and it will only affect that specific object.

that class may look like this:

public class FooInstance{
  Foo F1 = new Foo(){
    public Bar doBar(){
      //new activity
    }
  }

  Foo F2 = new Foo();

  F1.doBar(); //does the new activity
  F2.doBar(); //does the original activity found in the class
}

I'm not entirely sure that will do the trick for you but maybe it'll set you in the right direction. If nothing else it is possible to override a method outside of the class, maybe that will help you.

Solution 3

You can't replace methods in existing objects - you can't change an existing object's type, for one thing.

You could create a new instance of another class which delegated to the existing instance, but that has limitations too.

In your real world case is there no way you can simply make a separate call to wrap the streams returned by the socket? Can you give more details.

Solution 4

You can't really change an object on the fly in java.

You could have something which do what you want by wrapping your Foo into another similar objet which will delegate every call to Foo and at the same log everything you want. (see Proxy)

But if you want to do logging, maybe aspect is a better choice. (see AspectJ)

Solution 5

Another proxying-related solution: you could use Aspects to override a method on a given object without subclassing it yourself. This is especially appropriate and common for logging. This example uses spring-aop.

class Example {

    final Foo foo;

    Example(Foo original) {
        AspectJProxyFactory factory = new AspectJProxyFactory();
        factory.setTarget(original);
        factory.addAspect(FooAspect.class);
        foo = (Foo) factory.getProxy();
    }

    @Aspect
    static class FooAspect {

        @Before("execution(Foo.doBar())")
        Object beforeDoBar() {
            // My own activity
        }
    }
Share:
43,720
Tyler Szabo
Author by

Tyler Szabo

Updated on August 01, 2020

Comments

  • Tyler Szabo
    Tyler Szabo almost 4 years

    I would like to override a method in an object that's handed to me by a factory that I have little control over.

    My specific problem is that I want to override the getInputStream and getOutputStream of a Socket object to perform wire logging.

    The generic problem is as follows:

    public class Foo {
        public Bar doBar() {
            // Some activity
        }
    }
    

    Where I'd like to take an instantiated Foo and replace the doBar with my own that would work as follows:

    Bar doBar() {
        // My own activity
        return original.doBar();
    }
    

    For the Socket I'm going to return an InputStream and OutputStream that are wrapped by logging to intercept the data.

  • Tyler Szabo
    Tyler Szabo over 13 years
    Decorating a Socket is a real pain, but it seems to be my only option. Thanks.
  • Hazem Elraffiee
    Hazem Elraffiee over 10 years
    Both will do the original activity. Overriding using anonymous classes only work for methods inside the object itself. For the caller (from outside the object) you cannot use the overridden version of the method.
  • Tourki
    Tourki over 10 years
    hi i tried with the decorator but actually the object am trying to decorate has some protected methods that it uses internally, i can't override those methods because i would have to call them from the instance of my object which is impossible cause they're protected
  • Leo Pflug
    Leo Pflug over 10 years
    I actually just tested it, and it works. Don't know what you talking, Hazem.
  • Erhannis
    Erhannis almost 10 years
    @YAT You could look into reflection. It's generally considered bad form and pretty hacky, but it can work. Like: Method[] methods = object.getClass().getDeclaredMethods(); methods[0].setAccessible(true); methods[0].invoke(object, arg1, arg2);
  • Jeremy Trifilo
    Jeremy Trifilo almost 10 years
    @Erhannis Reflection is a terrible idea especially for something involving networking / data.
  • Robert Newton
    Robert Newton over 5 years
    You are overriding the method when the object is created. But the question states that he is handed the object from a factory, so the object has already been created. You cannot override the object method once the object has already been created.