Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check is instance method is called from a constructor

I would like to check, from an instance method of a non-final class, whether the constructors and initializers of that class and its chain of subclasses for the specific instance have already completed.

In the following example, I have a class Abstract, which can be used to implement an interface which allows listeners to be added (which, for simplicity, are just Runnable instances here) and which provides a method signalEvent() which calls all attached listeners.

abstract class Abstract {
    protected final void signalEvent() {
        // Check that constructs have run and call listeners.
    }

    public final void addListener(Runnable runnable) {
        ...
    }
}

class Concrete extends Abstract {
    Concrete() {
        // Should not call signalEvent() here.
    }

    void somethingHappened() {
        // May call signalEvent() here.
    }
}

Now it is possible to call signalEvent() from within the subclass constructor, but there is no way that a listener has already been added by that time and the event would just be lost. In our code-base, once in a while, someone adds such a call and I would like to be able to catch such calls as early as possible (using an assert statement or similar).

Is it possible to check whether an instance method is being called, directly or indirectly, from the subclass constructor or initializer of the current instance or, alternatively, is it possible to check whether all constructors for an instance have been completed?

like image 629
Feuermurmel Avatar asked Oct 31 '22 00:10

Feuermurmel


2 Answers

In short, there is no elegant Java mechanism that allows you to do that, but you may consider using a factory pattern. Instead of creating instances directly using new keyword, you could create a factory class, that takes care of creating the actual instance and invokes an additional "post-create" method, that lets the instance know it's been completely created.

If you're using some dependency injection like spring, you get that out of the box, but if not, a solution could look something like this:

interface PostConstruct { // the classes need to implement that
    void postConstruct();
}

public class InstanceFactory {
    public <T extends PostConstruct> T create(Class<T> clazz, Object... params) {
        T instance = //create using reflection
        instance.postConstruct();
        return instance;
    }
}
like image 177
pdabro Avatar answered Nov 13 '22 03:11

pdabro


A solution to the problem to see if a method or code is being called from a constructor. The code below will print true and false respectivly but would be slow and not pretty at all.

I still believe it is not the right solution for the problem above. As Codbender said, better to check if a listener has been added or set a status variable which would be faster

Edit - fixed the issue that Codebender mentioned and also made sure to check back in the stack trace incase of being called a couple of methods deep

public class TestClass extends TestAbstract {

    public TestClass() throws Exception {
       submethod();
    }

    public void submethod() throws Exception {
        System.out.println(isInConstructor());
    }

    public static void main(String[] args) throws Exception {
        System.out.println(new TestClass().isInConstructor());
    }

}

public class TestAbstract {

    public boolean isInConstructor() throws Exception {
        StackTraceElement[] elements = Thread.currentThread().getStackTrace();
        for (StackTraceElement element : elements) {
            if (element.getMethodName().equals("<init>") &&
                TestAbstract.class.isAssignableFrom(Class.forName(element.getClassName()))) {
                return true;
            }
        }
        return false;
    }

}

like image 28
tobad357 Avatar answered Nov 13 '22 05:11

tobad357