So, I finally succeeded. Here's what I've done:

- I created custom PropertyPointer subclass called CustomPropertyPointer
- I created BeanPropertyPointer subclass CustomBeanPointer that overrides the
getPropertyPointer() method to return my custom property pointer
- I created a custom NodePointerFactory that returns a CustomBeanPointer for
the bean in question (class Foo) called CustomPointerFactory


That's the easy version. It was a bit more difficult though...

In BeanPropertyPointer, everything is based on the method getPropertyDescriptors(). This method returns an array of java.beans.PropertyDescriptor. As my read method is not a standard bean read method, it cannot be described by a PropertyDescriptor. So I reimplemented BeanPropertyPointer (now named CustomPropertyPointer) to be based on a new method getPropertyDescs() that returns an array of PropertyDescs:

public interface PropertyDesc {
   public String getName();
   public int getLength(Object bean, Object baseValue);
   public Object getBaseValue(Object bean);
   public Object getValue(Object bean, int index);
   public boolean isCollection(Object baseValue);
}

I then created an implementation BeanPropertyDesc that is based on a PropertyDescriptor. This interface allowed me to implement the custom behavior. It's implemented in TestPropertyDesc.

The getValue method of this implementation looks like:

public Object getValue(Object bean, int index) {
   Root root = (Root) bean;
   List list = getMapping();
   return root.getC((String) list.get(index));
}

The mapping is a simple list that maps from index to a String in this case. The mapping is set on CustomPropertyFactory an is passed down all the way through CustomBeanPointer to CustomPropertyPointer to TestPropertyDesc.

The Root class has the following method:
+getC(key:String):C

With the above custom pointers it's now possible to access C objects by index like:

/c[2]

Why this fuss? Simply because there is no notion of ordering (e.g. Root does not have a list of C, it has a set of C) in the model of my application and I don't want to add an ordering. The ordering is only important for the output. In my real case, instances of C (Text) are accessed by language (Language).

If you are interested in the implementation example, you can have a glance here:
http://sim.iserver.ch:81/repos/private/jxpath/trunk/


As I'm pretty new to jxpath I might have implemented it way to complicated. Let me know, I'm interested in any simplifications...

Simon



Dmitri Plotnikov wrote:

Simon,

A possible alternative to using custom NodePointers in this situation could
be a custom Function.

Step 1. You implement a static method that does pretty much what you have in
your example:

public class MyFunc {
public static Bar barByLang(Foo foo, String ln) {
 Language lang = (Language)mapping.get(ln);
 return foo.getBar(lang);
}
}

Step 2. Register the MyFunc class with JXPathContext.

Step 3. Use the function like this context.getValue("barByLang(/foo,
'fr')");

Also see
http://jakarta.apache.org/commons/jxpath/users-guide.html#Extension%20Functions


Now, if you insist on custom implementation of NodePointer, choose the right superclass. For example, BeanPropertyPointer might be the right one.

I hope this helps

- Dmitri

----- Original Message ----- From: "Simon Raess" <[EMAIL PROTECTED]>
To: "Jakarta Commons Users List" <[EMAIL PROTECTED]>
Sent: Thursday, June 17, 2004 5:32 PM
Subject: [jxpath] Custom NodePointer implementation




hi

I hope to get some ideas how to implement the following:

Let's say I have a class Foo that can contain several Bar instances.
The Bar instances are accessed by a key, let's say a Language object.
So I have the following methods in Foo:

public Bar getBar(Language l);
public Set getLanguages();

In the model of my application I don't want to have an absolute
ordering of Bar objects, that is I don't want to expose a method like

public Bar getBar(int index);

or similar. My idea is to have an external object impose an ordering on
the Bar objects (that is an ordering on languages). The point is, that
the ordering may change at runtime. What that basically means is, that
I'll have a mapping from a int key to a Language. For example the
mapping would contain:

Language   int key
de         0
fr         1
en         2

So my idea is to create a custom NodePointer that receives such a
mapping definition (so it knows about the ordering of languages). The
following xpath expression (with the above mapping definition) should
return the text with language fr:

foo/bar[2]

This should be translated (by the custom NodePointer) to a call to:

int index = ...;
Foo foo = ...;
List mapping = ...;
Language lang = (Language)mapping.get(index);
Bar fr_bar = foo.getBar(lang);

The following xpath

foo/bar

should probably be converted to something like

List list = foo.getBar();

I'm still unconfident about the jxpath internals, so could please
somebody give me some pointers how I could achieve that? I'm I on the
right tracks? Which methods from NodePointer class must I override
(except the abstract ones, of course)? Is there a simple example that
shows how to implement a NodePointer for objects without using any
reflection, introspection, ...? Is there anything else I should
consider? Please ask me if I missed some important information!

best regards
Simon


--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]







--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]





---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Reply via email to