Le projet hérité sur lequel je travaille inclut une bibliothèque externe sous une forme d'ensemble de fichiers binaires de jar. Nous avons décidé que pour l'analyse et le correctif potentiel, nous souhaitons recevoir des sources de cette bibliothèque, les utiliser pour construire de nouveaux fichiers binaires et après un interrupteur de test de régression détaillé et suffisamment long sur ces fichiers binaires. P>
Supposons que nous avons déjà récupéré et construit les sources (je suis en fait en phase de planification). Avant des tests réels, je voudrais effectuer des "contrôles de compatibilité" pour exclure la possibilité que les sources représentent quelque chose de dramatiquement différent de ce qui se trouve dans les "anciens" binaires. P>
Utilisation de l'outil suppose que le même JDK serait utilisé pour la compilation des sources. P>
La question La bibliothèque est assez grande, alors je pense que l'analyse détaillée des binaires décompilés peut être une option. P> Javap code> J'ai pu extraire la version de JDK utilisée pour la compilation (au moins je crois que c'est la version de JDK). Il est écrit, les fichiers binaires ont été construits à l'aide de la version principale 46 et de Mineure 0. Selon cet article il mappe sur JDK 1.2. P>
4 Réponses :
Il existe une variété d'outils de comparaison JAR. Celui qui était plutôt bon est Jardiff . Je ne l'ai pas utilisé depuis un moment, mais je suis sûr que c'est encore disponible. Il existe également des offres commerciales dans le même espace qui pourraient répondre à vos besoins. P>
Jardiff que la perception mentionnée est un bon départ, mais il n'ya aucun moyen de le faire 100% pourcentage théoriquement. En effet, la même source peut être compilée avec différents compilateurs et différentes configurations de compilateur et niveaux d'optimisation. Donc, il n'ya aucun moyen de comparer le code binaire (bytecode) au-delà des signatures de classe et de méthode. P>
Que voulez-vous dire par "implémentation similaire" d'une méthode? Supposons que un compilateur intelligent dépose un cas Le meilleur moyen d'aller dans l'IMHO consiste à mettre en place de très bons cas de test de régression qui vérifient chaque caractéristique clé de vos bibliothèques. Strong> Cela pourrait être une horreur, mais à long terme pourrait être moins chère que la chasse à la chasse à la chasse aux bugs . Tout dépend de vos projets futurs dans ce projet. Pas une décision facile sans faille. P> sinon code> car il s'agit de savoir que la condition peut ne pas être vraie jamais. Sont les deux semblables? Oui et non ..: -) p>
Je suggère un processus multi-étapes: p>
Appliquez le Jardiff précédemment suggéré ou similaire à voir s'il existe des différences d'API. Si possible, choisissez un outil qui a une option pour signaler des méthodes privées, etc. Dans la pratique, tout changement substantiel de mise en œuvre de Java est susceptible de modifier certaines méthodes et classes, même si l'API publique est inchangée. P>
Si vous avez une correspondance API, compilez quelques fichiers sélectionnés au hasard avec le compilateur indiqué, décompilez le résultat et les fichiers de classe d'origine, et comparez les résultats. S'ils correspondent, appliquez le même processus à des organes de code plus gros et plus grands jusqu'à ce que vous trouviez une inadéquation ou avez vérifié tout. P>
Les diffses de code décompilé sont plus susceptibles de vous donner des indices sur la nature des différences et sont plus faciles à filtrer pour des différences non significatives que les fichiers de classe actuels. P>
Si vous obtenez une inadéquation, analysez-le. Cela peut être dû à quelque chose que vous ne vous souciez pas. Si tel est le cas, essayez de construire un script qui supprimera cette forme de différence et reprendre le processus de compil et de comparaison. Si vous obtenez des incompatibles généralisées, expérimentez des paramètres de compilateur tels que l'optimisation. Si les ajustements des paramètres du compilateur éliminent les différences, continuez avec la comparaison en vrac. L'objectif de cette phase est de trouver une combinaison de paramètres du compilateur et de filtres de code décompilés qui produisent une correspondance sur les fichiers échantillons et les appliquent à la comparaison en vrac de la bibliothèque. P>
Si vous ne pouvez pas obtenir une correspondance raisonnablement étroite dans le code décompilé, vous n'avez probablement pas le bon code source. Malgré tout, si vous avez un match d'API, il peut être intéressant de construire votre système et d'exécuter vos tests en utilisant le résultat de la compilation. Si vos tests fonctionnent au moins aussi à la version que vous avez construite à partir de la source, continuez à utiliser le travail en l'utilisant. P>
J'ai décidé d'utiliser la plupart de vos suggestions. Merci :)
Pour les signatures de méthode, utilisez un outil comme Jardiff.
Pour la similitude de la mise en œuvre, vous devez revenir à une supposition sauvage. La comparaison du bytecode sur le niveau de fonctionnement peut être dépendante du compilateur et conduire à un grand nombre de faux négatifs. Si tel est le cas, vous pouvez revenir à la comparaison des méthodes d'une classe à l'aide de la for forte> linenumbertable forte>. P>
Cela vous donne une liste de numéros de ligne pour chaque méthode (tant que Le fichier de classe a été compilé avec le drapeau de débogage, qui manque souvent dans des bibliothèques très anciennes ou commerciales). p>
Si deux fichiers de classe sont compilés à partir du même code source, puis au moins les numéros de ligne de chaque La méthode doit correspondre exactement. p>
Vous pouvez utiliser une bibliothèque telle que Apache Bcel pour récupérer la liste de linge de lecture: P>
// import org.apache.bcel.classfile.ClassParser; JavaClass fooClazz = new ClassParser( "Foo.class" ).parse(); for( Method m : fooClazz.getMethods() ) { LineNumberTable lnt = m.getLineNumberTable(); LineNumber[] tab = lnt.getLineNumberTable(); for( LineNumber ln : tab ) { System.out.println( ln.getLineNumber() ); } }
Réflexion (
java.lang.reflect code>) doit faire pour les signatures de classe et de méthode, mais pas pour la mise en œuvre.
Qu'en est-il de la comparaison des hachage de MD5 des deux binaires?
Pour une référence future, le moyen le plus simple de comprendre cette sortie d'avance (cela ne vous aidera pas maintenant) est d'utiliser un système de contrôle de version comme Git, Subversion ou Mercurial, puis inclure le numéro de révision et / ou l'ID de modification dans votre pot. , comme dans le fichier manifeste.
Je ne m'attends tout simplement pas que les hayes MD5 seront identiques. Les pots ont été construits il y a longtemps et dans un environnement inconnu. La seule chose que j'ai sont des sources, mentionné la version JDK et {{ant}} version de l'outil extrait du fichier manifeste. De plus, même si les hachages diffèrent, j'aimerais connaître une "similitude" de ces pots.
Quand je peux suggérer une approche complètement différente: lorsque vous voulez faire "test de régression assez long", la meilleure façon de le faire serait via une combinaison de tests d'unités automatisées. Courir à la fois les binaires hérités et la nouvelle construction à travers la même combinaison de test seraient un bon moyen de s'assurer qu'ils se comportent de manière identique.