Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Host object vs wrapped

208 views
Skip to first unread message

Daryl Stultz

unread,
Dec 25, 2009, 9:27:42 PM12/25/09
to Rhino JS User List
Hey all,

I've been using Rhino for some time now in my application. I simply use POJO
objects and let them get auto-wrapped by Rhino. I've been reading the docs
about host objects and I seem a bit unclear what the purpose is. I don't see
what the benefit of writing

public void jsFunction_resetCount()
vs just
public void resetCount().

Is it just the ability to add dynamic properties to an object?

Ultimately I'm looking for a better solution to my application design. I've
got a domain object, say MyEntity and a wrapper class called JsMyEntity that
forwards methods to MyEntity delegate. This is so I can restrict access to
various methods of the domain class and I have a "JS API" class that clearly
defines what's exposed to JavaScript.

I don't like writing the wrapper class. It's too much maintenance and prone
to error. I'm looking for some feature of Rhino or JavaScript that might let
me more easily define what methods of the domain class are accessible. I'm
wondering if a host object has such features. Any input on how others are
handling this type of thing would be appreciated.

Thanks.

--
Daryl Stultz
_____________________________________
6 Degrees Software and Consulting, Inc.
http://www.6degrees.com
mailto:da...@6degrees.com

Mark Storer

unread,
Dec 28, 2009, 12:34:12 PM12/28/09
to Daryl Stultz, Rhino JS User List
IIRC, there's an annotation-based object exposer in the source, but I don't
see anything in the .jar...

Yep.
http://mxr.mozilla.org/mozilla/source/js/rhino/src/org/mozilla/javascript/annotations/

I'm not aware of any code actually *using* those annotations. Furthermore,
the entire "annotations.*" package is missing from the jar file.

--Mark Storer

> _______________________________________________
> dev-tech-js-engine-rhino mailing list
> dev-tech-js-...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-tech-js-engine-rhino
>

--
--Mark Storer
Professional Geek

Daryl Stultz

unread,
Dec 28, 2009, 2:44:07 PM12/28/09
to Rhino JS User List
On Mon, Dec 28, 2009 at 12:34 PM, Mark Storer <mstor...@gmail.com> wrote:

> IIRC, there's an annotation-based object exposer in the source, but I don't
> see anything in the .jar...
>
> Yep.
> http://mxr.mozilla.org/mozilla/source/js/rhino/src/org/mozilla/javascript/annotations/
>
> I'm not aware of any code actually *using* those annotations.
> Furthermore, the entire "annotations.*" package is missing from the jar
> file.
>
>

Thanks, Mark, after I sent my first email, I thought annotations would be a
good way to implement part of what I'd like to do. Here, it seems the
annotations are an alternative to the naming convention for a host object.
What I'd like to do is mark a public method on my domain POJO as "private"
from the perspective of Rhino. I think if had that I'd be happy. I'd
probably still want to wrap the domain classes in a "JS API" class. The
wrapper would implement Scriptable and use annotations to determine if the
domain method being accessed (via scriptable.get("myMethod", start), for
example) should be allowed. While annotations would be nice, a Scriptable
class that has a list of excluded methods would probably be sufficient.

Hannes Wallnoefer

unread,
Dec 29, 2009, 4:39:27 AM12/29/09
to
On Dec 28, 6:34 pm, Mark Storer <mstorer3...@gmail.com> wrote:
> IIRC, there's an annotation-based object exposer in the source, but I don't
> see anything in the .jar...
>
> Yep.http://mxr.mozilla.org/mozilla/source/js/rhino/src/org/mozilla/javasc...

>
> I'm not aware of any code actually *using* those annotations.  Furthermore,
> the entire "annotations.*" package is missing from the jar file.

I implemented the annotation based mechanism a half year ago or so,
here's my announcement on this list:

http://groups.google.com/group/mozilla.dev.tech.js-engine.rhino/browse_frm/thread/bb20ab11868c35e9/3968cc0ccaade961

So far it isn't available in any released version, so you have to use
a recent snapshot from CVS or ftp://ftp.mozilla.org/pub/js/. The
annotations are a direct replacement for the name based scheme, so the
whole host class initialization process is the same as described here:

http://www.mozilla.org/rhino/apidocs/org/mozilla/javascript/ScriptableObject.html#defineClass(org.mozilla.javascript.Scriptable,%20java.lang.Class)

I've been using this exclusively in Helma NG, so I would consider it
save and fairly well-tested. For examples, look at the Binary or
Stream class in this package:

