You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@commons.apache.org by Hippo Man <hi...@gmail.com> on 2011/07/30 01:17:37 UTC

[jxpath] Passing casting information within a path-based setter?

I'm fairly new to JXPath and I have a question for which I was unable to find
an answer in any of the places I searched for on line. I ask you in advance to
please forgive me if the answer to my question can be found in some
easy-to-locate
place that I happened to overlook.

Is there a way to do casting within a path-based JXPath setter? I'd like to be
able to optionally specify that the setting of an item gets done via a
subclass that
has more attributes than the parent, but I couldn't find out how to do this.

I'm sure that my question is not completely clear, so as you read this
discussion, please look at the Java fragments at the bottom of this message
to see an illustration of what I'm trying to do.

Consider the sample class (below) called TheObject. It has two attributes:
a String called "name", and an array of TheData objects.

The TheData class (below) contains a single String attribute called "item".

There is a subclass of TheData called TheChild, and it contains a String
attribute called "varString", a Long attribute called "varLong", and a Double
attribute called "varDouble".

I want to use JXPath path-based setters to set the attributes within TheObject.
I have implemented an extension of AbstractFactory called ObjectFactory
to aid in this procedure. ObjectFactory also appears below.

In the "main" method of TheObject, I instantiate my JXPath context and attach
my ObjectFactory, after which I set some attributes. As you can see in my
example, this works fine as long as I want my "dataArray" to be instantiated
as an array of TheData objects and then set the "item" attribute of one of
these instances.

But sometimes, I might want to instantiate "dataArray" with an array of TheChild
objects. I would like this instantiation to take place within
"createObject", and I'd
like it to be able to determine at runtime via some sort of syntax in
the path setter
that "createObject" should instantiate with TheChild objects instead of TheData
objects.

In other words, is there some sort of "casting" syntax that I can pass into the
path setter which I can then see within the "name" or "pointer" parameters to
"createObject" which can tell me that I have to instantiate that array with
TheChild objects instead of TheData objects?

For the purpose of illustration, I gave an unworkable example of casting
syntax within the "main" method of TheObject, below. That example shows
exactly what I'm trying to do.

Thanks in advance for any pointers to documentation or any other help that
any of you might be able to give me.

Here are the Java code fragments that I mentioned above ...

public class TheObject {
    protected String      name      = null;
    protected TheData[]   dataArray = null;
    // constructor, getters, setters, and toString have been left out

    public static void main(String[] argv) {
        TheObject obj = new TheObject();
        JXPathContext context = JXPathContext.newContext(obj);
        context.setFactory(new ObjectFactory());

        context.createPathAndSetValue("/name", "foo"); // this works
        context.createPathAndSetValue("/dataArray[1]/item", "bar");
// this works

        // But instead of setting "item" as I did above, is there something
        // I can do syntactically in the path that I can see within the "name"
        // or "pointer" arguments that are passed to the createObject() method
        // of ObjectFactory, which would specify that "dataArray" should be
        // instantiated as an array of TheChild objects instead of as an array
        // of TheData objects?  Something analogous to this (I know this doesn't
        // work; it's just for illustration) ...

        context.createPathAndSetValue("/{cast to
TheChild}dataArray[1]/varString", "quack");

        System.out.println(obj);

        System.exit(0);
    }
}

public class TheData {
    protected String item = null;
    // constructor, getters, setters, and toString have been left out
}

public class TheChild extends TheData {
    protected String varString = null;
    protected Long   varLong   = null;
    protected Double varDouble = null;
    // constructor, getters, setters, and toString have been left out
}

public class ObjectFactory extends AbstractFactory {

