Cómo escribir métodos nativos

J2ObjC admite la incorporación de Objective-C en métodos nativos de Java, algo muy similar a cómo JSNI de GWT admite la incorporación de JavaScript. La principal diferencia entre la incorporación de J2ObjC y la de GWT es que J2ObjC usa /*-[ y ]-*/ para delinear el código Objective-C. Esta instalación se denomina OCNI (interfaz nativa de Objective-C) para diferenciarse de la JSNI de GWT.

Este es un ejemplo de la versión de java.lang.System de la biblioteca de emulación de JRE:

  public static native long currentTimeMillis() /*-[
    // Use NSDate
    return (long long) ([[NSDate date] timeIntervalSince1970] * 1000);
  ]-*/;

J2ObjC copia el comentario, menos los delimitadores, para crear el cuerpo del método:

  + (long long int)currentTimeMillis {
    // Use NSDate
    return (long long) ([[NSDate date] timeIntervalSince1970] * 1000);
  }

Importaciones nativas

J2ObjC analiza el código Java que se traduce a fin de agregar directivas #import para sus dependencias, además de importar el framework de Foundation. Sin embargo, cualquier importación que sea necesaria solo para el código nativo debe agregarse por separado. Para agregar importaciones, agrega una sección OCNI encima de la primera clase en el archivo fuente Java y especifica las importaciones allí; por ejemplo:

  package my.project;

  /*-[
  #import "java/lang/NullPointerException.h"
  ]-*/

  public class Test {
    native void test() /*-[
      @throw [[JavaLangNullPointerException alloc] init];
    ]-*/;
  }

En el ejemplo anterior, la importación es necesaria porque el único lugar al que se hace referencia a ese tipo es en el código nativo.

Bloques nativos

Dentro de un cuerpo de clase, J2ObjC busca bloques de OCNI. Estos bloques se agregan sin modificar al archivo traducido, en la misma posición relativa a los miembros de la clase traducidos. Por ejemplo:

  /*-[
    static void log(NSString *msg) {
      NSLog(@"%@", msg);
    }
  ]-*/;

Esta función C se puede invocar desde cualquier método nativo que se declare después de este bloque de OCNI.

Una variante especial de este bloque de OCNI inserta código en el encabezado generado en lugar del archivo .m: /*-HEADER[...]

Cómo invocar métodos de Java desde código nativo

public native void bar(JSNIExample x, String s) /*-[
  // Call instance method instanceFoo() on this
  [self instanceFooWithNSString:s];

  // Call instance method instanceFoo() on x
  [x instanceFooWithNSString:s];

  // Call static method staticFoo()
  JSNIExample_staticFooWithNSString_(s);
]-*/;

Cómo acceder a los campos desde código nativo

Para leer un campo de instancia, usa myInstanceField_ o self->myInstanceField_. El sufijo final evita un conflicto con los métodos que tienen el mismo nombre.

Ten en cuenta que los campos que tienen nombres reservados tendrán dos guiones bajos. Por ejemplo, un campo llamado "id" es legal en Java, pero no en el objetivo C. Cuando se traduzca, ese campo tendrá el nombre "id__". Por lo tanto, comprueba los archivos generados si hay errores del compilador que "no existe tal campo".

Para escribir en un campo de instancia de objeto, usa JSNIExample_set_myInstanceField(string).

Lee un campo estático: JSNIExample_get_myStaticField()

Escribe un campo estático: JSNIExample_set_myStaticField(value).

J2ObjC y GWT

Se eligieron diferentes delimitadores para que, en la próxima versión de J2ObjC, se ignoren los comentarios de JSNI de GWT (anteriormente, se utilizaban los mismos delimitadores como GWT). Esto significa que una sola fuente de Java puede tener métodos nativos que tengan implementaciones de Objective-C, GWT y Android (a través de JNI):

  static native void log(String text) /*-{ // left-brace for JavaScript
    console.log(text);
  }-*/ /*-[                                // left-bracket for Objective-C
     NSLog(@"%@", text);
  ]-*/;

J2ObjC y Android

Las implementaciones de métodos nativos de Android y J2ObjC "simplemente funcionan" porque los métodos nativos de Android se implementan en un archivo C o C++ de JNI independiente. Se quitan todos los comentarios de OCNI en las clases de Java cuando se compila con javac para Android o cualquier otra plataforma de Java.