Назад     Оглавление    Индекс     Вперёд

Ядро JavaScript 1.5. Руководство по Использованию.




Глава 9  LiveConnect. Обзор.



 

В этой главе рассматривается использование технологии LiveConnect, обеспечивающей совместную работу кодов, написанных на Java и JavaScript. Предполагается, что Вы уже знакомы с программированием на Java.


В главе имеются следующие разделы:
 


Дополнительную информацию об использовании LiveConnect см. в технических замечаниях по JavaScript на сайте DevEdge.




Работа с Оболочками



В JavaScript wrapper\оболочка это объект целевого типа данных языка, содержащий объект исходного языка. При программировании на JavaScript Вы можете использовать объект-оболочку для доступа к методам и полям Java-объекта; вызов методов или доступ к свойству в wrapper вызывает Java-объект. На стороне Java объекты JavaScript "обёртываются" в экземпляры класса netscape.javascript.JSObject и передаются в Java.


Если JavaScript-объект посылается в Java, машина времени выполнения создаёт Java-оболочку типа JSObject; когда JSObject посылается из Java в JavaScript, машина времени выполнения разворачивает его в оригинальный тип объекта JavaScript. Класс JSObject предоставляет интерфейс для вызова методов JavaScript и проверки JavaScript-свойств.




Взаимодействие JavaScript и Java



Если Вы ссылаетесь на пакет или класс Java или работаете с объектом или массивом Java, Вы используете один из специальных объектов LiveConnect. Весь доступ JavaScript к Java осуществляется через эти объекты, резюме по которым - в следующей таблице.


Таблица 9.1   Объекты LiveConnect
 
Объект Описание

JavaArray

Обёрнутый массив Java, к которому имеется доступ из кода JavaScript.

JavaClass

Ссылка JavaScript на Java-класс.

JavaObject

Обёрнутый объект Java, к которому имеется доступ из кода JavaScript.

JavaPackage

Ссылка JavaScript на Java-пакет.


Примечание

Поскольку Java является строго типизированным языком, а JavaScript типизирован слабо, машина выполнения JavaScript конвертирует значения аргументов в типы данных, подходящие для других языков, если Вы используете LiveConnect. См. Конвертация Типов Данных.


Иногда существование объектов LiveConnect достаточно прозрачно, поскольку Вы взаимодействуете с Java в довольно интуитивной манере. Например, Вы можете создать объект Java String и присвоить его в JavaScript переменной myString путём использования оператора new с конструктором Java таким вот образом:


var myString = new java.lang.String("Hello world")


Здесь переменная myString является JavaObject, поскольку она содержит экземпляр Java-объекта String. Как JavaObject, myString имеет доступ к public-методам экземпляра java.lang.String и его суперкласса, java.lang.Object. Эти Java-методы доступны в JavaScript как методы из JavaObject, и Вы можете вызывать их так:


myString.length() // возвращает 11



Объект Packages



Если Java-класс не является частью пакетов java, sun или netscape, Вы можете получить к нему доступ через объект Packages. Например, предположим, корпорация Redwood использует Java-пакет под названием redwood как контейнер различных Java-классов. Чтобы создать экземпляр класса HelloWorld из redwood, Вы осуществляете доступ к конструктору класса так:


var red = new Packages.redwood.HelloWorld()


Вы можете также иметь  доступ к классам в пакете по умолчанию (то есть к классам, не указывающим пакет явно). Например, если класс HelloWorld находится непосредственно в пути CLASSPATH, а не в пакете, Вы можете получить к нему доступ так:


var red = new Packages.HelloWorld()


Объекты LiveConnect java, sun и netscape являются аббревиатурами для наиболее часто употребляющихся Java-пакетов. Например:


var myString = new java.lang.String("Hello world")


вместо более длинной версии:
 

var myString = new Packages.java.lang.String("Hello world")



Работа с Массивами Java



Если любой Java-метод создаёт массив и Вы ссылаетесь на этот массив в JavaScript, Вы работаете с JavaArray. Например, следующий код создаёт JavaArray x из 10 элементов типа int:


x = java.lang.reflect.Array.newInstance(java.lang.Integer, 10)


