Aller au contenu

[Résolu] VerifyError au chargement d'une classe


BreizFenrir

Messages recommandés

Bonjour tout le monde,

et encore un problème bien tiré par les cheveux à partager avec vous. Ça ou bien il y a un truc qui m'a échappé. Enfin bref, je vous présente le problème, ça vaut le coup d'oeil : au chargement en mémoire d'une de mes classes, la JVM me retourne le message d'erreur suivant :

java.lang.VerifyError: (class: my/database/DatabaseMonitorManager, method: getItemsConfigMapper signature: (Ljava/io/File;)Lmy/util/monitor/AbstractItemsConfigMapper;) Wrong return type in function

Et m'indique que l'erreur se situe à la ligne où DatabaseMonitorManager est utilisée pour la première fois. Le message d'erreur en lui-même est relativement clair, donc je me suis attelé à vérifier mes définitions de méthodes et... bah je n'y trouve pas d'erreur, tout a l'air en ordre. Ci-après tout ce qu'il y a à savoir sur ces dernières (je n'ai gardé que les extraits de code relatifs à l'erreur décrite):

public class DatabaseMonitorManager
	extends AbstractMonitorManager<Database, DatabasesConfig> {
@Override
protected DatabasesConfigMapper getItemsConfigMapper(final File aItemFile) {
	return new DatabasesConfigMapper(aItemFile);
}
}

public abstract class AbstractMonitorManager<S, T extends AbstractSetConfig<S>>
{
protected abstract AbstractItemsConfigMapper<T> getItemsConfigMapper(
		final File aItemFile);
}

public class DatabasesConfig extends AbstractSetConfig<Database> {
}


public class DatabasesConfigMapper
	extends AbstractItemsConfigMapper<DatabasesConfig> {
}

Bref, l'erreur ne vient visiblement pas du code en lui-même. NetBeans d'ailleurs n'indique aucune erreur et tout compile correctement.

J'ai recherché des descriptions de cas similaires sur Internet et il s'est avéré que pour ces derniers, la classe héritée était contenue dans une librairie dont la version n'était pas la même en environnement de développement et en environnement de production. Mais cela ne semble pas s'appliquer ici, car toutes ces classes font partie du même projet. Bref, je me retrouve dans une impasse.

Merci d'avance pour votre aide !

P.S. : "Clean and build" ne corrige pas l'erreur (vu les cas présents sur le net, ça aurait pu venir de la non-recompilation d'une classe qui aurait dû l'être). J'ai créé un projet dans lequel j'ai recréé la même organisation de classes, avec juste ce qu'il faudrait (à mon avis et d'après le message d'erreur) pour générer le problème. Résultat : ça tourne. Je continue mes essais et je vous tiens au courant.

P.P.S. : J'ai aussi commenté juste la méthode décrite dans le message d'erreur (dans les classes où elle apparaît, ainsi que les blocs de code (peu nombreux) où elle est utilisée). Maintenant, charger la classe qui posait problème se fait bien. Vu que je n'ai pas commenté tant de code que ça, je vais tâtonner et voir ce que cela donne.

Lien vers le commentaire
Partager sur d’autres sites

Bon bah ça m'apprendra à mettre des bouts d'architecture foireux dans mon code. Je n'ai plus le problème, quand bien même je ne suis pas trop sûr de savoir quel est le lien entre ce que j'ai modifié et le message concernant l'erreur détectée. En fait, le problème venait de la manière dont AbstractItemsConfigMapper était définie :

public abstract class AbstractItemsConfigMapper<S, T extends AbstractSetConfig<S>> extends AbstractConfigMapper<T> {
}

public abstract class AbstractSetConfig<T> extends AbstractConfig implements Set<T> {
}

public abstract class AbstractConfigMapper<T extends AbstractConfig> {
}

Ce dernier gardait abstraites toutes les méthodes déclarées dans la classe abstraite héritée, n'ajoutant qu'un attribut à la classe, initialisé dans un constructeur. De fait, il n'avait pas vraiment d'intérêt, d'autant plus que la contrainte sur T est aussi présente dans une autre classe qu'il est nécessaire d'utiliser avec exactement les mêmes données. De fait, j'ai migré l'attribut dans DatabasesConfigMapper (il n'était pas particulièrement logique de le mettre dans AbstractItemsConfigMapper car il nuisait à la généricité de la classe de toute manière) et fait en sorte que la classe hérite directement de AbstractSetConfig. Et le code fonctionne désormais !

Je marque le problème comme résolu, quand bien même je ne pourrais expliquer à une personne qui le rencontrerait comment le résoudre, s'il se pose sur un graphe de classes organisé différemment.

Lien vers le commentaire
Partager sur d’autres sites

Petit complément d'information : j'ai cette erreur qui est réapparue et je l'ai éliminée assez rapidement ce coup-ci, en enlevant une autre classe "vide" (elle se contentait de fixer le type à utiliser vis-à-vis de la classe générique héritée).

À y réfléchir, c'est vraiment une très mauvaise manière d'utiliser les generics, vu qu'en les utilisant de cette manière, on perd une grande partie de la généricité dans les méthodes et classes qui en exploitent. Je cherche à être trop spécifique et c'est mal.

Sinon, serait-il possible que l'exploitation directe d'un type générique par un autre type générique (du genre de ce qu'il se passe dans la déclaration d'AbstractItemsConfigMapper dans mon message précédent) soit foireux ? Il va falloir que je relise le didacticiel de Sun concernant les generics. Il est plutôt complet donc j'imagine que si une telle chose n'y apparaît pas, j'aurais tendance à penser qu'une telle utilisation est à éviter.

Lien vers le commentaire
Partager sur d’autres sites

Salut !

J'ai pas tout bien suivi, mais il est bien possible d'utiliser plusieurs generics dans une même classe.

Mais après, pour te conseiller il faudrait comprendre un peu plus ce que tu veux faire ... là, je vois pas bien.

Car ce n'est pas une bonne idée de mettre du Generics dès qu'il y a une classe abstraite.

Cela est majoritairement utile lorsque l'objet en generics est exploité en dehors de la classe fille.

Exemple typique un DAO qui aurait en generics la donnée gérée qui serait donc renvoyée par des méthodes (get, find ...).

Lien vers le commentaire
Partager sur d’autres sites

J'ai un peu changé la façon dont j'utilisais mes classes hier soir histoire que cela soit plus propre, et le résultat il y a plus d'"exploitation en dehors de la classe fille" qu'avant. La façon dont je fonctionnais avant faisait que j'avais quelques classes en plus, ce qui était plus une gêne qu'autre chose.

Enfin bref, ces extraits de code correspondent à une application de surveillance de l'état de ressources (de types divers et variés) sur un réseau. Mes classes abstraites correspondent à des classes à hériter quand on veut développer de quoi surveiller pour un type donné. La gestion de l'exécution est déjà incluse dans ces classes, il n'y a plus qu'à implémenter les 2-3 méthodes qui font des opération spécifiques.

Mais il est vrai que je pourrais utiliser des relations de composition plutôt que d'héritage. Pour le moment mon application fonctionne bien, ou presque (enfin bon, si je sèche, j'irais poser ma question au bar de la prog, c'est un petit truc ce coup-ci), donc je n'ai pas de raison de retoucher sa forme actuelle.

Lien vers le commentaire
Partager sur d’autres sites

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...