Los problemas de la clase JSObject

Publicado en Java, JavaScript el 19 de October, 2009 por Fran.

Como los applets se ejecutan dentro de una página web, se creó un mecanismo (llamado LiveConnect) para comunicarse con el navegador mediante JavaScript, es decir, poder ejecutar JavaScript desde el applet.

Este mecanismo ofrece una clase llamada JSObject que permite realizar la comunicación del applet a JavaScript, esta clase se localiza en el paquete netscape.javascript.

Lo malo es que esta clase tiene varios problemas y fallos relacionados que no vienen documentados en ningún sitio, sólo en algunas páginas de gente que ha conseguido averiguarlos por su cuenta.

JSObject no es thread safe

En los ejemplos de la página de Sun dedicada a la clase JSObject, se puede ver un ejemplo de su uso:

import netscape.javascript.*;
import java.applet.*;
import java.awt.*;

class MyApplet extends Applet {
    public void init() {
        JSObject win = JSObject.getWindow (this);
        JSObject doc = (JSObject) win.getMember ("document");
        JSObject loc = (JSObject) doc.getMember ("location");

        // document.location.href
        String s = (String) loc.getMember ("href");
        win.call ("f", null);   // Call f() in HTML page
    }
}

Bien, pues este uso no es correcto, ya que esta clase no es thread safe y en las versiones más recientes del complemento de Java para los navegadores, puede que la máquina virtual de Java ejecute varios hilos y el uso de esta clase acabe fallando. Para arreglarlo, sólo se debe hacer lo siguiente:

synchronized (JSObject.class) {
    win = JSObject.getWindow (applet);
}

Básicamente, se trata de encapsular el uso de la clase JSObject en un bloque synchronized para evitar fallos por cualquier causa relacionada con hilos.

JSObject.getMember () no funciona en Firefox sobre Mac OS X

Otro problema que tiene esta clase es que en la versión de Firefox para Mac OS X, el método getMember no funciona bien y siempre devuelve null, lo que obliga a usar un trozo de código algo feo. Por ejemplo, para obtener el userAgent del navegador:

synchronized (JSObject.class) {
    win = JSObject.getWindow (applet);
}
JSObject nav = win.getMember ("navigator");
String userAgent = (String) nav.getMember ("userAgent");

Utilizando el método getMember.

synchronized (JSObject.class) {
    win = JSObject.getWindow (applet);
}
String userAgent = (String) win.eval ("navigator.userAgent");

Un apaño, utilizando el método eval.

Basado en los posts sobre JSObject de Svetlin Nakov

2 comentarios

  1. En 2 pasos me has solucionado un gran problema con la clase JSObject!!!!!!

    Con el tema de que no es thread safe, y es cierto que eso no esta especificado en la documentación de Sun, estuve horas tratando de encontrar el problema, hasta que hoy me tope con tu blog!!! Muchas gracias por la solución!

    Saludos desde Argentina,
    Daniel SL

    #  Daniel SL 16 de May, 2010

  2. Muchas gracias! Habia trabajando en este problema por un hora antes buscando tu blog. Lo siento para mi mal Español =)

    /sam
    California, USA

    #  Sam N 19 de May, 2010

Escribe un comentario