How to Call Getclass() from a Static Method in Java

How to call getClass() from a static method in Java?

The Answer

Just use TheClassName.class instead of getClass().

Declaring Loggers

Since this gets so much attention for a specific usecase--to provide an easy way to insert log declarations--I thought I'd add my thoughts on that. Log frameworks often expect the log to be constrained to a certain context, say a fully-qualified class name. So they are not copy-pastable without modification. Suggestions for paste-safe log declarations are provided in other answers, but they have downsides such as inflating bytecode or adding runtime introspection. I don't recommend these. Copy-paste is an editor concern, so an editor solution is most appropriate.

In IntelliJ, I recommend adding a Live Template:

  • Use "log" as the abbreviation
  • Use private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger($CLASS$.class); as the template text.
  • Click Edit Variables and add CLASS using the expression className()
  • Check the boxes to reformat and shorten FQ names.
  • Change the context to Java: declaration.

Now if you type log<tab> it'll automatically expand to

private static final Logger logger = LoggerFactory.getLogger(ClassName.class);

And automatically reformat and optimize the imports for you.

how to solve cannot make a static reference to the non-static method?

(If your class name is Main then) use Main.class.getResource instead of this.getClass.getResource

Read this for more details.

Getting the class name from a static method in Java

In order to support refactoring correctly (rename class), then you should use either:

 MyClass.class.getName(); // full name with package

or (thanks to @James Van Huis):

 MyClass.class.getSimpleName(); // class name and no more

I can't access my class location from static method

Instead of using getClass() you can use FileWriting.class.

The non-static method getClass() can't be called from the static main method unless you have an instance of the class. You can however get the class in the static context as shown above.

How to get getclass().getResource() from a static context?

It can't compile because getResource takes a resource name (a String, and not a File) as parameter, in order to load a resource using the class loading mechanism (from the classpath). Using it with a File makes no sense. If you want to open a file, just use a FileInputStream or a FileReader.

See http://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html#getResource%28java.lang.String%29, and include the compiler error message next time you have such a question.

How to get class which invokes static method?

At first, I thought this is impossible as the java compiler can figure out which method will be called and emit the same instruction.

Turns out that it actually records the way the class is called.

So, the question now becomes:

  • How do we get the place where the method is called?
  • How do we use this information to get the way the method is called?

The first one is easy: We use a StackWalker, which can give us the bytecode index.

Now we only need to parse the class, look at the instruction at that bytecode index, and figure out how this method was called.

I used ASM for that, but it might be the wrong tool here.

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.lang.StackWalker.StackFrame;
import java.util.Set;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;

import static org.objectweb.asm.Opcodes.*;

class CallingClassVisitor extends ClassVisitor {

private final StackFrame where;
String ownerClass = null;

public CallingClassVisitor(StackFrame where) {
// We need a backing ClassWriter, so the Label is resolved.
super(ASM8, new ClassWriter(0));
this.where = where;
}

@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
String[] exceptions) {
MethodVisitor parent = super.visitMethod(access, name, descriptor, signature, exceptions);
if (name.equals(where.getMethodName()) && descriptor.equals(where.getDescriptor())) {
return new CallingMethodVisitor(where, parent);
} else {
return parent;
}
}

class CallingMethodVisitor extends MethodVisitor {

private final StackFrame where;
public CallingMethodVisitor(StackFrame where, MethodVisitor parent) {
super(ASM8, parent);
this.where = where;
}

@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
Label lbl = new Label();
visitLabel(lbl);
if (lbl.getOffset() == where.getByteCodeIndex()) {
ownerClass = owner;
}
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
}

public String getOwnerClass() {
return ownerClass;
}
}

class A {

static final StackWalker SW = StackWalker.getInstance(Set.of(StackWalker.Option.RETAIN_CLASS_REFERENCE));

public static void doIt() {
StackFrame sf = SW.walk(s -> s.skip(1).findFirst()).orElseThrow();
InputStream source = sf.getDeclaringClass().getClassLoader()
.getResourceAsStream(sf.getClassName().replace('.', '/') + ".class");
try {
CallingClassVisitor ccv = new CallingClassVisitor(sf);
new ClassReader(source).accept(ccv, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
String how = ccv.getOwnerClass();
System.out.println(how);
} catch (IOException e) {
throw new UncheckedIOException(e);
}

}
}

class B extends A { }

public class NewMain {

public static void main(String[] args) {
A.doIt();
B.doIt();
}
}

In the end, I'm not sure if your requirement is worth that effort.

Why isn't getClass() available as a static method?

If nothing else, because it isn't legal to have both a static and non-static version of a method (probably because it's legal, if discouraged, to call a static method in a non-static context).

I also feel like such a method, while useful in the context of defining a logger or whatever, could be confusing in other contexts, such as when called from an instance method.



Related Topics



Leave a reply



Submit