Hi,

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):


public class Parent {
    private String name;
    private Map<String, Child> children;
}

public class Child {
    private String sex;
    private int age;
}

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);
    }
}

*
*

this code results as following:



*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

*

*
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.
*
*I'm quite sure that I will post this to issue tracking system, but first
I'd like to ask if anybody had similar issue? may be i am missing something
important?

Any comments are appreciated.

Regards,
Aleksandr
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() +
                "]";
    }
}
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);
    }
}
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() +
                "]";
    }



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

Reply via email to