J'ai développé une application à l'aide du reflets bibliothèque pour interroger toutes les classes ayant un particulier annotation. Tout fonctionne comme un charme jusqu'à ce que je puisse décider de créer un plug-in Eclipse de ma candidature. Ensuite, les réflexions cessent de fonctionner.
étant donné que mon application fonctionne bien lorsque je ne fais pas partie d'un plug-in Eclipse, je pense que cela devrait être un problème de chargement de classe. J'ai donc ajouté à mes réflexions code> Classes Code> Les chargeurs de classes de la classe d'activateur enfichable, le chargeur de classe de contexte et tous les autres chargeurs de classe que je pouvais imaginer, sans succès. Ceci est une version simplifiée de mon code: P>
ConfigurationBuilder config = new ConfigurationBuilder(); config.addClassLoaders(thePluginActivatorClassLoader); config.addClassLoaders(ClasspathHelper.getContextClassLoader()); config.addClassLoaders("all the classloaders I could imagine"); config.filterInputsBy(new FilterBuilder().include("package I want to analyze")); Reflections reflections = new Reflections(config); Set<Class<?>> classes = reflections.getTypesAnnotatedWith(MyAnnotation.class); //this Set is empty
3 Réponses :
Eclipse est construit sur Osgi et vous êtes à la hausse contre le chargement de la classe OSGI ... et ce n'est pas une bataille facile à gagner. P>
Jetez un coup d'œil à cet article de Neil Bartlett: Préparation à l'OSGI - Chargement de cours . Aussi, vous pouvez également google pour "Osgi Buddy Policy". P>
Je vois :(. @Tonny, connaissez-vous une autre bibliothèque pour interroger ce type d'information -Classe avec une annotation particulière et donc sur une application faisant partie d'un plug-in Eclipse?. Autant que je sache le printemps peut aussi Répondez aux questions similaires, mais je ne l'ai pas essayée auparavant, et aucune idée si cela fonctionnera bien lors de la participation d'un plug-in Eclipse ou s'il présentera les mêmes problèmes que j'ai actuellement. Merci pour vos commentaires!.
Vous pouvez effectuer la bibliothèque de réflexions dans un paquet OSGI, puis ajouter le fichier dynamicimport-package: * code> en direction de manifeste.mf. Vous pouvez effectuer le premier paquet du fichier JAR existant à l'aide du "nouveau projet" -> "Plug-in de Jar Archive existant" ... bonne chance.
Je suppose que vous savez déjà comment créer des paquets (sinon, vérifier Ceci ).
Après avoir débogué et exploration de réflexions API, j'ai compris que le problème est que les réflexions ne parviennent pas à lire les URL d'OSGI (Bundleresource: // ...) entraînant une exception: P > et cette suggestion: p> donc je pense que la mise en œuvre d'un URLTYPE pour OSGI (par exemple, classe BundleURLType implémente urltype {. ..} code>) et inscrivez-le comme ceci: P>
private Reflections createReflections(Bundle bundle) {
Vfs.addDefaultURLTypes(new BundleUrlType(bundle));
Reflections reflections = new Reflections(new Object[] { "reflectiveplugin.data" });
return reflections;
}
Merci pour votre réponse @vlad. Aucune idée de la façon de créer de tels faisceaux mais je vais essayer (je suis loin d'être un expert à Osgi pourtant ...). J'ai donc besoin de deux paquets: 1) la bibliothèque de réflexions ayant "dynamicimport-package: *" à son manifeste plug-in; 2) Un paquet avec mon plugin, où je dois rentrer dans la liste "Packages exportés" de l'éditeur de configuration du plug-in, tous les packages à accessibles au paquet de réflexions. Ensuite, je suppose que je devrais composer ces deux faisceaux dans une autre, non? Pourriez-vous s'il vous plaît élaborer un peu plus votre réponse? Tout cela semble être un peu complexe!. Merci
@Sergio, j'ai mis à jour la réponse avec mes conclusions (réponse précédente n'a pas fourni de solution). Malheureusement, cela serait beaucoup moins simple. J'espère que ça va aider.
Merci beaucoup pour développer votre réponse @vlad. J'ai essayé de le mettre en œuvre sans succès jusqu'à présent. Si je comprenais correctement votre nouvelle réponse, je n'ai besoin que du bundle du plugin et du pot de réflexions dans son point de classe de paquet (comme je l'avais à l'origine). Donc, j'ignore la réponse précédente sur la mise en place de réflexions dans un ensemble séparé, est-ce correct?. À propos de votre fichier manifeste: votre «Bundle-ClassPath» ressemble à la mienne, dans mon "forfait d'exportation", je n'ai pas de fichier ".Data" comme vous, et dans le "paquet d'importation", je ne vois pas les dépendances Vous avez, est-ce important pour que les réflexions fonctionnent?
Dans votre test: Avez-vous eu à utiliser la méthode "ConfigurationBuilder> AddClassloader ()" pour définir un chargeur de classe spécial? ou manipuler des chargeurs de classe n'était pas nécessaire?. Ceci est le message d'erreur que je rencontre dans la console: "20 [fil-1] erreur org.reflections.reflections - donnée des URL de numérisation sont vides. Définissez les URL dans la configuration". Je crée un objet FilterBuilder avec: "FilterBuilder FB = nouveau filtreBuilder ();" et après, faire cela: "fb.include (filterbuilder.prefix (" mypackageroot "));". Comme vous me recommandez, je fais la même chose pour le répertoire de sortie: "fb.include (filterbuilder.prefix (" bin "));"
Oui, ignorer la réponse précédente. Il est important d'importer tous les bocaux requis, vous devez les ajouter manuellement comme décrit dans l'article que j'ai fourni un lien vers la réponse (sauf si vous utilisez Maven avec les plug-ins Eclipse OSGI pour construire votre projet).
La manipulation des chargeurs de classeurs Il n'est pas nécessaire que vous puissiez voir dans la méthode code> CreeeeFlections Code>, et voici comment je devais le modifier (ajout du préfixe "bin") pour le faire fonctionner à partir d'Eclipse IDE: < Code> Reflections Reflections = Nouveaux reflets (nouvel objet [] {"réflectplugin.data", "bin"}); code>. Bien que si vous le faites avec ConfigurationBuilder code>, vous ne devez pas oublier de enregistrer des scanners. Vérifier
Reflections (Objet final [] URLHINTS, SCANNER final ... Scanners) CODE> Constructeur, il délégué au constructeur avec argument de configuration.
J'ai réussi à le faire fonctionner. Cela m'aurait pris des âges de le faire sans votre aide ici. Merci. Je vais toujours essayer de trouver une solution de contournement pour ne pas avoir à faire correspondre le dossier de sortie de mon plugin dans le chemin des réflexions, mais il s'agit d'un problème mineur par rapport au problème initial !.
Je t'en prie. Faites-nous savoir si vous trouvez une solution pour le dossier de sortie codé (j'ai une supposition, il peut être associé à ne pas avoir le dossier de sortie dans l'ensemble de la classe-classe dans Manifest.mf. De plus, si vous utilisez Maven avec PDE-Maven-plugin pour construire votre manifeste.mf, il devrait automatiquement construire correctement le paquet-classe-classe basé sur des dépendances défini dans pom.xml etc.)
Bonjour, j'ai essayé avec le dossier de sortie dans le sac de classe, mais cela n'a pas aidé :(. Entre-temps j'ai lancé un nouveau fil avec cette question spécifique: Stackoverflow.com/questions/8407364/...
MISE À JOUR: Apparemment, le problème de devoir écrire le dossier de sortie des filtres de réflexions, il se produit non seulement lors de l'exécution du plugin avec "Exécuter comme application Eclipse", mais également lorsque le plug-in est complètement déployé dans Eclipse (le pot de plugin a été situé dans le dossier Plugins). Je me demande si un moyen d'éviter cela est de demander aux réflexions de travailler avec le chargeur de classe de la classe Activator Plugin. Je fais des expériences dans cette direction et je posterai si je réussis, au cas où vous auriez une nouvelle idée, @vlad me le faire savoir. Merci!.
Juste pour les archives au cas où une autre personne ait le même problème. Ici, une petite modification de la réponse du VLAD afin d'éviter d'ajouter le répertoire de sortie aux modèles de chemin de réflexion. La différence est seulement dans la classe Bundledir. Il semble fonctionner correctement dans tous mes tests:
public class BundleUrlType implements UrlType { public static final String BUNDLE_PROTOCOL = "bundleresource"; private final Bundle bundle; public BundleUrlType(Bundle bundle) { this.bundle = bundle; } @Override public Dir createDir(URL url) { return new BundleDir(bundle, url); } @Override public boolean matches(URL url) { return BUNDLE_PROTOCOL.equals(url.getProtocol()); } public static class BundleDir implements Dir { private String path; private final Bundle bundle; private static String urlPath(Bundle bundle, URL url) { try { URL resolvedURL = FileLocator.resolve(url); String resolvedURLAsfile = resolvedURL.getFile(); URL bundleRootURL = bundle.getEntry("/"); URL resolvedBundleRootURL = FileLocator.resolve(bundleRootURL); String resolvedBundleRootURLAsfile = resolvedBundleRootURL.getFile(); return("/"+resolvedURLAsfile.substring(resolvedBundleRootURLAsfile.length())); } catch (IOException e) { throw new RuntimeException(e); } } public BundleDir(Bundle bundle, URL url) { //this(bundle, url.getPath()); this(bundle, urlPath(bundle,url)); } public BundleDir(Bundle bundle, String p) { this.bundle = bundle; this.path = p; if (path.startsWith(BUNDLE_PROTOCOL + ":")) { path = path.substring((BUNDLE_PROTOCOL + ":").length()); } } @Override public String getPath() { return path; } @Override public Iterable<File> getFiles() { return new Iterable<Vfs.File>() { public Iterator<Vfs.File> iterator() { return new AbstractIterator<Vfs.File>() { final Enumeration<URL> entries = bundle.findEntries(path, "*.class", true); protected Vfs.File computeNext() { return entries.hasMoreElements() ? new BundleFile(BundleDir.this, entries.nextElement()) : endOfData(); } }; } }; } @Override public void close() { } } public static class BundleFile implements File { private final BundleDir dir; private final String name; private final URL url; public BundleFile(BundleDir dir, URL url) { this.dir = dir; this.url = url; String path = url.getFile(); this.name = path.substring(path.lastIndexOf("/") + 1); } @Override public String getName() { return name; } @Override public String getRelativePath() { return getFullPath().substring(dir.getPath().length()); } @Override public String getFullPath() { return url.getFile(); } @Override public InputStream openInputStream() throws IOException { return url.openStream(); } } }
Je reçois aujourd'hui ce problème exact, je n'ai jamais créé de paquets avant, mais j'ai essayé pour cela. Je ne comprends pas où obtenir l'objet Bundle de passer à ce constructeur, pouvez-vous aider?