Encontrado um bug com pyjnius ao lidar com uma classe Java com vários construtores.
Quando eu executei o código Java abaixo, o método principal invocará o segundo construtor e terminará normalmente.
Quando eu executar o código Python abaixo, ele relatará que o construtor não foi encontrado.
(jnius.JavaException: No constructor matching your arguments, available: ['(ILjava/lang/String;)V', '(ILjava/lang/String;Ljava/lang/Object;[I)V'])
Mas quando removi o primeiro construtor no código java, meu código python com pyjnius pode encontrar corretamente o único construtor e terminar com perfeição.
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);
}
}
Código Python com 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()
você tentou usar uma dica de assinatura do construtor?
Consulte https://github.com/kivy/pyjnius/blob/307659b13c1e5583fcb25603b7d3732265ffd4a0/tests/test_constructor.py#L54 para obter um exemplo.
Quando pyjnius chama um método ou construtor, ele primeiro verifica se há 0, 1 ou vários construtores ou métodos com o nome fornecido. Se houver apenas 1, ele sempre fará a decisão, esperando o melhor. Se houver vários, ele faz esse processo de pontuação para tentar decidir se cada um é aceitável ou não. Esperançosamente, um e apenas um é aceitável; caso contrário, ele gera um erro.
Nesse caso, ele está rejeitando ambos, pois os construtores são inaceitáveis. Usar uma dica de assinatura contorna o problema, fazendo com que ela ignore o processo de pontuação. A dica de assinatura é uma boa solução alternativa.
Para esse problema, examinei o código mais de perto e descobri que, na verdade, há um bug que está causando a falha dele. E felizmente é uma solução fácil. Vou fazer um PR com um teste de unidade em um momento.
você tentou usar uma dica de assinatura do construtor?
Ver
Por exemplo.
Tentei adicionar uma assinatura conforme mostrado pelo código abaixo agora, mas emitiu um erro de declaração. Onde eu errei?
Erro
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
Código Python com 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()
Aqui está o código relevante:
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
Por que as dicas de assinatura não podem ser usadas com argumentos variáveis?
Não importa, eu descobri e tenho uma solução para isso. Vou adicioná-lo ao PR.
@enjoybeta Corrigi isso no PR, mas no final das
@cmacdonald , há outra solução alternativa que eles possam usar aqui?
Nada do topo da minha cabeça - adicionar uma classe de fábrica Java rápida que chama o construtor varargs?
De qualquer forma, proponho que possamos resolver o problema, pois a próxima versão do Jnius corrigirá o bug.
Boa ideia! Um método de fábrica pode cuidar disso se alterar o código-fonte for uma opção. Caso contrário, eles podem criar uma classe de utilitário auxiliar separada que faça isso por eles.
Concordo, podemos encerrar esse problema agora.
Comentários muito úteis
Quando pyjnius chama um método ou construtor, ele primeiro verifica se há 0, 1 ou vários construtores ou métodos com o nome fornecido. Se houver apenas 1, ele sempre fará a decisão, esperando o melhor. Se houver vários, ele faz esse processo de pontuação para tentar decidir se cada um é aceitável ou não. Esperançosamente, um e apenas um é aceitável; caso contrário, ele gera um erro.
Nesse caso, ele está rejeitando ambos, pois os construtores são inaceitáveis. Usar uma dica de assinatura contorna o problema, fazendo com que ela ignore o processo de pontuação. A dica de assinatura é uma boa solução alternativa.
Para esse problema, examinei o código mais de perto e descobri que, na verdade, há um bug que está causando a falha dele. E felizmente é uma solução fácil. Vou fazer um PR com um teste de unidade em um momento.