http://github.com/hns/helma-ng/tree/master/src/org/helma/wrappers/

The most important thing you need to know is that you can override all
method and property names. For example, @JSGetter getFoo() will
generate a property called "foo", but you can use @JSGetter("bar") to
name the property "bar".

Hannes

> > dev-tech-js-engine-rh...@lists.mozilla.org

Hannes Wallnoefer

unread,
Dec 29, 2009, 4:57:26 AM12/29/09
to
On Dec 29, 10:39 am, Hannes Wallnoefer <hann...@gmail.com> wrote:
> On Dec 28, 6:34 pm, Mark Storer <mstorer3...@gmail.com> wrote:
>
> > IIRC, there's an annotation-based object exposer in the source, but I don't
> > see anything in the .jar...
>
> > Yep.http://mxr.mozilla.org/mozilla/source/js/rhino/src/org/mozilla/javasc...
>
> > I'm not aware of any code actually *using* those annotations.  Furthermore,
> > the entire "annotations.*" package is missing from the jar file.
>
> I implemented the annotation based mechanism a half year ago or so,
> here's my announcement on this list:
>
> http://groups.google.com/group/mozilla.dev.tech.js-engine.rhino/brows...

PS: I'll update the documentation over the next days to include this
feature. Annotations really improve the experience of implementing
host objects, so it's a shame people people are still using the old
name based mechanism for new code.

Hannes

Daryl Stultz

unread,
Dec 29, 2009, 8:29:57 AM12/29/09
to Rhino JS User List
On Tue, Dec 29, 2009 at 4:39 AM, Hannes Wallnoefer <han...@gmail.com>wrote:

>
> I implemented the annotation based mechanism a half year ago or so,
> here's my announcement on this list:
>

I do appreciate the annotations approach to writing host objects but it's
actually off topic from my original post. I'm looking for two things: what
is the advantage of using a host object vs. a POJO? Also, I'm looking for an
easy-maintenance approach to wrapping my domain classes - this is the bigger
need. Suppose I have this domain class:

public class MyEntity {

private int foo;
public int getFoo() { return foo; }
public void setFoo(int foo) { this.foo = foo;}
public void save() { ... }

}

I could use this directly in JavaScript with the auto wrapping to make it
scriptable. But I prefer to have a wrapper class:

public class JsMyEntity {

private MyEntity delegate;
public int getFoo() { return delegate.getFoo(); }
public void setFoo(int foo) { delegate.setFoo(foo); }

}

So if JsMyEntity is in my "JavaScript API" package, I can "find usages" of
MyEntity.setFoo() and see that the method is exposed to the JS API. Also, as
you can see, I have restricted access to the MyEntity.save() method by
omitting it from the wrapper. The problem is that this approach is difficult
to maintain especially with collections. I'd like a simpler wrapper class
that automatically forwards to the delegate except perhaps when a delegate
method is marked with an annotation prohibiting JS access. What I'm not
clear on is if I can use features of Scriptable or ScriptableObject to
create such a wrapper.

I've experimented with ScriptableObject and I see that I can override get
and filter the method name, but the method (FunctionObject?) ultimately
comes from the same object and I want it to come from the delegate.

Mark Storer

unread,
Dec 29, 2009, 1:46:20 PM12/29/09
to dev-tech-js-engine-rhino
Whoops. Take two:


---------- Forwarded message ----------
From: Mark Storer <mstor...@gmail.com>
Date: Tue, Dec 29, 2009 at 10:45 AM
Subject: Re: Host object vs wrapped
To: Daryl Stultz <da...@6degrees.com>


On Tue, Dec 29, 2009 at 5:29 AM, Daryl Stultz <da...@6degrees.com> wrote:
> I do appreciate the annotations approach to writing host objects but it's
> actually off topic from my original post.

I disagree.  Observe:

import org.mozilla.javascript.annotations.*;
public class MyEntity {

private int foo;
@JSGetter


public int getFoo() { return foo; }

@JSSetter


public void setFoo(int foo) { this.foo = foo;}
public void save() { ... }
}

Done.  No need for a separate wrapper class, you can simply annotate
what you want exposed, and Rhino will ignore the rest.

Err... unless.... Are you required to extend ScriptableObject?  That
could be a deal-breaker for many Domain Objects.  All the examples
given examples do so...

I suppose the Actual Requirement is to implement Scriptable... extra
work, but not the end of the world for some object that has to derive
from Something Else.

--Mark

