New Reflection/Beans API

Markus Dahm <[email protected]>
Newsgroups gmane.comp.jakarta.bcel.devel
Message-ID <[email protected]>
Hi,

recently there has been some discussion about how to design/implement
an Reflection and Bean API using BCEL. Since I think it would be a
very good idea to have such a thing in BCEL, I'd like to start a
discussion here about the requirements and implementation issues.

This is not a real proposal, just a collection of thoughts and ideas
where I took some from a previous posting by Stephen Colebourne.

Reflection:
-----------

How it should work is obvious (!?), we add some code to the class that
is to used be used reflectively. We could do this statically, i.e., in
some kind of compiler, or using a class loader, which may be a little
less performant, but is of course much more flexible.

The benefits of such an API would be

a) increased performance of reflection (measurements?)

b) additional features possible, e.g., we could have a class loader
that allows to run a chain of class modifiers, where adding reflexive
behaviour would be just one. I.e., such class modifiers would have a
method

	 public JavaClass modifyClass(JavaClass clazz) { ... }

c) base for a Beans API

The question is how to tell which classes need to be augmented. This
has to be know statically since we only have one chance to augment the
class, namely when it is loaded/created. The simpliest approach would
be to require the class to implement a marker interface, say

	public interface Reflective {}

The other possibility would be to tell the class loader, before the
class gets loaded, e.g., via some regular expression:

cl.addReflectiveClass("com.foo.beans.*Impl");

One could also restrict access to certain methods and fields.

--------------------------------------------------------------------------------

Given that we want to modify class A

public class A implements Reflective {
        private String str;
        private int    x;

        int foo() { }
        int foo(int x) { }
}

We would then like to use reflection like this:

    A         a       = new A();
    JavaClass clazz   = Repository.lookupClass("A");
    Field[]   fields  = clazz.getFields();
    Method[]  methods = clazz.getMethods();

    fields[0].setValue(a, "Hello world");
    Object result = methods[i].invoke(a, new Object[] { new 
Integer(4711); });

Of course setValue/invoke would throw an exception if the passed
object does not support our kind of reflection.

    public void setValue(Object target, Object value) throws SomeException {
      if(target instanceof BCELReflective) {
        ((BCELReflective)target).BCELsetValue(target, field_name, value);
      } else if(target == null) { // Access to static field
        ??????????????
      }
    }

However, we have our first problem here: How does this work for static
fields and methods?


As you probably already noticed the class loader or whatever would let A
implement another interface and implement its methods:

public interface BCELReflective {
        public void BCELsetValue(String name, Object value);
        public Object BCELgetValue(String name);
        public Object BCELinvoke(String name, Object[] args);
}

These methods would wrap/unwrap the arguments and call the
corresponding methods or set/get the right field.


Problems so far:
---------------

* As we all know methods may be overloaded thus just using the name is
   not really sufficient here, instead we could use the method index or
   some generated identifier. Using the index would allow us to use a
   fast switch() statement.

* Fields and methods currently do not know their index nor the
   JavaClass object they belong to. We could pass them in the
   setValue/invoke argument list.

* How do we implement reflection for static fields and methods?



Beans (Really just a scratch file of ideas):
-------------------------------------------

I'm not an expert on Java Beans, but probably many of you are...

What we could have is an extension of ClassGen, say BeanGen that has
additional methods and an extended InstructionFactory. I know there
is a class somewhere the Java Bean API such as "BeanAdapter" which
already implements the default behaviour and can be used as a
delegatee. I.e., we can use this class in our API.

What we obviously need is a declarative way to tell which features
we want for our bean. Having an interface with empty methods is a
very simple approach, but I think we need something more powerful.
One problem is for example that property names need not to be
equivalent to field names. Getters and setters may have additional
checking code that relies on other fields.

Possible features:
------------------
* Property objects (i.e. bound to a particular object field)
* Read-only properties
* Automagically generated setters, getters, event methods, etc.
* Generate BeanInfo's for Introspection
* Generate Beans for alternate sources (XML, DB tables)
* Collection handling
* See below :)

Cheers
	Markus

P.S. The developer list is being archived now.

-------------------------------------------------------------------------------
The original positing from Stephen Colebourne


Scope:
Reflection - Class, Method, Field, ...
Bean - Introspector, javabeans

Need:
- Performance on java1.3 and earlier
- J2ME
- Current reliance on javabean spec version 1 that was designed to replace
ActiveX, not be a domain model.
- Boring coding of javabean gets/sets (I know tools can help, but I still
see bugs in gets and sets)
- Auto generated event methods (bound/constrained properties)
- Desire for dynamicly created javabeans/ properties (from databases, xml
etc.)
- Desire to pass around an object representing a property
- Desire to change the bean Introspector's lookup mechanism, such as to
allow private get/set methods to be treated as properties
- Desire to handle collections properly (they aren't handled at all by beans
Introspector at the moment
- Desire to dynamically make a property read only once setup (like const in
C)

Bean types:
- Coder writes interface with coded get and set methods, BCEL generates
implementation on the fly
- Coder writes abstract class with coded get and set methods, BCEL generates
implementation on the fly
- Coder writes real class with coded get and set methods, BCEL modifies
parts on the fly
- A general purpose bean, to be used where all the data is dynamic, similar
to a HashMap
- A mixture object, where some fields have coded get and set methods, others
are dynamically created as the application requires


OK, so if you haven't guessed, I'm more interested in Beans than Reflection
on its own (Reflection is fine and useful, but its very low level). Most of
these ideas come from the Joda project, but I think they represent a good
idea of what people are using beans for now.

Stephen
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.