Написание нативных методов

J2ObjC поддерживает встраивание Objective-C в собственные методы Java, очень похоже на то, как JSNI GWT поддерживает встраивание JavaScript. Основное различие между встраиванием J2ObjC и GWT заключается в том, что J2ObjC использует /*-[ и ]-*/ для описания кода Objective-C. Это средство называется OCNI (Objective-C Native Interface), чтобы отличаться от JSNI GWT.

Вот пример из версии java.lang.System библиотеки эмуляции JRE:

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

J2ObjC копирует комментарий без разделителей, чтобы создать тело метода:

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

Родной импорт

J2ObjC сканирует транслируемый код Java, чтобы добавить директивы #import для его зависимостей, а также импортировать платформу Foundation. Однако любой импорт, необходимый только для собственного кода, необходимо добавлять отдельно. Чтобы добавить импорт, добавьте раздел OCNI над первым классом в исходном файле Java и укажите там импорт; например:

  package my.project;

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

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

В приведенном выше примере импорт необходим, поскольку единственное место, где ссылается на этот тип, — это собственный код.

Родные блоки

Внутри тела класса J2ObjC сканирует блоки OCNI. Эти блоки добавляются в переведенный файл без изменений, в той же позиции относительно переведенных членов класса. Вот пример:

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

Эту функцию C можно вызвать из любых собственных методов, объявленных после этого блока OCNI.

Специальный вариант этого блока OCNI вставляет код в сгенерированный заголовок вместо файла .m: /*-HEADER[...]

Вызов методов Java из машинного кода

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);
]-*/;

Доступ к полям из собственного кода

Чтобы прочитать поле экземпляра, используйте myInstanceField_ или self->myInstanceField_ . Завершающий суффикс позволяет избежать конфликта с методами с тем же именем.

Обратите внимание, что поля с зарезервированными именами будут иметь два подчеркивания. Например, поле с именем «id» допустимо в Java, но не в Objective C. При переводе это поле будет называться «id__». Поэтому проверьте сгенерированные файлы на наличие ошибок компилятора «нет такого поля».

Чтобы записать в поле экземпляра объекта, используйте JSNIExample_set_myInstanceField(string)

Прочитайте статическое поле: JSNIExample_get_myStaticField()

Напишите статическое поле: JSNIExample_set_myStaticField(value)

J2ObjC и GWT

Были выбраны разные разделители, чтобы в следующем выпуске J2ObjC комментарии GWT JSNI были проигнорированы (ранее те же разделители использовались в качестве GWT). Это означает, что один исходный код Java может иметь собственные методы, имеющие реализации Objective-C, GWT и Android (через JNI):

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

J2ObjC и Android

Реализации собственных методов J2ObjC и Android «просто работают», поскольку собственные методы Android реализованы в отдельном файле JNI C или C++. Любые комментарии OCNI в классах Java удаляются при компиляции javac для Android или любой другой платформы Java.