example - my icon java
Buscando una manera conveniente de llamar a Java desde C++ (10)
Parece que la mayoría de la documentación o las bibliotecas auxiliares relacionadas con JNI (Interfaz nativa de Java) están relacionadas con llamar código nativo desde Java. Este parece ser su uso principal, aunque es capaz de más.
Quiero trabajar principalmente en la dirección opuesta: modificar un programa C ++ portátil existente (bastante grande) agregándole algunas bibliotecas de Java. Por ejemplo, quiero hacerlo llamar bases de datos a través de JDBC, o sistemas de colas de mensajes a través de JMS, o enviar correos electrónicos, o llamar a mis propias clases de Java, etc. Pero con JNI en bruto esto es bastante desagradable y propenso a errores.
Así que, idealmente, me gustaría escribir código C ++ que pueda llamar a clases de Java tan fácilmente como C ++ / CLI puede llamar a clases CLR. Algo como:
using namespace java::util::regex; // namespaces mapped
Pattern p = Pattern.compile("[,//s]+");
array<java::lang::String> result =
p.split("one,two, three four , five");
for (int i=0; i < result.length(); i++)
std::cout << result[i] << std::endl;
De esta manera, no tendría que hacer manualmente el trabajo de obtener el ID de método al pasar el nombre y las cadenas de firma extrañas , y estaría protegido de los errores de programación causados por las API sin marcar para los métodos de llamada. De hecho, se parecería mucho a Java equivalente.
NÓTESE BIEN. Todavía estoy hablando sobre el uso de JNI! Como tecnología subyacente es perfecta para mis necesidades. Es "en proceso" y altamente eficiente. No quiero ejecutar Java en un proceso separado y hacer llamadas RPC. JNI en sí está bien. Sólo quiero una interfaz agradable para ello.
Debería haber una herramienta de generación de código para crear clases de C ++, espacios de nombres, métodos, etc. equivalentes para que coincidan exactamente con lo que expone un conjunto de clases de Java que yo especifique. Las clases de C ++ generadas serían:
- Tenga funciones miembro que acepten versiones envueltas de manera similar de sus parámetros y luego realice el vudú JNI necesario para realizar la llamada.
- Envuelva los valores de retorno de la misma manera para que pueda encadenar llamadas de forma natural.
- Mantenga un caché estático por clase de ID de métodos para evitar buscarlos cada vez.
- Ser totalmente seguro para hilos, portátil, de código abierto.
- Verifique automáticamente las excepciones después de cada llamada de método y produzca una excepción estándar de C ++.
- También trabajo para cuando estoy escribiendo métodos nativos de la manera habitual de JNI pero necesito llamar a otro código Java.
- La matriz debe funcionar de manera totalmente consistente entre tipos y clases primitivas.
- Sin duda, necesitaremos algo como global para envolver las referencias cuando necesiten sobrevivir fuera de un marco de referencia local. De nuevo, debería funcionar igual para todas las referencias de matriz / objeto.
¿Existe una biblioteca / herramienta gratuita, de código abierto, portátil o estoy soñando?
Nota: Encontré esta pregunta existente, pero el OP en ese caso no era tan exigente de perfección como lo estoy siendo ...
Actualización: un comentario sobre SWIG me llevó a esta pregunta anterior , que parece indicar que se trata principalmente de la dirección opuesta y por lo tanto no haría lo que quiero.
IMPORTANTE
- Se trata de poder escribir código C ++ que manipula clases y objetos Java, no al revés (¡vea el título!)
- Ya sé que JNI existe (¡vea la pregunta!) Pero el código escrito a mano para las API de JNI es innecesariamente detallado, repetitivo, propenso a errores, no se verifica el tipo en tiempo de compilación, etc. Si desea almacenar en caché los ID de método y la clase objetos es aún más detallado. Quiero generar automáticamente clases de envoltorio de C ++ que se encarguen de todo eso por mí.
Actualización: comencé a trabajar en mi propia solución:
https://github.com/danielearwicker/cppjvm
Si esto ya existe, por favor hágamelo saber!
NÓTESE BIEN. Si está considerando usar esto en su propio proyecto, siéntase libre, pero tenga en cuenta que en este momento el código tiene algunas horas de antigüedad, y hasta ahora solo escribí tres pruebas muy poco rigurosas.
¿Qué pasa con el uso de Thrift o Protocol Buffers para facilitar sus llamadas de Java a C ++?
Como CORBA no parece ser lo que desea, aquí hay enlaces que describen cómo iniciar JVM desde C / C ++ y cómo llamar a los métodos de JAVA.
http://java.sun.com/docs/books/jni/html/invoke.html y http://java.sys-con.com/node/45840
PD: al establecer una interfaz de Java con C ++, también deberías echar un vistazo a JNA o bridj .
El artículo Java Tip 17: Integrating Java con C ++ describe cómo hacerlo en detalle.
Re llamando a Java desde C ++.
Puedes hacer lo que desees, pero debes dejar que Java tenga el control. Lo que quiero decir con esto es que creas hilos de Java que llaman al código nativo y desde allí se bloquean, esperando que tu código nativo le dé algo que hacer. Crea tantos hilos de Java como necesites para realizar el trabajo / throuhput suficiente.
Entonces, su aplicación de C ++ se inicia, crea una JVM / JavaVM (de acuerdo con la forma documentada, el ejemplo existe en el código base qtjambi que se muestra a continuación), esto a su vez realiza la inicialización JNI habitual y System.loadLibrary () y proporciona a los JARs "nativos" enlace. A continuación, inicializa un montón de subprocesos y llama a algún código JNI (que creó) donde pueden bloquear a la espera de que su código C ++ les dé algo de trabajo.
Su código C ++ (probablemente de otro hilo) luego configura y pasa toda la información necesaria a uno de los trabajadores de Java Thread bloqueados y en espera, luego se le da la orden de ejecutarse, luego puede volver al código Java puro para hacerlo. Trabajar y volver con un resultado.
...
Es posible configurar, crear y contener una instancia de JavaVM desde el código C ++. Esto puede ser forzado a alimentar su propio CLASSPATH / JARs para configurar el entorno contenido que necesita encapsulado dentro de su programa C ++.
Esquema de eso como estoy seguro de que ya ha encontrado en http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html
...
Hay un tipo de generador JNI de C ++ => Java en el proyecto QtJambi (en el que trabajo y ayudo a mantener). Esto es bastante a medida para el kit de herramientas de Qt, pero esencialmente traduce un grupo de archivos de encabezado de C ++ en una colección de archivos .cpp / .h de C ++ y el archivo * .java para proporcionar vinculación y contención de shell del objeto para que los esquemas de asignación de memoria de la competencia jugar bien juntos Tal vez haya algo que quitar de esto.
Esta es sin duda una prueba de lo que está pidiendo: el generador qtjambi está incluido en el proyecto (pero podría hacerse independiente con algún trabajo) y esto tiene licencia LGPL (código abierto). El kit de herramientas Qt no es una API pequeña, pero puede generar cientos de clases para cubrir un alto porcentaje de API (> 85% y casi el 100% de las piezas Core / GUI).
HTH
Respondiendo a mi propia pregunta:
No parece ser un proyecto activo. El autor recomienda que no se utilice con JDK 1.5 o posterior.
Parece tener un problema grave: pasa los punteros desnudos a sus objetos de envoltura:
java::lang::Integer* i = new java::lang::Integer("10");
delete i; // don''t forget to do this!
También causa un problema más sutil que para representar la compatibilidad de la asignación (por ejemplo, una clase como un subtipo de la interfaz que implementa) las envolturas deben heredarse unas de otras.
Sí, hay herramientas existentes que hacen exactamente esto: generar envoltorios de C ++ para clases de Java. Esto hace que el uso de las API de Java en C ++ sea más transparente y agradable, con menor costo y riesgo.
El que más he usado es JunC++ion . Es maduro, potente y estable. El autor principal es muy agradable y muy sensible. Desafortunadamente, es un producto comercial, y caro.
Jace es una herramienta gratuita de código abierto con una licencia BSD. Han pasado años desde la última vez que jugué con jace. Parece que todavía hay algún desarrollo activo. (Todavía recuerdo la publicación de USENET realizada por el autor original, hace más de una década, y básicamente le hice la misma pregunta que a usted).
Si necesita admitir devoluciones de llamada de Java a C ++, es útil definir clases de C ++ que implementen interfaces de Java. Al menos JunC ++ ion le permite pasar dichas clases de C ++ a métodos Java que aceptan devoluciones de llamada. La última vez que probé con Jace, no era compatible con esto, pero eso fue hace siete años.
Soy uno de los arquitectos principales de los productos de integración de lenguaje de Codemesh, incluido JunC ++ ion. Hemos estado haciendo este tipo de integración desde 1999 y funciona muy bien. El mayor problema no es la parte JNI. JNI es tedioso y difícil de depurar, pero una vez que lo haces bien, casi siempre funciona. De vez en cuando, te interrumpe una JVM o una actualización del sistema operativo, y luego tienes que ajustar tu producto, pero en general es estable.
El mayor problema es el mapeo del sistema de tipos y las compensaciones entre la usabilidad general y la solución específica. Por ejemplo, declara que no le gusta el hecho de que JACE trate todas las referencias de objetos como globales. Hacemos lo mismo (con algunas escotillas de escape) porque resulta que este es el comportamiento que funciona mejor para el 95% de los clientes, incluso si perjudica el rendimiento. Si va a publicar una API o un producto, debe elegir los valores predeterminados que hagan que las cosas funcionen para la mayoría de las personas. Elegir las referencias locales como la opción predeterminada sería incorrecto porque cada vez más personas escriben aplicaciones de multiproceso, y muchas API de Java que las personas quieren usar desde otros lenguajes son intrínsecamente multihebra con devoluciones de llamada asíncronas y similares.
También descubrimos que realmente desea dar a las personas un generador de código basado en GUI para crear la especificación de integración. Una vez que lo han especificado, utiliza la versión CLI para integrarlo en la compilación nocturna.
Buena suerte con tu proyecto. Es mucho trabajo hacer bien. Pasamos varios años en él y todavía lo estamos mejorando regularmente.
Tal vez un martillo demasiado grande para este clavo, pero ¿no es para eso que fue construido CORBA ?
También tuve muchas dificultades para que JNI funcionara en diferentes sistemas operativos, para hacer frente a arquitecturas de 32/64 bits y para asegurarse de que se encontraran y cargaran las bibliotecas compartidas correctas. Me pareció que CORBA (MICO y Jacorb) también era difícil de usar.
No encontré una forma efectiva de llamar desde C / C ++ a Java y mis soluciones preferidas en esta situación son ejecutar mi código Java como:
un programa independiente que puedo ejecutar fácilmente desde programas C / C ++ con
java -cp myjar.jar org.foo.MyClass
. Supongo que esto es demasiado simplista para su situación.Como mini servidor, aceptar solicitudes de programas C / C ++ en un socket TCP / IP y devolver resultados a través de este socket también. Esto requiere escribir funciones de red y de serialización, pero desacopla los procesos C / C ++ y Java, y puede identificar claramente cualquier problema que se encuentre en el lado C ++ o Java.
Como Servlet en Tomcat y realice solicitudes HTTP desde mi programa C / C ++ (también funcionarán otros contenedores de servlet). Esto también requiere escribir redes y serializar funciones. Esto es más como SOA.
Tuve casi los mismos problemas, terminé haciéndolo por mi cuenta, tal vez esto ayude a alguien.
Tiene una pequeña huella de tiempo de ejecución (<30kb), gestiona las referencias y admite la generación de interfaces de clase Java. Es decir, LocalRef> stringArray; y luego usando stringArray [1] -> getBytes () o algo así.