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