JXPathContext: using AbstractFactory with Map in XPath
------------------------------------------------------
Key: JXPATH-150
URL: https://issues.apache.org/jira/browse/JXPATH-150
Project: Commons JXPath
Issue Type: Improvement
Affects Versions: 1.3
Reporter: Aleksandr Bissekerskij
Priority: Minor
Hello,
I have a problem with JXPath which I suppose is something that is not supported
yet, though it's looks like a bug.
I'm using AbstractFactory implementation to create missing objects in XPath
when setting properties. (see
http://commons.apache.org/jxpath/users-guide.html#Creating_Objects). Everything
works fine as long as missing objects are Bean-like objects, or any
Collections. But if missing object is one of objects in Map<K,V> problems
begin. Here is my issue (please find complete code of used classes and working
example attached):
{code:title=Parent.java}
package tests.xpath;
import java.util.Map;
public class Parent {
private String name;
private Map<String, Child> children;
Parent() {}
Parent(String name) { setName(name); }
public Map<String, Child> getChildren() { return children; }
public void setChildren(Map<String, Child> children) { this.children =
children; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
@Override
public String toString() {
return this.getClass().getSimpleName() + "[" +
"name=" + getName() + ", " +
"children=" + getChildren() +
"]";
}
}
{code}
{code:title=Child.java}
package tests.xpath;
public class Child {
private String sex;
private int age;
Child() {}
Child(String sex, int age) { setSex(sex); setAge(age); }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getSex() { return sex; }
public void setSex(String sex) { this.sex = sex; }
@Override
public String toString() {
return this.getClass().getSimpleName() + "[" +
"sex=" + getSex() + ", " +
"age=" + getAge() +
"]";
}
}
{code}
{code:title=JXPathMap.java}
package tests.xpath;
import java.util.LinkedHashMap;
import org.apache.commons.jxpath.AbstractFactory;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.Pointer;
public class JXPathMap {
public static void main (String[] args) {
Parent p = new Parent("Dad");
p.setChildren(new LinkedHashMap<String, Child>() {{
put("Bobby", new Child("Male", 9));
put("Steven", null);
put("Sandra", new Child("Female", 12));
}});
JXPathContext context = JXPathContext.newContext(p);
context.setFactory(new AbstractFactory() {
@Override
public boolean createObject(JXPathContext context, Pointer pointer,
Object parent, String name, int index) {
System.out.println("parent: " + parent);
System.out.println("name: " + name);
System.out.println("index: " + index);
return super.createObject(context, pointer, parent, name,
index);
}
});
context.createPathAndSetValue("children/Steven/age", 4);
}
}
{code}
this code results as following:
{noformat}
parent: {Bobby=Child[sex=Male, age=9], Steven=null, Sandra=Child[sex=Female,
age=12]}
name: Steven
index: 0
Exception in thread "main" org.apache.commons.jxpath.JXPathException: Exception
trying to create xpath children/Steven/age; Factory could not create an object
for path: /children[@name='Steven']
at
org.apache.commons.jxpath.ri.JXPathContextReferenceImpl.createPathAndSetValue(JXPathContextReferenceImpl.java:549)
at
org.apache.commons.jxpath.ri.JXPathContextReferenceImpl.createPathAndSetValue(JXPathContextReferenceImpl.java:533)
at tests.xpath.JXPathMap.main(JXPathMap.java:29)
Caused by: org.apache.commons.jxpath.JXPathAbstractFactoryException: Factory
could not create an object for path: /children[@name='Steven']
at
org.apache.commons.jxpath.ri.model.dynamic.DynamicPropertyPointer.createPath(DynamicPropertyPointer.java:230)
at
org.apache.commons.jxpath.ri.model.beans.NullPointer.createPath(NullPointer.java:100)
at
org.apache.commons.jxpath.ri.model.beans.NullPropertyPointer.createPath(NullPropertyPointer.java:138)
at
org.apache.commons.jxpath.ri.JXPathContextReferenceImpl.setValue(JXPathContextReferenceImpl.java:584)
at
org.apache.commons.jxpath.ri.JXPathContextReferenceImpl.createPathAndSetValue(JXPathContextReferenceImpl.java:546)
... 2 more
{noformat}
I must mention that context.createPathAndSetValue("children/Bobby/age", 4)
works fine - sets Bobby's age to 4. In case of missing object is element of
collection - everything works fine, I would get Parent as parent object,
children as property that has missing object and index so i know where to put
my newly created object.
In case of Map I don't get enough information to instantiate missing object.
"Steven" as property name is most surprising. Exception is OK, cause nothing is
created by factory.
I suppose that AbstractFactory should have separate method in case of Map
element is missed. JXPath easily detects that it is Map because setting
"children/Bobby/age" works as expected.
Regards,
Aleksandr
--
This message is automatically generated by JIRA.
-
For more information on JIRA, see: http://www.atlassian.com/software/jira