ASPN ActiveState Programmer Network
ActiveState
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups


Recent Messages
List Archives
About the List
List Leaders
Subscription Options

View Subscriptions
Help

View by Topic
ActiveState
.NET Framework
Open Source
Perl
PHP
Python
Tcl
Web Services
XML & XSLT

View by Category
Database
General
SOAP
System Administration
Tools
User Interfaces
Web Programming
XML Programming


MyASPN >> Mail Archive >> Jython-users
Jython-users
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

Privacy Policy | Email Opt-out | Feedback | Syndication
© 2004 ActiveState, a division of Sophos All rights reserved