commons-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Simon Räss <co...@gmx.ch>
Subject Re: [jxpath] Custom NodePointer implementation
Date Tue, 22 Jun 2004 13:23:38 GMT
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" <cocoa@gmx.ch>
>To: "Jakarta Commons Users List" <commons-user@jakarta.apache.org>
>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: commons-user-unsubscribe@jakarta.apache.org
>>For additional commands, e-mail: commons-user-help@jakarta.apache.org
>>
>>
>>
>>
>
>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: commons-user-unsubscribe@jakarta.apache.org
>For additional commands, e-mail: commons-user-help@jakarta.apache.org
>
>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-user-help@jakarta.apache.org


Mime
View raw message