Как и объект Array из JavaScript, JavaArray имеет свойство length, которое возвращает количество элементов массива. В отличие от Array.length, JavaArray.length, это свойство только для чтения, поскольку количество элементов Java-массива фиксируется в момент создания.



Ссылки на Пакеты и Классы


 

Простые ссылки из JavaScript на пакеты и классы Java создают объекты JavaPackage и JavaClass. В предыдущем примере о компании Redwood, к примеру, ссылка Packages.redwood это JavaPackage-объект. Аналогично ссылка java.lang.String является JavaClass-объектом.


В большинстве случаев  Вам не нужно беспокоиться об объектах  JavaPackage и JavaClass - Вы просто работаете с пакетами и классами Java, а LiveConnect создаёт эти объекты прозрачно.


В JavaScript 1.3 и ранее JavaClass-объекты не конвертируются автоматически в экземпляры java.lang.Class. Если Вы передаёте их в качестве параметров Java-методам - Вы обязаны создавать wrapper/оболочку вокруг экземпляра java.lang.Class. В следующем примере метод forName создаёт объект-оболочку theClass, который затем передаётся методу newInstance для создания массива.


// JavaScript 1.3
theClass = java.lang.Class.forName("java.lang.String")
theArray = java.lang.reflect.Array.newInstance(theClass, 5)


В JavaScript 1.4 и позднее Вы можете передавать JavaClass-объект непосредственно в метод, как в следующем примере:


// JavaScript 1.4
theArray = java.lang.reflect.Array.newInstance(java.lang.String, 5)



Аргументы Типа char


 

В JavaScript 1.4 и позднее Вы можете передавать строку из одного символа в Java-метод, который требует аргумент типа char. Например, Вы можете передать строку "H" в конструктор Character:


c = new java.lang.Character("H")


В JavaScript 1.3 и ранее Вы обязаны передавать в такие методы целое число, соответствующее Unicode-значению символа. Например, следующий код также присваивает значение "H" переменной c:


c = new java.lang.Character(72)



Обработка Исключений Java в JavaScript


 

Если код Java прерывается на этапе прогона программы, он вызывает исключение. Если Ваш JavaScript-код имеет доступ к члену данных Java или методу и терпит неудачу, исключение Java передаётся в JavaScript для обработки. Начиная с JavaScript 1.4, Вы можете отловить это исключение в операторе try...catch.


Например, предположим, Вы используете Java-метод forName для присвоения имени Java-класа переменной theClass. Метод forName вызывает исключение, если передаваемое Вами значение не вычисляется в имя Java-класса. Поместите оператор присвоения forName в блок try для обработки исключения:


function getClass(javaClassName) {
   try {
      var theClass = java.lang.Class.forName(javaClassName);
   } catch (e) {
      return ("The Java exception is " + e);
   }
   return theClass
}


В этом примере, если javaClassName вычисляется в верное имя класса, такое как "java.lang.String", присвоение проходит успешно. Если javaClassName вычисляется в неверное имя класса, такое как "String", функция getClass отлавливает исключение и возвращает нечто подобное:


The Java exception is java.lang.ClassNotFoundException: String


См. в разделе "Операторы Обработки Исключений" информацию об исключениях JavaScript.




Взаимодействие Java и JavaScript



Если Вы хотите использовать объекты JavaScript в Java, Вы обязаны импортировать пакет netscape.javascript в Ваш Java-файл. Этот пакет определяет следующие классы:
 


Начиная с JavaScript 1.2, эти классы поставляются в .jar файле; в предыдущих версиях JavaScript они поставлялись в .zip файле. См. в книге Ядро JavaScript. Справочник. информацию об этих классах.


Для доступа к классам LiveConnect поместите .jar или .zip файл в CLASSPATH компилятора JDK одним из следующих способов:
 


Например, в Navigator 4. 0 для Windows NT классы расположены в файле java40.jar в директории Program\Java\Classes ниже директории Navigator'а. Вы можете специфицировать переменную окружения в Windows NT, дважды щёлкнув иконку System в Control Panel и создав пользовательскую переменную окружения под названием CLASSPATH со значением, типа такого:


