Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to approximate class.getSimpleName() without loading class?

Given a fully qualified class name that can be loaded with Class.forName(), is there a way to transform the name into what would be the result of loading the class and invoking getSimpleName() without actually attempting to load the class? I need this capability for reflection purposes.

like image 852
Uri Avatar asked Apr 20 '16 21:04

Uri


2 Answers

I'm going to say that you can't do it simply based on the name.

You can try to split on . and $, but this example code demonstrates that it is not always obvious where the simple name begins:

class Ideone
{
    private static class Bar {};

    public static void main (String[] args) throws java.lang.Exception
    {
      class Foo$o {
        class Bar$bar {}
      };
      class Foo$o$Bar {
        class Bar$bar {}
      };
      class Foo$o$Bar$Bar$bar {}
      print(Ideone.class);
      print(Bar.class);
      print(Foo$o.class);
      print(Foo$o.Bar$bar.class);
      print(Foo$o$Bar.Bar$bar.class);
      print(Foo$o$Bar$Bar$bar.class);
    }

    private static void print(Class<?> clazz) {
        System.out.printf("fqn=%s, sn=%s%n", clazz.getName(), clazz.getSimpleName());
    }
}

Output:

fqn=Ideone, sn=Ideone
fqn=Ideone$Bar, sn=Bar
fqn=Ideone$1Foo$o, sn=Foo$o
fqn=Ideone$1Foo$o$Bar$bar, sn=Bar$bar
fqn=Ideone$1Foo$o$Bar$Bar$bar, sn=Bar$bar
fqn=Ideone$2Foo$o$Bar$Bar$bar, sn=Foo$o$Bar$Bar$bar

Ideone demo

i.e. if you were to say "the bit of the name after the final $ or .", you'd be wrong.

The only conclusive way to do this is to load the class, potentially without initializing it:

Class<?> clazz = Class.forName(className, false, someClassLoadeR);
like image 98
Andy Turner Avatar answered Oct 02 '22 20:10

Andy Turner


As demonstrated by the answer of @AndyTurner you cannot derive the simple name from the qualified class string in all cases.

But if the constraint without actually attempting to load the class does not forbid to read the contents of the class file, you could do the following (for the edge cases):

  1. Get a InputStream for the class file contents via Class.getResourceAsStream()
  2. Parse the beginning of the class file and read the super class name from the constant pool.
  3. (as commented by @shmosel) Implement the logic of Class.getSimpleName(). The super class name allows you to replace Class.getSimpleBinaryString() which relies on an already loaded class.
like image 39
wero Avatar answered Oct 02 '22 19:10

wero