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.