Trouvé un bogue avec pyjnius lors du traitement d'une classe Java avec plusieurs constructeurs.
Lorsque j'ai exécuté le code Java ci-dessous, la méthode principale invoquera le 2ème constructeur et se terminera normalement.
Lorsque j'exécute le code python ci-dessous, il signalera que le constructeur est introuvable.
(jnius.JavaException: No constructor matching your arguments, available: ['(ILjava/lang/String;)V', '(ILjava/lang/String;Ljava/lang/Object;[I)V'])
Mais lorsque j'ai supprimé le 1er constructeur dans le code java, mon code python avec pyjnius peut trouver correctement le seul constructeur et finir en beauté.
Classe Java
public class SampleJavaClass {
public SampleJavaClass( int arg1, String arg2, int arg3, Object arg4, int... arg5 ) {
System.out.println("arg1: " + Integer.toString(arg1));
System.out.println("arg2: " + arg2);
System.out.println("arg3: " + arg3);
System.out.println("arg3: " + arg4);
System.out.println("arg4: " + arg5.toString());
}
// the constructor plans to use
public SampleJavaClass (int arg1, String arg2, Object arg3, int... arg4) {
System.out.println("arg1: " + Integer.toString(arg1));
System.out.println("arg2: " + arg2);
System.out.println("arg3: " + arg3);
System.out.println("arg4: " + arg4.toString());
}
public static void main(String[] args) {
SampleJavaClass test = new SampleJavaClass(1, "var2", null, 4);
}
}
Code Python avec pyjnius
import os
currentPath = os.getcwd()
classpath = currentPath + "/SampleJavaClass.class"
import jnius_config
jnius_config.set_classpath('.', classpath)
from jnius import autoclass
def main():
SampleJavaClass = autoclass("SampleJavaClass")
SampleJavaClass(1, "var2", None, 4)
print("Execution finished!")
if __name__ == "__main__":
main()
avez-vous essayé d'utiliser un indice de signature de constructeur ?
Voir https://github.com/kivy/pyjnius/blob/307659b13c1e5583fcb25603b7d3732265ffd4a0/tests/test_constructor.py#L54 pour un exemple.
Lorsque pyjnius appelle une méthode ou un constructeur, il vérifie d'abord s'il existe 0, 1 ou plusieurs constructeurs ou méthodes avec le nom donné. S'il n'y en a qu'un, il appelle toujours, en espérant le meilleur. S'il y en a plusieurs, il effectue ce processus de notation pour essayer de décider si chacun est acceptable ou non. Espérons qu'un et un seul est acceptable ; sinon, il renvoie une erreur.
Dans ce cas, il rejette les deux car les constructeurs sont inacceptables. L'utilisation d'un indice de signature contourne le problème en lui faisant sauter le processus de notation. L'indice de signature est une bonne solution de contournement.
Pour ce problème, j'ai examiné de plus près le code et j'ai découvert qu'il y avait en fait un bogue qui faisait échouer cela. Et heureusement, c'est une solution facile. Je ferai un PR avec un test unitaire dans un instant.
avez-vous essayé d'utiliser un indice de signature de constructeur ?
Voir
à titre d'exemple.
J'ai essayé d'ajouter une signature comme indiqué par le code ci-dessous tout à l'heure, mais elle a émis une erreur d'assertion. Où ai-je foiré ?
Erreur
File "jnius/jnius_export_class.pxi", line 270, in jnius.JavaClass.__init__
File "jnius/jnius_export_class.pxi", line 319, in jnius.JavaClass.call_constructor
AssertionError
Code Python avec pyjnius
import os
currentPath = os.getcwd()
classpath = currentPath + "/SampleJavaClass.class"
import jnius_config
jnius_config.set_classpath('.', classpath)
from jnius import autoclass
def main():
SampleJavaClass = autoclass("SampleJavaClass")
SampleJavaClass(1, "var2", None, 4, signature="(ILjava/lang/String;Ljava/lang/Object;[I)V")
print("Execution finished!")
if __name__ == "__main__":
main()
Voici le code correspondant :
requestedDefn = kwargs.pop('signature', None)
for definition, is_varargs in definitions:
found_definitions.append(definition)
d_ret, d_args = parse_definition(definition)
if requestedDefn == definition:
assert not is_varargs
scores=[]
score=1
scores.append((score, definition, d_ret, d_args, args))
break
Pourquoi les indices de signature ne peuvent-ils pas être utilisés avec des arguments variables ?
Peu importe, j'ai compris et j'ai une solution à cela. Je vais l'ajouter au PR.
@enjoybeta J'ai corrigé cela dans le PR, mais en fin de compte, la solution de contournement de l'indice de signature ne fonctionne pas dans la version actuelle.
@cmacdonald , existe-t-il une autre solution de contournement qu'ils peuvent utiliser ici ?
Rien de ce qui me vient à l'esprit - ajouter une classe d'usine Java rapide qui appelle le constructeur varargs ?
Quoi qu'il en soit, je propose que nous puissions clore le problème car la prochaine version de Jnius corrigera le bogue.
Bonne idée! Une méthode d'usine peut s'en occuper si la modification de ce code source est une option. Sinon, ils peuvent créer une classe d'utilitaire d'assistance distincte qui le fait pour eux.
D'accord, nous pouvons clore ce problème maintenant.
Commentaire le plus utile
Lorsque pyjnius appelle une méthode ou un constructeur, il vérifie d'abord s'il existe 0, 1 ou plusieurs constructeurs ou méthodes avec le nom donné. S'il n'y en a qu'un, il appelle toujours, en espérant le meilleur. S'il y en a plusieurs, il effectue ce processus de notation pour essayer de décider si chacun est acceptable ou non. Espérons qu'un et un seul est acceptable ; sinon, il renvoie une erreur.
Dans ce cas, il rejette les deux car les constructeurs sont inacceptables. L'utilisation d'un indice de signature contourne le problème en lui faisant sauter le processus de notation. L'indice de signature est une bonne solution de contournement.
Pour ce problème, j'ai examiné de plus près le code et j'ai découvert qu'il y avait en fait un bogue qui faisait échouer cela. Et heureusement, c'est une solution facile. Je ferai un PR avec un test unitaire dans un instant.