    @Override
    public boolean createObject(JXPathContext context, Pointer
pointer, Object parent, String name, int index) {
        System.out.println("createObject: pointer: " + pointer + ",
parent: " + parent.getClass().getName() + ", name: " + name + ",
index: " + index);

        if (parent instanceof TheObject) {

            // Is there something I can pass in via the path setter or that
            // I can access via "pointer" which will tell me that I
want to instantiate
            // the data array with instances of TheChild instead of TheData?

            if (name.equalsIgnoreCase("dataArray")) {
                TheData[] data = new TheData[index + 1];
                TheData[] oldData = ((TheObject) parent).getDataArray();
                int nold = (oldData == null ? 0 : oldData.length);
                for (int n = 0; n <= index; n++) {
                    if (n < nold) {
                        data[n] = oldData[n];
                    }
                    else {
                        data[n] = new TheData();
                    }
                }
                for (int n = index + 1; n < nold; n++) {
                    data[n] = oldData[n];
                }
                ((TheObject) parent).setDataArray(data);
            }
            return (true);
        }
        return (false);
    }
}

--
 hippo.mailbox@gmail.com

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


Re: [jxpath] Passing casting information within a path-based setter?

Posted by Hippo Man <hi...@gmail.com>.
On Fri, Jul 29, 2011 at 20:54, Matt Benson <gu...@gmail.com> wrote:
> Quick potential suggestions:
>
> - Set some property on the parent, and query it in your factory
> - Subclass TheObject and override the dataArray accessors to TheChild[]
> - Use a different factory instance that does what you want

Thank you. My proposed fix already would use another factory
instance. That's where my custom createObject() method lives.
But that factory instance would still have to figure out how to
cast the items based on _some_ information, which I hoped
that I could embed within the xpath setter.

If there are no such things as comments within these xpath
setters (which I could read at run time via the "name" parameter
to createObject), then I guess I'll have to figure out a way to
store this information as properties of the objects, themselves
... or something.

Oh well ... (sigh)

Thanks again!

--
 hippo.mailbox@gmail.com

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


Re: [jxpath] Passing casting information within a path-based setter?

Posted by Matt Benson <gu...@gmail.com>.
Quick potential suggestions:

- Set some property on the parent, and query it in your factory
- Subclass TheObject and override the dataArray accessors to TheChild[]
- Use a different factory instance that does what you want

Matt

On Fri, Jul 29, 2011 at 6:17 PM, Hippo Man <hi...@gmail.com> wrote:
> I'm fairly new to JXPath and I have a question for which I was unable to find
> an answer in any of the places I searched for on line. I ask you in advance to
> please forgive me if the answer to my question can be found in some
> easy-to-locate
> place that I happened to overlook.
>
> Is there a way to do casting within a path-based JXPath setter? I'd like to be
> able to optionally specify that the setting of an item gets done via a
> subclass that
> has more attributes than the parent, but I couldn't find out how to do this.
>
> I'm sure that my question is not completely clear, so as you read this
> discussion, please look at the Java fragments at the bottom of this message
> to see an illustration of what I'm trying to do.
>
> Consider the sample class (below) called TheObject. It has two attributes:
> a String called "name", and an array of TheData objects.
>
> The TheData class (below) contains a single String attribute called "item".
>
> There is a subclass of TheData called TheChild, and it contains a String
> attribute called "varString", a Long attribute called "varLong", and a Double
> attribute called "varDouble".
>
> I want to use JXPath path-based setters to set the attributes within TheObject.
> I have implemented an extension of AbstractFactory called ObjectFactory
> to aid in this procedure. ObjectFactory also appears below.
>
> In the "main" method of TheObject, I instantiate my JXPath context and attach
> my ObjectFactory, after which I set some attributes. As you can see in my
> example, this works fine as long as I want my "dataArray" to be instantiated
> as an array of TheData objects and then set the "item" attribute of one of
> these instances.
>
> But sometimes, I might want to instantiate "dataArray" with an array of TheChild
> objects. I would like this instantiation to take place within
> "createObject", and I'd
> like it to be able to determine at runtime via some sort of syntax in
> the path setter
> that "createObject" should instantiate with TheChild objects instead of TheData
> objects.
>
> In other words, is there some sort of "casting" syntax that I can pass into the
> path setter which I can then see within the "name" or "pointer" parameters to
> "createObject" which can tell me that I have to instantiate that array with
> TheChild objects instead of TheData objects?
>
> For the purpose of illustration, I gave an unworkable example of casting
> syntax within the "main" method of TheObject, below. That example shows
> exactly what I'm trying to do.
>
> Thanks in advance for any pointers to documentation or any other help that
> any of you might be able to give me.
>
> Here are the Java code fragments that I mentioned above ...
>
> public class TheObject {
>    protected String      name      = null;
>    protected TheData[]   dataArray = null;
>    // constructor, getters, setters, and toString have been left out
>
>    public static void main(String[] argv) {
>        TheObject obj = new TheObject();
>        JXPathContext context = JXPathContext.newContext(obj);
>        context.setFactory(new ObjectFactory());
>
>        context.createPathAndSetValue("/name", "foo"); // this works
>        context.createPathAndSetValue("/dataArray[1]/item", "bar");
> // this works
>
>        // But instead of setting "item" as I did above, is there something
>        // I can do syntactically in the path that I can see within the "name"
>        // or "pointer" arguments that are passed to the createObject() method
>        // of ObjectFactory, which would specify that "dataArray" should be
>        // instantiated as an array of TheChild objects instead of as an array
>        // of TheData objects?  Something analogous to this (I know this doesn't
>        // work; it's just for illustration) ...
>
>        context.createPathAndSetValue("/{cast to
> TheChild}dataArray[1]/varString", "quack");
>
>        System.out.println(obj);
>
>        System.exit(0);
>    }
> }
>
> public class TheData {
>    protected String item = null;
>    // constructor, getters, setters, and toString have been left out
> }
>
> public class TheChild extends TheData {
>    protected String varString = null;
>    protected Long   varLong   = null;
>    protected Double varDouble = null;
>    // constructor, getters, setters, and toString have been left out
> }
>
> public class ObjectFactory extends AbstractFactory {
>
>    @Override
>    public boolean createObject(JXPathContext context, Pointer
> pointer, Object parent, String name, int index) {
>        System.out.println("createObject: pointer: " + pointer + ",
> parent: " + parent.getClass().getName() + ", name: " + name + ",
> index: " + index);
>
>        if (parent instanceof TheObject) {
>
>            // Is there something I can pass in via the path setter or that
>            // I can access via "pointer" which will tell me that I
> want to instantiate
>            // the data array with instances of TheChild instead of TheData?
>
>            if (name.equalsIgnoreCase("dataArray")) {
>                TheData[] data = new TheData[index + 1];
>                TheData[] oldData = ((TheObject) parent).getDataArray();
>                int nold = (oldData == null ? 0 : oldData.length);
>                for (int n = 0; n <= index; n++) {
>                    if (n < nold) {
>                        data[n] = oldData[n];
>                    }
>                    else {
>                        data[n] = new TheData();
>                    }
>                }
>                for (int n = index + 1; n < nold; n++) {
>                    data[n] = oldData[n];
>                }
>                ((TheObject) parent).setDataArray(data);
>            }
>            return (true);
>        }
>        return (false);
>    }
> }
>
> --
>  hippo.mailbox@gmail.com
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
> For additional commands, e-mail: user-help@commons.apache.org
>
>

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


[jxpath] Passing casting information within a path-based setter?

Posted by Hippo Man <hi...@gmail.com>.
On Fri, Jul 29, 2011 at 20:43, Hippo Man <hi...@gmail.com> wrote:
>
> Am I out of luck?

I just thought of another idea.

Can I perhaps use some sort of custom function for this purpose?

For example:

context.createPathAndSetValue("/myCastFunc(\"/dataArray[1]\",
\"TheChild\")/varString", "quack");

... or something like that, where "myCastFunc" is a custom-written
function that will take the supplied xpath and cast it to the class
named as the second argument.

Would something like this work for me?

--
 hippo.mailbox@gmail.com

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


Fwd: [jxpath] Passing casting information within a path-based setter?

Posted by Hippo Man <hi...@gmail.com>.
I'm sorry.  I have to figure out how to make my email client
auto-respond to this mailing list.

Here's my recent response, which accidentally was sent to the
sender and not this list ...

On Fri, Jul 29, 2011 at 20:14, Martin Gainty <mg...@hotmail.com> wrote:
>
> [ ... ]
>
> MG>Create the properly casted item BEFORE passing into createPathAndSetValue
> method
> MG>TheChild child=(TheChild)dataArray[i].varString;

Thank you very much, but unfortunately, I am unable to do this
in the application that I'm working on. We have several
hundred beans which get auto-generated from some changing
configuration information, and the _only_ way we can set
values within our application is to do so via the xpath-based
setters. Sadly, we can't instantiate objects before calling
createPathAndSetValue.

Is there perhaps some "neutral", do-nothing syntax that can
be embedded in the xpath setter? Perhaps some sort of
comment?

For example, if there were comments that were delimited by
"{{" and "}}" (I know there aren't), the xpath setter could look
something like this:

"/{{cast:TheChild}}dataArray[1]/varString"

Then, I could parse this casting information out of the "name"
parameter for createObject, and I could then do the casting
myself, within that method.

If out-of-the-box jxpath doesn't allow comments within the
xpath setter, is it possible, perhaps, to write a custom parser?

Um ... I guess I should rephrase that: is it relatively simple
to write a custom parser?


> MG>There is a way to divine the type of Object passed in with
> Class.instanceOf  ..something like this should test the Type of class
> [ ... etc. ... ]

But wouldn't this only work if I previously set the object
to TheChild, as you suggested above?

If it turns out that I can't easily do what I want, I'll try to figure
out some sort of workaround within our application. But I'd
prefer to get this to work solely via xpath setters and the
createObject method, if at all possible.

Am I out of luck?

Thanks again for your help!

--
 hippo.mailbox@gmail.com

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