2011-02-09 18 views
11

Si tengo una clase com.example.test.Enum2.Test como en el código siguiente, ¿por qué getCanonicalName() devuelve com.example.test.Enum2.Test pero Class.forName() requiere "com.example.test.Enum2$Test" como argumento?

¿Hay alguna manera de ser consistente, de modo que pueda serializar/deserializar un valor enum por su nombre, sin tener que marcar cada posibilidad de $ frente a ., cuando la enumeración es una clase anidada?

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()); 
    } 
} 

aclaración: estoy buscando una buena manera de hacer frente a este problema en una aplicación real (no sólo el caso de prueba artificial arriba), ya sea:

a. serialize/deserialize usando la salida getCanonicalName() (solo con el nombre punteado), y para Class.forName() intente cada posibilidad a su vez, p. primero "com.example.test.Enum2.Test", luego "com.example.test.Enum2$Test", luego "com.example.test$Enum2$Test", etc.

b. use la notación $ apropiada, para que Class.forName() funcione correctamente la primera vez. Pero esto requiere que implemente una alternativa para getCanonicalName() que produzca una cadena que sea coherente con Class.forName().

Me inclino por el enfoque (b), parcialmente por la sensación visceral, y en parte porque el enfoque (a) tiene ambigüedades si hay nombres de paquetes con letras mayúsculas: com.example.Test.Enum2 y com.example.Test $ Enum2 pueden ser entradas válidas a Class.forName() si hay un com/example/Test/Enum2.java, y un com/example/Test.java que contiene una clase interna Enum2.

... pero no sé cómo implementarlo. ¿Algunas ideas?

Respuesta

9

ARGH: Debería haber estado simplemente usando Class.getName() en lugar de Class.getCanonicalName().

5

Bueno, la documentación para getCanonicalName Estado:

Devuelve el nombre canónico de la clase subyacente como se define por la especificación del lenguaje Java.

(El subrayado es mío.)

En Java el lenguaje , anidación se indica con un punto. En lo que respecta a las bibliotecas y la máquina virtual, la clase anidada es solo una clase con un $ en el nombre.

No ha dicho de qué tipo de serialización está hablando, siempre que sea coherente en ambas direcciones, debería estar bien.

+0

bummer. por lo que el nombre del idioma! = el nombre de la VM. :-(¿Hay alguna manera más fácil de convertir la notación punteada a la $ correcta, sin tener que probar cada posibilidad por turno? (P.ej. com.example.test.Enum2.Test, com.example.test.Enum2 $ Test, com .example.test $ Enum2 $ Test, etc.) –

+0

@Jason S: No, desafortunadamente es ambiguo. xyz.ABC podría significar 'xyz.ABC', o' xyz.AB $ C', o 'xyz.A $ B $ C' o 'xyz $ A $ B $ C'. La" versión en dólares "no es ambigua. –

+0

ok, gracias, eso es lo que pensé. (+1 para la explicación) –

Cuestiones relacionadas