You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "Aleksandr Bissekerskij (JIRA)" <ji...@apache.org> on 2011/02/17 17:22:24 UTC

[jira] Created: (JXPATH-150) JXPathContext: using AbstractFactory with Map in XPath

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

        

[jira] [Issue Comment Edited] (JXPATH-150) JXPathContext: using AbstractFactory with Map in XPath

Posted by "Matt Benson (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/JXPATH-150?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13045993#comment-13045993 ] 

Matt Benson edited comment on JXPATH-150 at 6/8/11 3:16 PM:
------------------------------------------------------------

I don't see that your custom {{AbstractFactory}} subclass _does_ anything.  JXPath does not know how to instantiate your missing objects, at all.  The {{AbstractFactory}} thing is somewhat brittle, but it's really all we have.  But for example, you could change your example to something like:


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

        final 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) {
                if (parent == p.getChildren()) {
                    return new Child();
                }
                return super.createObject(context, pointer, parent, name, index);
            }
        });
        context.createPathAndSetValue("children/Steven/age", 4);
    }
}
{code}


      was (Author: mbenson):
    I don't see that your custom {{AbstractFactory}} subclass _does_ anything.  JXPath does not know how to instantiate your missing objects, at all.  The {{AbstractFactory}} thing is somewhat brittle, but it's really all we have.  But for example, you could have something like:

//example to follow
  
> 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
>         Attachments: Child.java, JXPathMap.java, Parent.java
>
>
> 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

[jira] [Closed] (JXPATH-150) JXPathContext: using AbstractFactory with Map in XPath

Posted by "Matt Benson (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/jira/browse/JXPATH-150?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Matt Benson closed JXPATH-150.
------------------------------

    Resolution: Invalid

> 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
>         Attachments: Child.java, JXPathMap.java, Parent.java
>
>
> 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

[jira] Updated: (JXPATH-150) JXPathContext: using AbstractFactory with Map in XPath

Posted by "Aleksandr Bissekerskij (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/jira/browse/JXPATH-150?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Aleksandr Bissekerskij updated JXPATH-150:
------------------------------------------

    Attachment: Parent.java
                JXPathMap.java
                Child.java

Original files representing issue that is described.

> 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
>         Attachments: Child.java, JXPathMap.java, Parent.java
>
>
> 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

        

[jira] [Commented] (JXPATH-150) JXPathContext: using AbstractFactory with Map in XPath

Posted by "Matt Benson (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/JXPATH-150?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13045993#comment-13045993 ] 

Matt Benson commented on JXPATH-150:
------------------------------------

I don't see that your custom {{AbstractFactory}} subclass _does_ anything.  JXPath does not know how to instantiate your missing objects, at all.  The {{AbstractFactory}} thing is somewhat brittle, but it's really all we have.  But for example, you could have something like:

{quote}{{
foo
}}{quote}

> 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
>         Attachments: Child.java, JXPathMap.java, Parent.java
>
>
> 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

[jira] [Issue Comment Edited] (JXPATH-150) JXPathContext: using AbstractFactory with Map in XPath

Posted by "Matt Benson (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/JXPATH-150?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13045993#comment-13045993 ] 

Matt Benson edited comment on JXPATH-150 at 6/8/11 3:05 PM:
------------------------------------------------------------

I don't see that your custom {{AbstractFactory}} subclass _does_ anything.  JXPath does not know how to instantiate your missing objects, at all.  The {{AbstractFactory}} thing is somewhat brittle, but it's really all we have.  But for example, you could have something like:

//example to follow

      was (Author: mbenson):
    I don't see that your custom {{AbstractFactory}} subclass _does_ anything.  JXPath does not know how to instantiate your missing objects, at all.  The {{AbstractFactory}} thing is somewhat brittle, but it's really all we have.  But for example, you could have something like:

{quote}{{
foo
}}{quote}
  
> 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
>         Attachments: Child.java, JXPathMap.java, Parent.java
>
>
> 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