Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 720
Ruik Avatar asked Jun 08 '16 11:06

Ruik


People also ask

Can a function call another function Java?

We cannot call another function within a function unless there static or object instantiation.

What happens when a function is called in Java?

The current method call halts. The arguments of the newly called method are pushed to the stack. The method code runs. After the method finished running, the stack is again emptied and the old stack contents is again restored.

Can you call methods from other classes in Java?

We can call the private method of a class from another class in Java (which are defined using the private access modifier in Java). We can do this by changing the runtime behavior of the class by using some predefined methods of Java. For accessing private method of different class we will use Reflection API.

What are the two ways to call a function in Java?

To call a method in Java, simply write the method's name followed by two parentheses () and a semicolon(;).


2 Answers

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
like image 101
Laszlo Hirdi Avatar answered Oct 27 '22 19:10

Laszlo Hirdi


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
like image 32
Mehmet Ataş Avatar answered Oct 27 '22 18:10

Mehmet Ataş