D:\Navigator\Program\Java\Classes\java40.jar


См. в документации Sun JDK информацию о CLASSPATH.


Примечание

Поскольку Java является строго типизированным языком, а JavaScript -слабо типизированным, машина выполнения JavaScript конвертирует значения аргументов в типы данных, подходящие для других языков, если Вы используете LiveConnect. См. полную информацию в разделе Конвертация Типов Данных.



Использование Классов LiveConnect



Все объекты JavaScript появляются в коде Java как экземпляры netscape.javascript.JSObject. Если Вы вызываете метод в Java-коде, Вы можете передать в него JavaScript-объект как один из аргументов. Чтобы выполнить это, Вы обязаны определить соответствующий формальный параметр этого метода как имеющий тип JSObject.


Итак, при использовании JavaScript-объектов в Java-коде Вы всегда должны помещать вызов JavaScript-объекта внутри оператора try...catch, который обрабатывает исключения типа netscape.javascript.JSException. Это даёт Вашему Java-коду возможность обрабатывать ошибки при выполнении JavaScript-кода, которые появляются в Java как исключения типа JSException.


 

Доступ к JavaScript через JSObject


 

Например, предположим, Вы работаете с Java-классом JavaDog. Как показано в следующем коде, конструктор JavaDog принимает в качестве аргумента JavaScript-объект jsDog, который определён как имеющий тип JSObject:


import netscape.javascript.*;

public class JavaDog
{
    public String dogBreed;
    public String dogColor;
    public String dogSex;

    // определяется конструктор класса
    public JavaDog(JSObject jsDog)
    {
        // здесь try...catch используется для обработки JSExceptions
        this.dogBreed = (String)jsDog.getMember("breed");
        this.dogColor = (String)jsDog.getMember("color");
        this.dogSex = (String)jsDog.getMember("sex");
    }
}


Обратите внимание, что метод getMember из JSObject используется для доступа к свойствам JavaScript-объекта. Предыдущий пример использует getMember для присвоения значения JavaScript-свойства jsDog.breed члену данных Java JavaDog.dogBreed.


Примечание

Более жизненный пример - помещение вызова метода getMember внутрь блока try...catch для обработки ошибок типа JSException. См. также Обработка Исключений JavaScript в Java.


Чтобы лучше понять, как работает getMember, посмотрите на определение специального JavaScript-объекта Dog:


function Dog(breed,color,sex) {
   this.breed = breed
   this.color = color
   this.sex = sex
}


Вы можете создать в JavaScript экземпляр объекта Dog под названием gabby:
 

gabby = new Dog("lab","chocolate","female")


Если Вы вычисляете gabby.color, то увидите, что это свойство имеет значение "chocolate". Теперь предположим, что Вы создаёте экземпляр JavaDog в Вашем JavaScript-коде, передавая конструктору объект gabby:


javaDog = new Packages.JavaDog(gabby)


Если Вы вычисляете javaDog.dogColor, то увидите, что это свойство также имеет значение "chocolate", потому что метод getMember в Java-конструкторе присваивает переменной dogColor значение свойства gabby.color.


 

Обработка Ошибок JavaScript в Java


 

Когда JavaScript-код вызываемый из Java, терпит неудачу на этапе прогона программы, он вызывает исключение. Если Вы вызываете JavaScript-код из Java, Вы можете отловить это исключение в операторе try...catch. Исключение JavaScript доступно в Вашем Java-коде как экземпляр netscape.javascript.JSException.


JSException это Java-оболочка вокруг исключения любого типа, вызываемого в JavaScript, аналогично тому, как экземпляры JSObject являются оболочками для JavaScript-объектов. Используйте JSException, если Вы вычисляете JavaScript-код в Java.


Если Вы вычисляете JavaScript-код в Java, следующие ситуации могут вызвать ошибки времени выполнения:
 


Например, предположим, что Java-объект eTest вычисляет строку jsCode, которую Вы ему передали. Вы можете отреагировать на любую ошибку времени выполнения, возникающую при вычислении, реализуя такой обработчик исключения:


import netscape.javascript.JSObject;
import netscape.javascript.JSException;

