You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@commons.apache.org by Simon Raess <co...@gmx.ch> on 2004/06/17 23:32:01 UTC

[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


Re: [jxpath] Custom NodePointer implementation

Posted by Simon Räss <co...@gmx.ch>.
Actually I want to get bar by index. So I've tried the static method 
alternative with success with the following method:

public static Bar bar(Foo foo, int index) {
  return foo.getBar((Language)mappings.get(index));
}

The idea is to have an ordering on Bar objects when evaluating xpath 
expressions. In the application imposing any order on Bar objects would 
not make sense because

a) the order can change
b) conceptually there is no notion of ordering

I registered the function with:

JXPathContext context = ...;
// MyFunctions contains the static method from above
context.setFunctions(new ClassFunctions(MyFunctions.class, "test"));

I can then use an xpath expression like:

/test:bar(/, 1)

to extract the first bar. Of course I have to set the mapping to be used 
by the bar method...

By the way, I tried the empty string as namespace parameter to 
ClassFunctions constructor but that did not work 
(NullPointerException...). Is this a bug?

An even simpler version uses an ExpressionContext (as highlighted in the 
users guide) as follows:

public static Bar bar(ExpressionContext context, int index) {
  Foo foo = (Foo)context.getContextNodePointer().getValue();
  return foo.getBar((Language)mappings.get(index));
}

the corresponding xpath is then:

/test:bar(1)

But I'd prefer the following (simpler) form:

/bar[1]

So I'll have to dig a bit deeper. Any help is still appreciated...


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" <co...@gmx.ch>
>To: "Jakarta Commons Users List" <co...@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


Re: [jxpath] Custom NodePointer implementation

Posted by Dmitri Plotnikov <dm...@plotnix.com>.
Congratulations!  Custom implementation of NodePointer is pretty advanced
stuff.  I am impressed.

- Dmitri

----- Original Message ----- 
From: "Simon Räss" <co...@gmx.ch>
To: "Jakarta Commons Users List" <co...@jakarta.apache.org>
Sent: Tuesday, June 22, 2004 9:23 AM
Subject: Re: [jxpath] Custom NodePointer implementation


> 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%20Funct
ions
> >
> >
> >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" <co...@gmx.ch>
> >To: "Jakarta Commons Users List" <co...@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
>
>
>



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


Re: [jxpath] Custom NodePointer implementation

Posted by Simon Räss <co...@gmx.ch>.
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" <co...@gmx.ch>
>To: "Jakarta Commons Users List" <co...@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


Re: [jxpath] Custom NodePointer implementation

Posted by Dmitri Plotnikov <dm...@apache.org>.
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" <co...@gmx.ch>
To: "Jakarta Commons Users List" <co...@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