On Tue, Dec 29, 2009 at 5:29 AM, Daryl Stultz <da...@6degrees.com> wrote:
>
> On Tue, Dec 29, 2009 at 4:39 AM, Hannes Wallnoefer <han...@gmail.com>wrote:
>
> >

> > I implemented the annotation based mechanism a half year ago or so,
> > here's my announcement on this list:
> >
>

> --
>
> Daryl Stultz
> _____________________________________
> 6 Degrees Software and Consulting, Inc.
> http://www.6degrees.com
> mailto:da...@6degrees.com
> _______________________________________________
> dev-tech-js-engine-rhino mailing list

> dev-tech-js-...@lists.mozilla.org

Daryl Stultz

unread,
Dec 29, 2009, 1:55:19 PM12/29/09
to Rhino JS User List
On Tue, Dec 29, 2009 at 1:46 PM, Mark Storer <mstor...@gmail.com> wrote:

> On Tue, Dec 29, 2009 at 5:29 AM, Daryl Stultz <da...@6degrees.com> wrote:
> > I do appreciate the annotations approach to writing host objects but it's
> > actually off topic from my original post.
>
> I disagree. Observe:
>
> import org.mozilla.javascript.annotations.*;
> public class MyEntity {
>
> private int foo;
> @JSGetter
> public int getFoo() { return foo; }
> @JSSetter
> public void setFoo(int foo) { this.foo = foo;}
> public void save() { ... }
> }
>
> Done. No need for a separate wrapper class, you can simply annotate
> what you want exposed, and Rhino will ignore the rest.
>

Ah, "Rhino will ignore the rest". That's good for chopping off the save()
method. In most cases I need to change the behavior of the save() method
rather than hide it. I can't subclass my domain class.

>
> Err... unless.... Are you required to extend ScriptableObject? That
> could be a deal-breaker for many Domain Objects. All the examples
> given examples do so...
>

Yeah, my domain classes are (bytecode enhanced) JPA entities. I don't want
to extend ScriptableObject nor implement Scriptable. I'm pretty sure I need
a wrapper. I think I need a ScriptableObject that is the superclass of all
my Js Entity wrappers. The superclass takes a POJO as delegate and
intercepts the calls to properties and functions and forwards them to the
delegate. Is that a reasonable idea or a crazy undertaking?

Norris Boyd

unread,
Dec 29, 2009, 1:59:41 PM12/29/09
to
For most uses, just wrapping POJOs is sufficient. Several things have
changed since the host object mechanism was created:
* Rhino has implemented bean properties (getFoo/setFoo) as JavaScript
properties (foo)
* Java has implemented, and Rhino has supported, variable arguments to
methods
* Java's reflection APIs have gotten much faster
With all these changes, the delta in functionality between wrapping
POJOs and using host objects has substantially narrowed. And wrapping
POJOs is much easier.

The main thing you can do with the host object APIs that you can't do
with wrapping POJOs is writing generic property getters, for example
as was done with http://mxr.mozilla.org/mozilla/source/js/rhino/examples/Matrix.java.

And Hannes' new annotation-based host objects are definitely better
than the mangled-name form.

--Norris

> > dev-tech-js-engine-rh...@lists.mozilla.org

Daryl Stultz

unread,
Dec 29, 2009, 2:08:04 PM12/29/09
to Rhino JS User List
On Tue, Dec 29, 2009 at 1:59 PM, Norris Boyd <norri...@gmail.com> wrote:

> For most uses, just wrapping POJOs is sufficient.


Essentially I'm wrapping a POJO with another POJO at the present.

>
> The main thing you can do with the host object APIs that you can't do
> with wrapping POJOs is writing generic property getters, for example
> as was done with
> http://mxr.mozilla.org/mozilla/source/js/rhino/examples/Matrix.java.
>

> Are you referring to the fact that there is no getter/setter for the "dim"
property and the implementation of get/put provides the functionality of
get/set? That's similar to what I want to do. My host object would be
generic with no properties, just the inner POJO delegate. A call to get/put
would cause the host object to use reflection to access the appropriate
getter/setter in the delegate (or in a subclass of the host object). I'm not
sure how this could be done for a method/function though. Any ideas?

Daryl Stultz

unread,
Dec 30, 2009, 10:35:32 AM12/30/09
to Rhino JS User List
On Tue, Dec 29, 2009 at 2:08 PM, Daryl Stultz <da...@6degrees.com> wrote:

