Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: static nested classes and reflection: "$" vs "."

If I have a class com.example.test.Enum2.Test as in the code below, why does getCanonicalName() return com.example.test.Enum2.Test but Class.forName() requires "com.example.test.Enum2$Test" as an argument?

Is there a way to be consistent, so that I can serialize/deserialize an enum value by its name, without having to check each $ vs . possibility, when the enum is a nested class?

package com.example.test;

import java.util.Arrays;

public class Enum2 {

    enum Test {
        FOO, BAR, BAZ;
    }

    public static void main(String[] args) {
        for (String className : Arrays.asList(
                "com.example.test.Enum2.Test",
                "com.example.test.Enum2$Test"))
        {
            try {
                Class<?> cl = Class.forName(className);
                System.out.println(className+" found: "+cl.getCanonicalName());
            }
            catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        System.out.println(Test.FOO.getDeclaringClass().getCanonicalName());
    }
}

clarification: I'm looking for a good way to deal with this problem in a real application (not just the above contrived test case), either:

a. serialize/deserialize using getCanonicalName()'s output (dotted name only), and for Class.forName() try each possibility in turn e.g. first "com.example.test.Enum2.Test", then "com.example.test.Enum2$Test", then "com.example.test$Enum2$Test", etc.

b. use proper $ notation, so that Class.forName() works right the first time. But this requires me to implement an alternative to getCanonicalName() that produces a string that is consistent with Class.forName().

I am leaning toward approach (b), partially from gut feel, and partially because approach (a) has ambiguities if there are package names with capital letters: com.example.Test.Enum2 and com.example.Test$Enum2 can both be valid inputs to Class.forName() if there is a com/example/Test/Enum2.java, and a com/example/Test.java containing an Enum2 inner class.

...but I don't know how to implement it. Any ideas?

like image 813
Jason S Avatar asked Feb 09 '11 18:02

Jason S


1 Answers

ARGH: I should have been simply using Class.getName() instead of Class.getCanonicalName().

like image 134
Jason S Avatar answered Oct 02 '22 23:10

Jason S