Re: [Jython-users] Java classes with dynamic properties
by Oti other posts by this author
Dec 9 2004 9:35PM messages near this date
Re: RE : [Jython-users] Junit with Jython
|
Re: [Jython-users] How to invoked a class main method ...
[ katre ]
> I am writing an application that needs a scripting language, and I
> think
> jython looks very useful.
Indeed!
> I am only having one problem with my
> implementation. I have a dedicated data object class that is going
> to
> be manipulated by jython scripts. This class is a Java Bean and has
> a
> number of properties defined the usual way (getFoo/setFoo, etc).
> However, I also want to be able to let users dynamically create new
> properties, because the same objects will be processed by many
> different
> scripts. I have the java code to handle the dynamic properties, but
> I
> am not sure how to make them visible to Jython.
>
> Example:
>
> java side
> public class Data {
> public String getFoo() ...
> public void setFoo(String foo) ...
> public void addDynProp(String name) ...
> public Object getDynProp(String name) ...
> public void setDynProp(String name, Object value) ...
> }
>
> jython side
> d = Data()
> d.foo = "bob"
> print d.foo
>
> d.bar = "thing" # error
> d.addDynProp("bar")
> d.bar = "thing" # works
> print d.bar # works
>
> My initial thought was to use a BeanInfo, but each instance of the
> Data
> class needs its own properties. I then thought to use th apache
> commons
> beanutils DynaBean class, but jython doesn't work with those. Then I
> hoped to somehow override the __getattr__ and __setattr__ methods,
> but
> those are final in PyObject.
>
> Does anyone have any advice? At a last resort I can just make people
> pretend like dynProp is a Map (or dictionary), but my version also
> handles type checking, etc and it would be more convenient to be able
> to
> access the dynamic properties directly.
Hi Katre,
maybe I have a trick for you. But this might be incompatible with
future versions of Jython, so carefully consider the possible
tradeoffs.
If you apply the following changes to the 2.1 codebase:
File /core/PyJavaInstance.java:
-------------------------------
Old method:
protected void noField(String name, PyObject value) {
throw Py.TypeError("can't set arbitrary attribute in java instance:
"+
name);
}
replaced with:
protected void noField(String name, PyObject value) {
PyObject method = __class__.lookup("__setattr__", false);
if ( method == null ) {
throw Py.TypeError("can't set arbitrary attribute in java
instance: " + name);
} else {
method.__call__(this, new PyString(name), value);
}
}
File /core/PyInstance.java:
---------------------------
Old method:
protected PyObject ifindfunction(String name) {
PyObject getter = __class__.__getattr__;
if (getter == null)
return null;
try {
return getter.__call__(this, new PyString(name));
} catch (PyException exc) {
if (Py.matchException(exc, Py.AttributeError)) return null;
throw exc;
}
}
replaced with:
protected PyObject ifindfunction(String name) {
PyObject getter = __class__.__getattr__;
if ( getter == null && __class__.getProxyClass() != null ) {
getter = __class__.lookup("__getattr__", false);
}
if ( getter == null ) {
return null;
}
try {
return getter.__call__(this, new PyString(name));
} catch (PyException exc) {
if (Py.matchException(exc, Py.AttributeError)) return null;
throw exc;
}
}
then you can design your java class as follows (just a sketch):
package test;
import java.util.HashMap;
import java.util.Map;
public class DynamicProperties {
private Map _properties = new HashMap();
private String _foo;
public String getFoo() {
return _foo;
}
public void setFoo(String foo) {
_foo = foo;
}
public Object getDynProp(String name) {
return _properties.get(name);
}
public void setDynProp(String name, Object value) {
_properties.put(name, value);
}
public Object __getattr__(String name) {
if (_properties.containsKey(name)) {
return getDynProp(name);
} else {
return null;
}
}
public void __setattr__(String name, Object value) {
setDynProp(name, value);
}
}
and write:
Jython 2.1 on java1.4.2_05 (JIT: null)
Type "copyright", "credits" or "license" for more information.
> >> from test import DynamicProperties
> >> dp = DynamicProperties()
> >> dp.dynamic1 = "dynamic1"
> >> dp.dynamic1
'dynamic1'
> >> dp.dynamic2 = "dynamic2"
> >> dp.dynamic2
'dynamic2'
> >> dp.foo = "hey foo"
> >> dp.foo
'hey foo'
> >> dp.getFoo()
'hey foo'
> >> dp.setFoo("foo2")
> >> dp.foo
'foo2'
> >>
Because I heavily depend on this feature - "script-enable" my own java
classes - you can be sure that I will try to make it happen in Jython
2.2, too, but of course I can't guarantee anything.
And a last hint: in java it is completely legal to have a method named
like the lowered part of the set/get bean property method:
public String foo() {
return "this was method foo()";
}
with this method added to DynamicProperties.java, you get:
> >> dp = DynamicProperties()
> >> dp.foo
<method test.DynamicProperties.foo of test.DynamicProperties instance
at 18724539>
> >> dp.foo = "some foo property"
Traceback (innermost last):
File "<console> ", line 1, in ?
TypeError: can't assign to this attribute in java instance: foo
> >> dp.foo()
'this was method foo()'
> >>
Best wishes,
Oti.
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
Jython-users mailing list
Jython-users@[...].net
https://lists.sourceforge.net/lists/listinfo/jython-users
|