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 :
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.