Ruik
Ruik

Reputation: 1363

Java: Is it possible to always execute a certain function before other functions are called? (Like @Before in JUnit)

Is there a way to always execute a function before any other function of a class is called?

I have a class where I need to refresh some fields always before any function is called:

public class Example {

private int data;

public void function1(){

}

public void function2(){

}

//@BeforeOtherFunction
private void refresh(){
    // refresh data
}
}

Because it seems to be bad programming, I don't want to call refresh at the beginning of every other function. Since other persons are going to work on this project as well, there would be the danger, that somebody extends the calls and doesn't call refresh.

JUnit has a solution for this with the @Before-Annotation. Is there a way to do this in other classes as well?

And by the way: If you know a programming pattern wich solves this problem in another way than executing a function everytime any function is called, that would be very helpful, too!

Upvotes: 12

Views: 24737

Answers (7)

Robo
Robo

Reputation: 612

You should use Decorator in this case. Decorator is a good choice for something like interceptor. Example here: https://msdn.microsoft.com/en-us/library/dn178467(v=pandp.30).aspx

Upvotes: 0

Laszlo Hirdi
Laszlo Hirdi

Reputation: 1150

Use a dynamic proxy in which you can filter to those methods before which your specific "before" method should be called. And call it in those cases before dispatching the call. Please see the answer from How do I intercept a method invocation with standard java features (no AspectJ etc)?

UPDATE:

An interface is needed to be separated for the proxy. The refresh() method cannot remain private. It must be public and part of the interface (which is not nice here) to be able to be called from the proxy.

package CallBefore;

public interface ExampleInterface {
    void function1();

    void function2();

    void otherFunction();

    void refresh();
}

Your class implements that interface:

package CallBefore;

public class Example implements ExampleInterface {

    @Override
    public void function1() {
    System.out.println("function1() has been called");
    }

    @Override
    public void function2() {
    System.out.println("function2() has been called");
    }

    @Override
    public void otherFunction() {
    System.out.println("otherFunction() has been called");
    }

    @Override
    public void refresh() {
    System.out.println("refresh() has been called");
    }
}

The proxy which does the trick. It filters the needed methods and calls refresh().

package CallBefore;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ExampleProxy implements InvocationHandler {

    private ExampleInterface obj;

    public static ExampleInterface newInstance(ExampleInterface obj) {
    return (ExampleInterface) java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(),
        obj.getClass().getInterfaces(), new ExampleProxy(obj));
    }

    private ExampleProxy(ExampleInterface obj) {
    this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
    Object result;
    try {
        if (m.getName().startsWith("function")) {
        obj.refresh();
        }
        result = m.invoke(obj, args);
    } catch (InvocationTargetException e) {
        throw e.getTargetException();
    } catch (Exception e) {
        throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
    }
    return result;
    }
}

The usage:

package CallBefore;

public class Main {

    public static void main(String[] args) {

    ExampleInterface proxy = ExampleProxy.newInstance(new Example());
    proxy.function1();
    proxy.function2();
    proxy.otherFunction();
    proxy.refresh();
    }
}

Output:

refresh() has been called
function1() has been called
refresh() has been called
function2() has been called
otherFunction() has been called
refresh() has been called

Upvotes: 8

Mehmet Ataş
Mehmet Ataş

Reputation: 11549

This may not solve your exact problem but at least could be a starting point if you are allowed considering a re-design. Below is a simple implementation but with some small touches I believe you can achieve a more elegant solution. BTW, this is called Dynamic Proxy Pattern.

First thing you need is an interface for your class.

public interface Interface {
    void hello(String name);
    void bye(String name);
}

public class Implementation implements Interface {
    @Override
    public void hello(String name) {
        System.out.println("Hello " + name);
    }

    @Override
    public void bye(String name) {
        System.out.println("Bye " + name);
    }
}

Then java.lang.reflect.Proxy class comes to help. This class is able to create an instance for a given interface at runtime. It also accepts an InvocationHandler which helps you to capture method calls and looks like this.

public class InvocationHandlerImpl implements InvocationHandler {
    private final Object instance;

    public InvocationHandlerImpl(Object instance) {
        this.instance = instance;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result;
        try {
            System.out.println("Before");
            result = method.invoke(instance, args);
            System.out.println("After");
        } catch (Exception e){
            e.printStackTrace();
            throw e;
        } finally {
            System.out.println("finally");
        }
        return result;
    }
}

After all your client code will look like this.

Interface instance = new Implementation();

Interface proxy = (Interface)Proxy.newProxyInstance(
        Interface.class.getClassLoader(),
        new Class[] { Interface.class },
        new InvocationHandlerImpl(instance));

proxy.hello("Mehmet");

proxy.bye("Mehmet");

Output for this code is

Before
Hello Mehmet
After
finally
Before
Bye Mehmet
After
finally

Upvotes: 6

leo
leo

Reputation: 71

It is better to write another method which will be made protected(accessible to the child classes) which will call first the refresh method and then call the function.

This way the data would be refreshed before the function is called everytime(As per your requirement). eg:

protected void callFunction1(){
refresh();
function();
    }

Thanks, Rajesh

Upvotes: 0

Abylay Sabirgaliyev
Abylay Sabirgaliyev

Reputation: 726

You can have a protected getter method for data. Access getData method instead of using data field. Child classes will see only getData and will have updated data every time.

public class Example {

    private int data;

    public void function1(){

    }

    public void function2(){

    }

    protected int getData(){
        refresh();
        return data;
    }

    //@BeforeOtherFunction
    private void refresh(){
        // refresh data
    }
}

Upvotes: 0

jpkroehling
jpkroehling

Reputation: 14061

Not in Java SE, but if you are using Java EE, you could use interceptors.

For standalone applications, you could consider using a bytecode manipulation framework, like javassist.

Upvotes: 1

J Fabian Meier
J Fabian Meier

Reputation: 35805

I would define getters for every field and do the refreshment inside the getter. If you want to avoid unrefreshed access to your private fields at all, put them in a superclass (together with the getters which call refresh).

Depending on your project structure, it may be also sensible to introduce a separate class for all data that is regularly refreshed. It can offer getters and avoid that anyone accesses the non-refreshed fields.

Upvotes: 3

Related Questions