public class eTest {
    public static Object doit(JSObject obj, String jsCode) {
        try {
            obj.eval(jsCode);
        } catch (JSException e) {
            if (e.getWrappedException()==null)
                return e;
            return e.getWrappedException();
        }
        return null;
    }
}


В этом примере код блока try пытается вычислить строку jsCode, переданную ему Вами. Скажем, Вы передали строку "myFunction()" в качестве значения jsCode. Если myFunction не определена как функция JavaScript, интерпретатор JavaScript не может вычислить jsCode. Интерпретатор генерирует сообщение об ошибке, Java-обработчик отлавливает сообщение, а метод doit возвращает экземпляр объекта netscape.javascript.JSException.


Предположим, однако, что myFunction определена в JavaScript так:


function myFunction() {
   try {
      if (theCondition == true) {
         return "Everything's ok";
      } else {
         throw "JavaScript error occurred" ;
      }
   } catch (e) {
      if (canHandle == true) {
         handleIt();
      } else {
         throw e;
      }
   }
}


Если theCondition - false, функция вызывает исключение. Это исключение отлавливается в коде JavaScript, и, если canHandle - true, JavaScript обрабатывает исключение. Если canHandle - false, исключение повторно вызывается, Java-обработчик отлавливает его, а метод doit возвращает Java-строку:


JavaScript error occurred


См. в разделе "Операторы Обработки Исключений" полную информацию об исключениях JavaScript.


 

Обратная Совместимость

В JavaScript 1.3 и ранее, класс JSException имел три public-конструктора, которые по выбору принимали строковой аргумент, специфицирующий детали сообщения или другую информацию для исключения. Метод getWrappedException отсутствовал.


Используйте оператор try...catch для обработки LiveConnect-исключений в JavaScript 1.3 и более ранних версиях таким образом:


try {
   global.eval("foo.bar = 999;");
} catch (Exception e) {
   if (e instanceof JSException) {
      jsCodeFailed()";
   } else {
      otherCodeFailed();
   }
}


В этом примере оператор eval терпит неудачу, если foo не определено. Блок catch выполняет метод jsCodeFailed, если оператор eval в блоке try вызывает JSException; метод otherCodeFailed выполняется в случае, если блок try вызывает какую-либо иную ошибку.




Конвертация Типов Данных



Поскольку язык Java строго типизирован, а JavaScript типизирован слабо, машина выполнения JavaScript конвертирует значения аргументов в типы данных, подходящие для других языков, если Вы используете LiveConnect. Эта конвертация описана в разделах:
 



Конвертация JavaScript в Java



Если Вы вызываете Java-метод и передаёте ему параметры из JavaScript, типы данных передаваемых параметров конвертируются в соответствии с правилами, описанными в следующих разделах:
 


return-значения методов объекта netscape.javascript.JSObject всегда конвертируются в экземпляры объекта java.lang.Object. Правила конвертации этих return-значений также описаны в этих разделах.


Например, если JSObject.eval возвращает JavaScript-число, Вы можете найти правила конвертации этого числа в экземпляр объекта java.lang.Object в разделе Числа.


 

Числа



Если Вы передаёте числовые типы JavaScript в качестве параметров методам Java, Java конвертирует эти значения в соответствии с правилами, описанными в следующей таблице:


Тип Java-параметра Правила Конверсии

double

Точное значение переносится в Java без округления и без потери точности или знака.

lava.lang.Double
java.lang.Object

Создаётся новый экземпляр java.lang.Double, и точное значение передаётся в Java без округления и без потери точности или знака.

float

  • Значения округляются до чисел с плавающей точкой.

  • Значения, которые слишком малы или велики, чтобы быть представленными, округляются до +infinity или -infinity.

byte
char
int
long
short

  • Значения округляются с использованием режима round-to-negative-infinity/округление-в-сторону-отрицательной-бесконечности.

  • Значения, которые слишком малы или велики, чтобы быть представленными, дают ошибку времени выполнения.

  • Значения NaN конвертируются до нуля.

java.lang.String

Значения конвертируются в строки. Например,

  • 237 становится "237"

