How to get the calling class name from the static method of the superclass in Java?

While coding Java for one of my projects, I came across a  weird requirement. I had a super class that had a static method and I wanted to know the name of the sub classes of my super class that called the method. Let me explain that by example.

I have a class Super that contains a static method superStaticMethod() that prints the name of the class.

package example;

/** Super.java **/
public class Super {

	/** prints the name of the calling class **/
	public static void aStaticMethod() {
		System.err.println("Super static method called from " + getClassName());
	}

	private static String getClassName() {
		return Super.class.getName();
	}

}

Now I have another class Sub that extends the Super class.

package example;

/** Sub.java **/
public class Sub extends Super {
	// nothing here.
}

Now, whether I call Super.aStaticMethod() or Sub.aStaticMethod(), I will get the same output :

Super static method called from example.Super

This is precisely because Super class has no idea of which class actually called the method. Had this been a simple instance method, it was simple. I can just use this.class.getName(). But achieving the same effect is tricky because there is no instance involved when calling the static method and calling Sub.aStaticMethod() is same as calling Super.aStaticMethod().

However, after battling with reflection, I found some way which I would like to share. Here is how its done. The trick is that you hide inside the Super class a spy that can tell you who called the method. This spy will actually be a nested static class that will reveal the details of the calling class.

What you need to do is modify the Super class to this:

package example2;

public class Super {

	public static void aStaticMethod() {
		System.err.println("Super static method called from "
				+ new Spy().revealTheCallingClass());
	}

	/** This class helps get the class name */
	static class Spy extends SecurityManager {

		public String revealTheCallingClass() {
			Class[] classes = getClassContext();
			for (Class cls : classes) {
				// check if the class is a sub class and its the Super class
				// itself.
				if (Super.class.isAssignableFrom(cls) && cls != Super.class) {
					return cls.getName();
				}
			}

			return null;
		}
	}

}

Now if you modify the class for Sub to

package example2;

public class Sub extends Super{

  public static void useSuperClassName(){
    aStaticMethod();
  }
}

Calling Sub.useSuperClassName() will print example2.Sub. Note however that calling Sub.aStaticMethod() will still print null or the name of the class in which it is called (if that class is a subclass of Super) which is something that I will try to rectify in future, if possible.

Comments