2015-09-16 1 views
0

Je souhaite stocker les propriétés dans un Map par leur classe, c'est-à-dire que la mappe ne doit contenir qu'un seul objet de tout type d'exécution. Il y a déjà une implémentation en cours (c'est un projet existant), et le mécanisme est implémenté avec un Map<String, Object>.Nom de domaine complet d'origine de la classe anonyme

mise en œuvre actuelle:

import com.foo.IConfiguration; 
public class ClientCode { 
    private Options options = new Options(); 
    public void putMethod() { 
     options.subOptions(new IConfiguration() { 
      public void configure() {} 
     }); 
    } 

    public Object getMethod() { 
     return options.getSubOption(IConfiguration.class); 
    } 
} 
public class Options { 
    private Map<String, Object> map = new HashMap<>(); 

    public void subOptions(Object subOptionsValue) { 
     if (subOptionsValue != null) { 
      map.put(subOptionsValue.getClass().getName(), subOptionsValue); 
     } 
    } 
    public Object getSubOption(Class<?> subOptionsClass) { 
     return subOptionsClass == null ? null : map.get(subOptionsClass.getName()); 
    } 
} 

Cependant, cela ne fonctionne pas comme je veux pour les classes anonymes. Dans ce cas, getName() et les méthodes connexes mettront Options$1 ou quelque chose de similaire, alors que j'en ai besoin pour mettre com.foo.IConfiguration afin que je puisse l'utiliser de manière fiable dans mon getMethod().

J'ai regardé à travers l'API pour java.lang.Class, mais je ne trouve rien qui me ramènera à la définition de com.foo.IConfiguration. Eh bien, je peux, mais ce n'est pas infaillible: clazz.getInterfaces() donne un tableau d'interfaces, ce qui est bon ici, mais je peux aussi créer un new Object() {} ou une classe locale, ou une classe publique régulière.

Existe-t-il donc un moyen décent de récupérer sans ambiguïté le nom de domaine complet de l'interface ou de la superclasse d'une classe anonyme?

Répondre

2

Les classes anonymes n'ont pas de noms entièrement qualifiés sur lesquels vous pouvez compter, mais vous pouvez vérifier si un objet est une classe anonyme via ob.getClass().isAnonymousClass(). Vous pouvez ensuite récupérer la superclasse ou une superinterface uniquement si cela renvoie true.

Vous devriez aussi penser à manipuler lambdas, même si vous ne l'utilisez pas encore sur Java 8.

+0

C'était le début de ma solution qui semble fonctionner. Je posterai le code dans une réponse séparée, mais c'est ce qui m'a fait réfléchir. – blagae

0

Je vous suggère de mettre plusieurs fois l'objet dans la carte par toutes ses interfaces, classes de base et super interfaces de ses interfaces et ainsi de suite.

Par exemple, vous avez

interface I1 {} 
interface I2 extends I1 {} 
class C1 {} 
class C2 extends C1 implements I2{} 

Et vous mettez par exemple de votre C2 dans Options

Vous pouvez le récupérer par I1.class ou C1.class

Mais dans ce cas, vous devez être prêt pour une éventuelle ambiguïté si vous avez par exemple deux classes qui implémentent une interface.

Dans ce cas, vous pouvez avoir la possibilité de spécifier explicitement la liste des classes et des interfaces qui peuvent être utilisées pour extraire une classe spécifique.

+0

Désolé, nous ne pouvons pas avoir ce genre d'ambiguïté. – blagae

+0

Si vous ne pouvez pas ajouter tout simplement à la carte. – talex

1

Comme promis dans le commentaire à la suggestion de biziclop, je soumets le code que j'ai mis en service. Cela semble fonctionner pour les classes régulières et anonymes, qu'elles implémentent une interface ou étendent une super-classe.

public void subOptions(Object subOptionsValue) { 
    if (subOptionsValue != null) { 
     Class<?> clazz = subOptionsValue.getClass(); 
     String clazzName; 
     if (clazz.isAnonymousClass()) { 
      // not sure if getInterfaces can return null 
      if (clazz.getInterfaces() != null && clazz.getInterfaces().length > 0) { 
       // anonymous classes can implement only one interface 
       clazzName = clazz.getInterfaces()[0].getName(); 
      } else { 
       clazzName = clazz.getSuperclass().getName(); 
      } 
     } else { 
      clazzName = clazz.getName(); 
     } 
     map.put(clazzName, subOptionsValue); 
    } 
} 

EDIT: Manipulation lambdas est plus difficile parce qu'il n'y a aucun moyen sans ambiguïté de singulariser implémentations lambda, mais on peut approcher assez près (pour mes besoins au moins) en suivant How to correctly determine that an object is a lambda? et le changement

if (clazz.isAnonymousClass()) {...} 

à

if (clazz.isAnonymousClass() || clazz.isSynthetic()) {...}