Pyjnius: No se pudo encontrar el constructor cuando hay varios constructores (sobrecargados)

Creado en 22 oct. 2020  ·  8Comentarios  ·  Fuente: kivy/pyjnius

Encontré un error con pyjnius cuando se trataba de una clase Java con varios constructores.

Cuando ejecuté el siguiente código Java, el método principal invocará el segundo constructor y terminará con gracia.
Cuando ejecuto el código de Python a continuación, informará que no se encuentra el constructor.
(jnius.JavaException: No constructor matching your arguments, available: ['(ILjava/lang/String;)V', '(ILjava/lang/String;Ljava/lang/Object;[I)V'])
Pero cuando eliminé el primer constructor en el código java, mi código Python con pyjnius puede encontrar correctamente el único constructor y terminar con gracia.

Clase 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 con 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()

Comentario más útil

Cuando pyjnius llama a un método o constructor, primero verifica si hay 0, 1 o varios constructores o métodos con el nombre de pila. Si solo hay 1, siempre hace la llamada, esperando lo mejor. Si son múltiples, realiza este proceso de puntuación para intentar decidir si cada uno es aceptable o no. Ojalá uno y solo uno sea aceptable; si no, arroja un error.

En este caso, se rechazan ambos ya que los constructores son inaceptables. El uso de una pista de firma soluciona el problema haciendo que se salte el proceso de puntuación. La pista de la firma es una buena solución.

Para este problema, eché un vistazo más de cerca al código y descubrí que, de hecho, hay un error que está causando que esto falle. Y felizmente es una solución fácil. Haré un PR con una prueba unitaria en un momento.

Todos 8 comentarios

¿Ha intentado utilizar una pista de firma de constructor?

Consulte https://github.com/kivy/pyjnius/blob/307659b13c1e5583fcb25603b7d3732265ffd4a0/tests/test_constructor.py#L54 para ver un ejemplo.

Cuando pyjnius llama a un método o constructor, primero verifica si hay 0, 1 o varios constructores o métodos con el nombre de pila. Si solo hay 1, siempre hace la llamada, esperando lo mejor. Si son múltiples, realiza este proceso de puntuación para intentar decidir si cada uno es aceptable o no. Ojalá uno y solo uno sea aceptable; si no, arroja un error.

En este caso, se rechazan ambos ya que los constructores son inaceptables. El uso de una pista de firma soluciona el problema haciendo que se salte el proceso de puntuación. La pista de la firma es una buena solución.

Para este problema, eché un vistazo más de cerca al código y descubrí que, de hecho, hay un error que está causando que esto falle. Y felizmente es una solución fácil. Haré un PR con una prueba unitaria en un momento.

¿Ha intentado utilizar una pista de firma de constructor?

Ver

https://github.com/kivy/pyjnius/blob/307659b13c1e5583fcb25603b7d3732265ffd4a0/tests/test_constructor.py#L54

para un ejemplo.

Intenté agregar una firma como se muestra en el código a continuación hace un momento, pero emitió un error de afirmación. ¿Dónde me equivoqué?

Error

  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 con 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()

Aquí está el 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 qué no se pueden usar sugerencias de firma con argumentos variables?

No importa, lo descubrí y tengo una solución para esto. Lo agregaré al PR.

@enjoybeta Arreglé esto en el PR, pero en

@cmacdonald , ¿hay otra solución alternativa que puedan usar aquí?

Nada en la parte superior de mi cabeza: ¿agregar una clase de fábrica Java rápida que llame al constructor varargs?

De todos modos, propongo que podamos cerrar el problema ya que la próxima versión de Jnius solucionará el error.

¡Buena idea! Un método de fábrica puede encargarse de ello si una opción es alterar ese código fuente. De lo contrario, pueden crear una clase de utilidad auxiliar separada que lo haga por ellos.

De acuerdo, podemos cerrar este tema ahora.

¿Fue útil esta página
0 / 5 - 0 calificaciones