boolean

  • Значения 0 и NaN конвертируются в false.

  • Другие значения конвертируются в true.


Если число JavaScript передаётся в качестве параметра в Java-метод, который ожидает экземпляр объекта java.lang.String, это число конвертируется в строку. Используйте метод equals() для сравнения результата этой конвертации с другими строковыми значениями.


 

Булевы Значения



Если Вы передаёте Булевы типы JavaScript как параметры для Java-методов, Java конвертирует значения в соответствии с правилами, описанными в следующей таблице:


Тип Java-параметра Правила Конверсии

boolean

Все значения конвертируются непосредственно в Java-эквиваленты.

lava.lang.Boolean
java.lang.Object

Создаётся новый экземпляр объекта java.lang.Boolean. Каждый параметр создаёт новый экземпляр, а не один экземпляр с тем же примитивным значением.

java.lang.String

Значения конвертируются в строки. Например:
 

  • true становится "true"

  • false становится "false"

byte
char
double
float
int
long
short

  • true становится 1

  • false становится 0


Если Булево значение JavaScript передаётся в качестве параметра Java-методу, ожидающему экземпляр объекта java.lang.String, Булево значение конвертируется в строку. Используйте операцию == для сравнения результата этой конвертации с другими строковыми значениями.


 

Строковые Значения



Если Вы передаёте строковые типы JavaScript как параметры для Java-методов, Java конвертирует значения в соответствии с правилами, описанными в следующей таблице:


Тип Java-параметра Правила Конверсии

lava.lang.String
java.lang.Object

JavaScript 1.4:
 

  • Строка JavaScript конвертируется в экземпляр объекта java.lang.String со значением Unicode.


JavaScript 1.3 и ранее:
 

  • Строка JavaScript конвертируется в экземпляр объекта java.lang.String со значением ASCII.

byte
double
float
int
long
short

Все значения конвертируются в числа так, как описано в ECMA-262.

Строковые значения JavaScript конвертируются в числа в соответствии с правилами ECMA-262

char

JavaScript 1.4:
 

  • Односимвольные строки конвертируются в Unicode-символы.

  • Все иные значения конвертируются в числа.


JavaScript 1.3 и ранее:
 

  • Все значения конвертируются в числа.

boolean

  • Пустая строка становится false.

  • Все иные значения становятся true.


 

Undefined-Значения



Если Вы передаёте значения undefined JavaScript в качестве параметров методам Java, Java конвертирует значения в соответствии с правилами, описанными в следующей таблице:


Тип Java-параметра Правила Конверсии

lava.lang.String
java.lang.Object

Значение конвертируется в экземпляр объекта java.lang.String, значением которого является строка "undefined".

boolean

Значение становится false.

double
float

Значение становится NaN.

byte
char
int
long
short

Значение становится 0.


Конверсия значения undefined возможна только в JavaScript 1.3 и более поздних версиях. Более ранние версии JavaScript не поддерживают значения undefined.


Если значение undefined JavaScript передаётся в качестве параметра Java-методу, который ожидает экземпляр объекта java.lang.String, значение undefined конвертируется в строку. Используйте операцию == для сравнения результата этой конвертации с другими строковыми значениями.


 

Null-Значения



Если Вы передаёте значения null JavaScript в качестве параметра Java-методам, Java конвертирует значения в соответствии с правилами, описанными в следующей таблице:


Тип Java-параметра Правила Конверсии

Любой класс
Любой тип интерфейса

Значение становится null.

byte
char
double
float
int
long
short

Значение становится 0.

boolean

Значение становится false.


 

Объекты JavaArray и JavaObject



В большинстве случаев, если Вы передаёте JavaArray или JavaObject JavaScript в качестве параметра Java-методу, Java просто снимает оболочку с объекта; в некоторых случаях объект приводится к другому типу данных в соответствии с правилами, описанными в следующей таблице:


Тип Java-параметра Правила Конверсии

Любой интерфейс или класс, совместимый при присвоении с развёрнутым /unwrapped объектом.

Объект разворачивается.

java.lang.String

Объект разворачивается, вызывается метод toString развёрнутого Java-объекта, и результат возвращается как новый экземпляр объекта java.lang.String.

