9

I have several methods in a class that require a boolean to be set to true in order to execute correctly.

I could write the if statement in each method, but it is not convenient if I or someone else wants to ad another method. I or he could forget about the check.

Is there a way in java to execute a method before each other methods (exactly like JUnit does with @BeforeEach ) in a class ?

Edit: Lots of very interesting techniques/answers/concepts proposed. I'll be in touch when I've understood them. Thanks.

Itération 122442
  • 2,644
  • 2
  • 27
  • 73
  • Probably an overkill: You could create an abstract class or interface, with a default method, which checks for the boolean, and extend the method in your class. –  Feb 11 '20 at 12:48
  • 3
    Look into Aspect Oriented Programming (specifically before advice) - https://stackoverflow.com/questions/31121513/is-there-an-elegant-way-to-make-every-method-in-a-class-start-with-a-certain-blo – Mykyta Lebid Feb 11 '20 at 12:54
  • @NikitaLebed If you actually want to prevent the method executing on a condition as it sounds like OP wants, you'd need an Around advice. – daniu Feb 11 '20 at 12:59
  • Similar questions don't always have the same best answer. What is this Boolean for? – Matt Timmermans Feb 11 '20 at 13:29
  • @MattTimmermans This boolean is a flag indicating if the soft has received and handled correctly an HTTP request. – Itération 122442 Feb 11 '20 at 13:33
  • Maybe encapsulate the fields that those methods need to use inside an object, and only return them from the `markReceived` method. – Matt Timmermans Feb 11 '20 at 13:42

4 Answers4

6

Lets make a method turnBooleanTrue() where effectively the boolean is set to true in order for the method to be execute correctly.

Then, you can write up your very own InvocationHandler that would intercept calls to your objects, and then reflectively (using reflection API) invoke first the turnBooleanTrue() method followed by the method to which the call was made.

Will look something like this

public class MyClassInvocationHandler implements InvocationHandler {

    // initiate an instance of the class
    MyClass myClass = new MyClassImpl();

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {

        // look up turnBooleanTrue() method
        Method turnBooleanTrue = myClass.getClass().getMethod("turnBooleanTrue");

        // invoke the method
        turnBooleanTrue.invoke(...); // toggle the boolean

        // invoke the method to which the call was made
        // pass in instance of class
        Object returnObj = method.invoke(myClass, args);

        return returnObj;
}

EDIT

Added some lines to have an object of MyClass initialized. You need something to invoke the method on and maintain the state. Changed util to myClass in the code example above.

Saif Asif
  • 5,516
  • 3
  • 31
  • 48
1

Considering my use case, it was a bit overkill to use AOP or other concepts. So I basically did a check in each functions.

Itération 122442
  • 2,644
  • 2
  • 27
  • 73
0

I suggest a simple solution by dividing your workflow in four components.

You have an interface you use to execute commands.
You have an interface that defines which commands you can use.
You have one wrapper that analyzes your boolean value.
You have an implementation of the work performing class, that implements the second interface.

Your wrapper initialize the worker.
Your wrapper exposes an action performing command that accepts the executing interface.
if the boolean is true, pass the worker to the executing interface work method.
the executing interfaces work method calls the work function on the command instance interface, the worker.

See it online: https://ideone.com/H6lQO8

class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        WorkDistributer wd = new WorkDistributer();
        wd.enable();
        wd.performAction((w) -> {w.printHello();});
        wd.disable();
        wd.performAction((w) -> {w.printHello();});
        wd.enable();
        wd.performAction((w) -> {w.printAnswer();});
        wd.disable();
        wd.performAction((w) -> {w.printAnswer();});
    }
}
class WorkDistributer 
{
    private boolean enabled = false;
    private ActionPerformer worker;
    public WorkDistributer() {
        this.worker = new Worker();
    }
    public void enable() {
       enabled = true;
    }
    public void disable() {
        enabled = false;
    }
    public void performAction(ActionCommand command) {
        if(this.enabled) {
           command.run(this.worker);
        }
    }
}
class Worker implements ActionPerformer {
    public void printHello() {
        System.out.println("hello");
    }
    public void printAnswer() {
        System.out.println(21 * 2);
    }
}

interface ActionPerformer {
    public void printHello();
    public void printAnswer();
}

interface ActionCommand {
    public void run(ActionPerformer worker);
}
Tschallacka
  • 27,901
  • 14
  • 88
  • 133
  • For this kind of decorator, I'd say it's enough to use `Runnable` for the command, and a single wrapper that evaluates the boolean, created by a factory method (`static Runnable wrap(Runnable wrapped, Supplier allowed)) { return () -> { if (allowed.get()) wrapped.run(); }`) – daniu Feb 11 '20 at 13:27
  • @daniu One could do that, but that's not my preferred way to do it. For me your proposed method loses a lot of "intention" and self documenting properties of the layout of the code flow. But to each their own preferred method. It's heaps better than relying on reflection. Using a native method to steer the code flow forces when changes are made in the future to proper actions. "Magic" reflection methods may be forgotten, resulting in long behavior hunts. – Tschallacka Feb 11 '20 at 13:45
0

With AOP, this is how what you need would look:

// wraps around all methods in your class that have a boolean parameter
@Around(value = "@target(*..YourClass) && args(yourBool)", argNames = "jp,yourBool")
Object scheduleRequest(ProceedingJoinPoint jp, boolean yourBool) {
    if (yourBool) {
        jp.proceed(yourBool);
    } else {
        throw new RuntimeException("cannot execute this method!");
    }
}

This would handle the case that the method take the boolean you say needs evaluation as its (only) parameter. If it comes from a different source, you may need to wire it into the aspect somehow, that depends on your overall design.

daniu
  • 14,137
  • 4
  • 32
  • 53