2012-06-01 3 views
13

J'écris une partie d'une application web PHP (qui sera utilisée dans un concours de recherche de bogues au lycée) où l'utilisateur doit trouver des bogues dans un programme Java donné. Dans le cadre de cela, lorsque le programme Java s'exécute, nous voulons mettre en évidence les lignes de la source du programme Java où le code a été exécuté. Pour ce faire, tout ce dont nous avons besoin sont les numéros de ligne de la source qui ont été exécutés, c'est-à-dire le chemin du code (ou est-ce appelé couverture de code?). Nous allons mettre en évidence les lignes dans le fichier source en utilisant les numéros de ligne.Numéros de ligne du code java exécuté

Nous utiliserons shell-exec() de PHP pour exécuter le programme Java et l'outil pour obtenir le chemin du code (quel qu'il soit). Quel est le moyen le plus simple d'obtenir les numéros de ligne du chemin de code?

Merci beaucoup!

Voici une image qui décrit ce que nous voudrions

enter image description here

Répondre

0

Vous pourriez obtenir un numéro de ligne si vous compilez le programme avec l'option -g, faire un printStackTrace(), capturer la sortie de trace et extrait le linenumber de là.

4

PHP interperts le code, ce qui signifie qu'il s'exécute sur la source chaque fois que vous exécutez le programme. Cela a l'avantage de sauter lorsque le code est lu (ce qui rend les impressions de numéros de ligne triviales); Cependant, il est souvent coûteux d'une autre manière, car vous ne pouvez pas optimiser en profondeur (ou effectuer une vérification d'erreur avant l'exécution).