byte
char
double
float
int
long
short

Объект разворачивается, и возникает одна из следующих ситуаций:
 

  • Если развёрнутый Java-объект имеет метод doubleValue, the JavaArray или JavaObject конвертируется в значение, возвращаемое этим методом.

  • Если развёрнутый Java-объект не имеет метода doubleValue, возникает ошибка.

boolean

В JavaScript 1.3 и более поздних версиях, объект разворачивается, и возникает одна из следующих ситуаций:
 

  • Если объект - null, он конвертируется в false.

  • Если объект имеет какое-либо другое значение, он конвертируется в true.


В JavaScript 1.2 и ранее, объект разворачивается, и возникает одна из следующих ситуаций:
 

  • Если развёрнутый объект имеет метод booleanValue, the исходный объект конвертируется в return-значение.

  • Если развёрнутый объект не имеет метода booleanValue, конвертация терпит неудачу.


Интерфейс или класс совместим для присвоения с развёрнутым объектом, если развёрнутый объект является экземпляром типа Java-параметра. То есть, следующий оператор должен возвращать true:


развёрнутыйОбъект instanceof параметраТип


 

Объекты JavaClass


 

Если Вы передаёте объект JavaClass из JavaScript в качестве параметра Java-методу, Java конвертирует значение в соответствии с правилами, описанными в следующей таблице:


Тип Java-параметра Правила Конверсии

java.lang.Class

Объект разворачивается.

java.lang.JSObject
java.lang.Object

Объект JavaClas разворачивается в новый экземпляр объекта java.lang.JSObject.

java.lang.String

Объект разворачивается, вызывается метод toString развёрнутого Java-объекта и результат возвращается как новый экземпляр объекта java.lang.String.

boolean

В JavaScript 1.3 и позднее, объект разворачивается, и возникает одна из следующих ситуаций:
 

  • Если объект - null, он конвертируется в false.

  • Если объект имеет какое-либо другое значение, он конвертируется в true.


В JavaScript 1.2 и ранее, объект разворачивается, и возникает одна из следующих ситуаций:
 

  • Если развёрнутый объект имеет метод booleanValue, исходный объект конвертируется в return-значение.

  • Если развёрнутый объект не имеет метода booleanValue, конвертация терпит неудачу.



Другие Объекты JavaScript



Если Вы передаёте любой иной объект JavaScript в качестве параметра Java-методу, Java конвертирует значение в соответствии с правилами, описанными в следующей таблице:


Тип Java-параметра Правила Конверсии

java.lang.JSObject
java.lang.Object

Объект разворачивается в новый экземпляр объекта java.lang.JSObject.

java.lang.String

Объект разворачивается, вызывается метод toString развёрнутого Java-объекта и результат возвращается как новый экземпляр объекта java.lang.String.

byte
char
double
float
int
long
short  

Объект конвертируется в значение с использованием логики оператора ToPrimitive, описанного в ECMA-262. Подсказка PreferredType, используемая с этим оператором, является Number.

boolean

В JavaScript 1.3 и позднее, объект разворачивается, и возникает одна из следующих ситуаций:
 

  • Если объект - null, он конвертируется в false.

  • Если объект имеет какое-либо другое значение, он конвертируется в true.


В JavaScript 1.2 и ранее, объект разворачивается, и возникает одна из следующих ситуаций:
 

  • Если развёрнутый объект имеет метод booleanValue, исходный объект конвертируется в return-значение.

  • Если развёрнутый объект не имеет метода booleanValue, конвертация терпит неудачу.



Конвертация из Java в JavaScript



Значения, передаваемые из Java в JavaScript, конвертируются так:
 

Java String-объекты также соответствуют JavaScript-оболочкам. Если Вы вызываете метод JavaScript, который требует строки JavaScript, и передаёте его этой оболочке, Вы получите ошибку. Вместо этого конвертируйте оболочку в строку JavaScript путём присоединения к ней пустой строки, как показано здесь:


var JavaString = JavaObj.methodThatReturnsAString();
var JavaScriptString = JavaString + "";
 


Назад     Оглавление    Индекс     Вперёд


На главную страницу