Last Updated: October 11, 2016
·
7.827K
· davidklotz

Don't rely on class.getSimpleName() or class.getCanonicalName()

Building code that universally gets the class name of an object can have some unexpected pitfalls in Java. You should never rely on class.getSimpleName() or class.getCanonicalName() to give you anything meaningful if your code could be passed arbitrary objects of any class. Especially for anonymously created objects, they will be empty or null.

To give you an example, this script will generate the output below it:

import java.util.function.BiConsumer;
import java.util.function.Consumer;

import static java.lang.String.format;

/**
 * Demo of some common pitfalls with class.getSimpleName() and class.getCanonicalName().
 * @author David Klotz
 */
public class MyClassNames {

    private static class StaticInnerClass {}
    private class InnerClass {}

    private static void logClassName(String prefix, Class<?> clazz) {
        System.out.println(format("%s:\n Simple:\t '%s'\n Name  :\t '%s'\n Canonical:\t '%s'\n Type name:\t '%s'\n\n", prefix, clazz.getSimpleName(), clazz.getName(), clazz.getCanonicalName(), clazz.getTypeName()));
    }

    public static void main(String[] args) {
        Runnable anonymous = new Runnable() {
            @Override
            public void run() {

            }
        };

        Runnable someLambda = () -> {};
        Consumer<String> someOtherLambda = s -> {};
        BiConsumer<String, Class<?>> methodReference = MyClassNames::logClassName;

        logClassName("Normal class", MyClassNames.class);
        logClassName("Static inner class", MyClassNames.StaticInnerClass.class);
        logClassName("Inner class", MyClassNames.InnerClass.class);
        logClassName("Anonymous class", anonymous.getClass());
        logClassName("Lambda runnable class", someLambda.getClass());
        logClassName("Lambda consumer class", someOtherLambda.getClass());
        logClassName("Method reference class", methodReference.getClass());
    }
}

Output:

Normal class:
 Simple:     'MyClassNames'
 Name  :     'com.example.MyClassNames'
 Canonical:  'com.example.MyClassNames'
 Type name:  'com.example.MyClassNames'


Static inner class:
 Simple:     'StaticInnerClass'
 Name  :     'com.example.MyClassNames$StaticInnerClass'
 Canonical:  'com.example.MyClassNames.StaticInnerClass'
 Type name:  'com.example.MyClassNames$StaticInnerClass'


Inner class:
 Simple:     'InnerClass'
 Name  :     'com.example.MyClassNames$InnerClass'
 Canonical:  'com.example.MyClassNames.InnerClass'
 Type name:  'com.example.MyClassNames$InnerClass'


Anonymous class:
 Simple:     ''
 Name  :     'com.example.MyClassNames$1'
 Canonical:  'null'
 Type name:  'com.example.MyClassNames$1'


Lambda runnable class:
 Simple:     'MyClassNames$$Lambda$1/110992469'
 Name  :     'com.example.MyClassNames$$Lambda$1/110992469'
 Canonical:  'com.example.MyClassNames$$Lambda$1/110992469'
 Type name:  'com.example.MyClassNames$$Lambda$1/110992469'


Lambda consumer class:
 Simple:     'MyClassNames$$Lambda$2/1638172114'
 Name  :     'com.example.MyClassNames$$Lambda$2/1638172114'
 Canonical:  'com.example.MyClassNames$$Lambda$2/1638172114'
 Type name:  'com.example.MyClassNames$$Lambda$2/1638172114'


Method reference class:
 Simple:     'MyClassNames$$Lambda$3/1651945012'
 Name  :     'com.example.MyClassNames$$Lambda$3/1651945012'
 Canonical:  'com.example.MyClassNames$$Lambda$3/1651945012'
 Type name:  'com.example.MyClassNames$$Lambda$3/1651945012'