I've started to use Commons JXPath in my unit and integration tests, as a simple way to set a set of properties in a bean hierarchy.
One scenario where I can't use JXPath "cleanly" is in setting list entries.
I'd really like for JXPath to do the "obvious stuff", so that if I try to set entry "[1]" of a list (odd that they chose to use 1-based indexes), it will configure the underlying list to have at least one entry. From what I've seen, this doesn't happen, and I have to do it manually.
For instance, here's some code that I'd like to write:
JXPathContext context = JXPathContext.newContext(request);
context.setValue("foo", new Foo());
context.setValue("foo/subscriberNumber", "1234567890");
context.setValue("foo/bar", new Bar());
context.setValue("foo/bar/numbers[1]", "123"); // this fails
This does not work, for a couple of different reasons.
The first issue is that the "numbers" list property will be null. I could deal with that like this:
JXPathContext context = JXPathContext.newContext(request);
context.setValue("foo", new Foo());
context.setValue("foo/subscriberNumber", "1234567890");
context.setValue("foo/bar", new Bar());
context.setValue("foo/bar/numbers", new ArrayList<String>());
context.setValue("foo/bar/numbers[1]", "123");
Or I could register an AbstractFactory and use "createPathAndSetValue()" instead.
However, this still fails because even though the list may exist, it will have zero size and fails to access the 0th entry.
I'm forced to do something like this:
JXPathContext context = JXPathContext.newContext(request);
context.setValue("foo", new Foo());
context.setValue("foo/subscriberNumber", "1234567890");
context.setValue("foo/bar", new Bar());
context.setValue("foo/bar/numbers", Arrays.asList(""));
context.setValue("foo/bar/numbers[1]", "123");
If I have to set other entries in the list besides the first one, I'll have to init the list with more dummy entries.
I'll also feel responsible to add a comment everywhere I do this to quell the WTFs.
Is there a cleaner way to do this?