> That's similar to what I want to do. My host object would be generic with
> no properties, just the inner POJO delegate. A call to get/put would cause
> the host object to use reflection to access the appropriate getter/setter in
> the delegate (or in a subclass of the host object).
>

I'm currently experimenting with the idea of putting my domain object into
the prototype. Consider this:

// my java domain class
public class DomainEntity {

public void save() {
System.out.println("DomainEntity.save()");
}
public void delete() {
System.out.println("DomainEntity.delete()");
}
}

// my Java Host object wrapper
public class HostEntity extends ScriptableObject {
public HostEntity() {
super();
DomainEntity proto = new DomainEntity();
NativeJavaObject jsproto = new NativeJavaObject(scope, proto, null);
setPrototype(jsproto);
}
public void jsFunction_save() {
System.out.println("HostEntity.save()");
}
}

The idea is that methods found in HostEntity will be executed before those
found in DomainEntity.
So this JS code:

var obj = new HostEntity();
obj.save();
obj.delete();

will produce this output:

HostEntity.save()
DomainEntity.delete()

The obvious problem is that "scope" is not available at this line:
NativeJavaObject jsproto = new NativeJavaObject(scope, proto, null);

I don't see any way of getting the "current scope" as one might get the
current context. Am on the right track with what I want to accomplish or is
there a better way. I'm open to hearing how anyone else handles an "API"
layer between their Java domain classes and what is exposed to Javascript.

Thanks.

Daryl Stultz

unread,
Dec 30, 2009, 1:11:11 PM12/30/09
to Rhino JS User List
On Wed, Dec 30, 2009 at 1:04 PM, Mark Storer <mstor...@gmail.com> wrote:

> Err... can't you just use the parent scope of the current object?
> Anything that extends "Scriptable" has a getParentScope(). You won't
> have access to it in the constructor (since setParentScope hasn't been
> called), but perhaps in your host's jsConstructor()?
>
> Hi Mark, I started with the constructor approach rather than the "current
object" so got stuck there. What you're suggesting may in fact do the trick.
I wasn't aware that setParentScope would be called between the Java
constructor and the JS constructor.

I'm currently exploring a path using a WrapFactory. If it doesn't pan out
I'll give your suggestion a try.

Mark Storer

unread,
Dec 30, 2009, 3:58:47 PM12/30/09
to Daryl Stultz, Rhino JS User List
On Wed, Dec 30, 2009 at 10:11 AM, Daryl Stultz <da...@6degrees.com> wrote:
> I wasn't aware that setParentScope would be called between the Java
> constructor and the JS constructor.

I'm not sure that it is... but it should be a simple matter to check
at runtime. I poked around in the code for a bit, but couldn't come
up with a definitive answer. I /think/ it does
(BaseFunction.createObject() whips up an empty object then immediately
sets its prototype and parent scope), but I won't be sure until I step
through that code.


--Mark

Daryl Stultz

unread,
Dec 30, 2009, 4:06:08 PM12/30/09
to Rhino JS User List
On Wed, Dec 30, 2009 at 3:58 PM, Mark Storer <mstor...@gmail.com> wrote:

>
> I'm not sure that it is... but it should be a simple matter to check
> at runtime. I poked around in the code for a bit, but couldn't come
> up with a definitive answer. I /think/ it does


Thanks for your help Mark, I believe I've found the solution to my problem.
I'll follow up on the other thread.

Mark Storer

unread,
Dec 30, 2009, 5:10:40 PM12/30/09
to Daryl Stultz, Rhino JS User List
For Future Reference:

The parent scope IS defined by the time jsConstruct() is called.

BTW, getPrototype returns a different instance (?!) of the host class. Funky.

--Mark

On Wed, Dec 30, 2009 at 1:06 PM, Daryl Stultz <da...@6degrees.com> wrote:
> On Wed, Dec 30, 2009 at 3:58 PM, Mark Storer <mstor...@gmail.com> wrote:
>
>>
>> I'm not sure that it is... but it should be a simple matter to check
>> at runtime.  I poked around in the code for a bit, but couldn't come
>> up with a definitive answer.  I /think/ it does
>
>
> Thanks for your help Mark, I believe I've found the solution to my problem.
> I'll follow up on the other thread.
>

> --
> Daryl Stultz
> _____________________________________
> 6 Degrees Software and Consulting, Inc.
> http://www.6degrees.com
> mailto:da...@6degrees.com
> _______________________________________________
> dev-tech-js-engine-rhino mailing list

> dev-tech-js-...@lists.mozilla.org

0 new messages