2013-01-28 2 views
8

sto chiamando un metodo annotato @JSFunction di un ScriptableObjectChiamata @JSFunction da JavaScript, TypeError: Impossibile trovare il valore predefinito per oggetto

il file JavaScript

Target = Packages.com.acme.rhino.Target; 

function evaluate() { 
    var t = Target(); 
    t.addModifier("foobar", 1); 
    return t; 
} 

Il file Java

public class Target extends ScriptableObject { 
    private static final long serialVersionUID = 1L; 
    public List<Modifier> modifiers = new LinkedList<>(); 

    @JSConstructor 
    public Target() { 
    } 

    @JSFunction 
    public void addModifier(final String message, final int value) { 
     modifiers.add(new Modifier(message, value)); 
    } 

    public int getValue() { 
     int sum = 0; 
     for (final Modifier modifier : modifiers) { 
      sum += modifier.getValue(); 
     } 
     return sum; 
    } 

    @Override 
    public String getClassName() { 
     return "Target"; 
    } 
} 

Ma ottengo

org.mozilla.javascript.EcmaError: TypeError: Cannot find default value for object. 
    at org.mozilla.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3687) 
    at org.mozilla.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3665) 
    at org.mozilla.javascript.ScriptRuntime.typeError(ScriptRuntime.java:3693) 
    at org.mozilla.javascript.ScriptRuntime.typeError1(ScriptRuntime.java:3705) 
    at org.mozilla.javascript.ScriptableObject.getDefaultValue(ScriptableObject.java:976 ) 
    at org.mozilla.javascript.ScriptableObject.getDefaultValue(ScriptableObject.java:895 ) 
    at org.mozilla.javascript.ScriptRuntime.toString(ScriptRuntime.java:761) 
    at org.mozilla.javascript.ScriptRuntime.notFunctionError(ScriptRuntime.java:3774) 
    at org.mozilla.javascript.ScriptRuntime.getPropFunctionAndThisHelper(ScriptRuntime. java:2269) 
    at org.mozilla.javascript.ScriptRuntime.getPropFunctionAndThis(ScriptRuntime. java:2251) 
    at org.mozilla.javascript.optimizer.OptRuntime.callProp0(OptRuntime.java:83) 
    at org.mozilla.javascript.gen.script_5._c_evaluate_1(script:6) 
    at org.mozilla.javascript.gen.script_5.call(script) 
    at org.mozilla.javascript.ContextFactory.doTopCall(ContextFactory.java:394) 
    at org.mozilla.javascript.ScriptRuntime.doTopCall(ScriptRuntime.java:3091) 
    at org.mozilla.javascript.gen.script_5.call(script) 

e non so dove andare da lì. Quando non chiamo il metodo addModifier, il codice dato funziona e dato l'errore notFunctionError nella traccia dello stack, penso che Rhino non interpreti il ​​metodo dato come una funzione JavaScript.

  • OSX 10.8.2
  • Java 7
  • Rhino 1.7R4

Progetto completo Maven che riproduce l'errore può essere trovato here

risposta

3

tl; dr vedere thesetwo alternative.

Il problema con l'approccio precedente è che Target.prototype non è impostato correttamente nell'ambito di script. Vedere il metodo statico ScriptableObject.defineClass() per i dettagli su come definire correttamente i prototipi in un ambito di script.

Si dispone di un paio di alternative per fornire il costruttore Target agli script. Il first alternative dovrebbe sempre definire il costruttore Target per tutti gli script. Funziona bene se sai in anticipo che vuoi che lo Target sia globalmente disponibile. Questa tratta fondamentalmente al seguente:

final Context context = Context.enter(); 
try { 
    final ScriptableObject scope = context.initStandardObjects(); 
    ScriptableObject.defineClass(scope, Target.class, false, true); 
    context.evaluateString(scope, script, "script", 1, null); 
    // etc. 
} finally { 
    Context.exit(); 
} 

Se invece si desidera che l'autore dello script di decidere quali costruttori sono necessari, il second alternative è quello di fornire la funzione defineClass agli script. Con questa funzione, gli autori di script possono "importare" qualsiasi oggetto scriptable sul loro percorso di classe (che potrebbe essere più di quanto si desideri consentire). Per fornire le defineClass funzioni agli script, effettuare le seguenti operazioni dopo aver inserito il contesto:

final Context context = Context.enter(); 
try { 
    final ScriptableObject scope = context.initStandardObjects(); 
    scope.defineFunctionProperties(
      new String[] {"defineClass"}, 
      Global.class, 
      ScriptableObject.DONTENUM); 

    context.evaluateString(scope, script, "script", 1, null); 
    // etc. 
} finally { 
    Context.exit(); 
} 

E poi, l'autore JavaScript fa uso del costruttore Target con il seguente:

defineClass("com.acme.rhino.Target"); 
// whatever `getClassName()` returns is now available 
var target = new Target(); 

in entrambe le sopra i rami, ho apportato un paio di altre modifiche che ti migliorano se aggiungi altro al costruttore Target. Il costruttore dell'argomento zero non ha bisogno dell'annotazione @JSConstructor. Se in seguito si desidera avere un costruttore che accetta argomenti, questo costruttore di argomenti con zero verrà utilizzato come costruttore del prototipo e sarà possibile utilizzare l'annotazione @JSConstructor su un metodo che verrà utilizzato per inizializzare l'oggetto. A seconda di come si crea questo metodo di costruzione, diventa importante utilizzare la parola chiave new nel codice JavaScript.

In breve, la sintassi è Packages.com.acme...non utile per ottenere l'accesso a ScriptableObject costruttori da script.

+3

Solo una nota che i collegamenti github non funzionano più. – lycono

0

Ho capito che funziona (codice molto simile) utilizzando il nuovo operatore. Nel tuo esempio facendo

function evaluate() { 
     var t = new Target(); 
     ... 

dovrebbe funzionare pure.