Java compiles its code into a JVM assembly language called "bytecode." Cela signifie que ce qui est en cours d'exécution n'a généralement pas accès au code source (ni même son utilisation). Cela dit, il y a des techniques. Une classe Java compilée a la possibilité d'ajouter des "données supplémentaires" et l'un de ces "éléments de données supplémentaires" est a line number table, qui est un index permettant à quelqu'un exécutant l'assembly de "rechercher" le numéro de ligne comme le compilateur l'a enregistré. Cela fonctionne généralement bien, avec les considérations suivantes: les compilateurs ne marquent souvent pas toutes les instructions, le code source peut ne pas être disponible, l'optimisation peut empêcher certains codes internes de fonctionner de manière à faciliter le pointage vers l'entrée texte de code. Comment les outils de couverture de code "fixent" ceci est qu'ils insèrent généralement dans le code (au niveau de l'assemblage) un grand nombre de commandes qui agissent comme des instructions de journalisation dans un format qui permet à l'outil de déterminer le chemin à travers le le code a été effectivement suivi. Il est ensuite recopié le mieux possible dans la table des numéros de ligne, puis utilisé pour mettre en surbrillance les lignes dans le fichier source d'origine.

Si vous voulez quelque chose avec une résolution plus fine (quelque chose qui peut traiter quelle partie d'une ligne a été exécutée) alors vous devez creuser plus profondément. Finalement, vous pourriez même envisager d'écrire votre propre compilateur (ou extension de compilateur) qui stockera votre propre table de numéro de ligne personnalisée qui surmonte les lacunes des solutions actuelles.

Des trucs comme jeter des exceptions (comme Shiven l'a mentionné) et analyser le numéro de ligne fonctionnent; cependant, ils polluent votre code avec un traitement d'exception impair pour les éléments qui ne sont vraiment ne sont pas exceptionnel, juste pour "obtenir le numéro de ligne". En raison de l'encombrement du code et des performances d'exécution généralement moins bonnes des exceptions, j'ai tendance à éviter de telles solutions (mais elles fonctionnent).

Quoi qu'il en soit, j'espère que cela vous donnera une idée de pourquoi cela ne fonctionne pas toujours exactement de la même manière que PHP.

+0

Si vous voulez vraiment vous amuser avec les numéros de ligne _without_ throwing exceptions, vous pouvez écrire votre propre 'ClassLoader' qui serait capable de vous fournir une facilité pour obtenir la table de numéros de ligne; Cependant, vous devrez peut-être écrire votre propre extension dans Thread pour avoir une interface utilisable avec l'instruction bytecode actuelle de la JVM. C'est faisable, comme le lancer d'exception le fait pour vous déjà, mais c'est beaucoup de travail pour quelque chose qui est généralement inutile avec une journalisation différemment structurée. –

+0

Merci pour ça! Je comprends la différence entre les langages compilés et interprétés et je sais que l'obtention des numéros de ligne pour Java exécuté (ou n'importe quel langage compilé) n'est pas vraiment trivial. J'ai décidé d'aller avec Cobertura pour générer le rapport. Je n'ai jamais utilisé un outil de couverture de code auparavant, donc ça va me prendre un peu de temps pour comprendre. Voir le commentaire ci-dessous ce post. De l'aide serait grandement appréciée. Merci beaucoup! – DanB91

1

Jetez un coup d'œil à Cobertura. Il calcule la couverture et ce genre de choses, et s'il ne le fait pas déjà, il devrait être relativement facile d'ajouter le numéro de ligne qui s'y rapporte. Il y a une tentative très fâcheuse de le faire, mais c'est tellement lent que vous ne pourrez pas l'utiliser en production https://bitbucket.org/jowu/myriapod/wiki/Home

+0

J'ai regardé cobertura et il semble faire ce que je veux qu'il fasse. Les numéros de ligne que nous voulons sont dans un fichier XML, donc nous pouvons juste l'analyser. Mais j'ai vraiment du mal à faire fonctionner le programme Java via la ligne de commande. L'ordre est-il de générer le chemin d'accès au code pour l'instrument, l'exécution et la génération de rapports? J'essaye ceci et il génère le chemin de code mais il montre que le programme n'a jamais été exécuté (toutes les lignes sont rouges). Quelles sont les étapes pour générer cela? – DanB91

+0

Je ne peux que vous renvoyer à la documentation de cobertura pour cela: http://cobertura.sourceforge.net/introduction.html. Vous devrez peut-être recompiler/reconstruire votre projet chaque fois que vous essayerez de l'instrumenter et cela échouera, mais au-delà, je n'ai jamais eu de problème pour obtenir ce travail et votre question ne contient pas assez d'informations pour m'aider. . – Jochen

0

Je n'ai jamais fait ou vu quelque chose comme ça, mais cela me semble un problème intéressant. Ma pensée serait d'utiliser the java debugger (jdb) pour exécuter le code, plutôt que de simplement la commande java.

Vous pouvez parcourir le code ligne par ligne (via la commande step dans jdb) et chaque fois qu'une ligne exécute son numéro de ligne est craché. Cela demanderait un peu d'aide du côté PHP (il faudrait analyser le numéro de ligne et exécuter la commande step suivante) mais les numéros de ligne sont là. Voici un exemple de sortie d'un programme Java très basique.

Java (TestClass.java)

public class TestClass { 
    public static void main(String[] args) { 
     System.out.println("foo"); 
     System.out.println("bar"); 
    } 
} 

JDB (JDB TestClass après l'exécution javac TestClass.java)

Initializing jdb ... 
> stop at TestClass:3 
Deferring breakpoint TestClass:3. 
It will be set after the class is loaded. 
> run 
run TestClass 
Set uncaught java.lang.Throwable 
Set deferred uncaught java.lang.Throwable 
> 
VM Started: Set deferred breakpoint TestClass:3 

Breakpoint hit: "thread=main", TestClass.main(), line=3 bci=0 
3   System.out.println("foo"); 

main[1] step 
> foo 

Step completed: "thread=main", TestClass.main(), line=4 bci=8 
4   System.out.println("bar"); 

main[1] step 
> bar 

Step completed: "thread=main", TestClass.main(), line=5 bci=16 
5  } 

main[1] step 
> 
The application exited 
0

Essayez référence à ce lien JVMDI

Vous pouvez essayer d'accéder à les valeurs du compteur de programme, puis le mapper sur le lineNumberTable. OU Je pense que JVMDI a une méthode qui peut accéder au numéro de ligne du code d'exécution. Je ne suis pas sûr de ce dernier, reportez-vous au lien ci-dessus et espérons que cela aide.