Java 如何让JXPath干净地设置列表/集合项

Java 如何让JXPath干净地设置列表/集合项,java,jxpath,Java,Jxpath,我已经开始在单元和集成测试中使用Commons JXPath,作为在bean层次结构中设置一组属性的简单方法 我不能“干净地”使用JXPath的一个场景是设置列表项 我真的希望JXPath做一些“显而易见的事情”,这样,如果我尝试设置列表的条目“[1]”(奇怪的是,他们选择使用基于1的索引),它会将基础列表配置为至少有一个条目。据我所见,这种情况不会发生,我必须手动完成 例如,我想写一些代码: JXPathContext context = JXPathContext.newCont

我已经开始在单元和集成测试中使用Commons JXPath,作为在bean层次结构中设置一组属性的简单方法

我不能“干净地”使用JXPath的一个场景是设置列表项

我真的希望JXPath做一些“显而易见的事情”,这样,如果我尝试设置列表的条目“[1]”(奇怪的是,他们选择使用基于1的索引),它会将基础列表配置为至少有一个条目。据我所见,这种情况不会发生,我必须手动完成

例如,我想写一些代码:

    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
由于两个不同的原因,这不起作用

第一个问题是“数字”列表属性将为空。我可以这样处理:

    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");
    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");
如果我必须在列表中设置除第一个之外的其他条目,我必须使用更多的伪条目初始化列表

我也会觉得有责任在任何地方添加评论,以平息WTF


有没有更干净的方法呢?

嗯,确实很棘手。首先,离题

(奇怪的是,他们选择使用基于1的索引)

这就是XPath的工作方式。有很多原因,但我不确定为什么。Lua编程语言也使用1表示数组

下面是基于您的示例的一些代码(也在中)

public class TestsJxpath {

    public static class Request {
        private Foo foo;
        public Foo getFoo() {
            return foo;
        }
        public void setFoo(Foo foo) {
            this.foo = foo;
        }
        @Override
        public String toString() {
            return "Request [foo=" + foo + "]";
        }
    }

    public static class Foo {
        private String subscriberNumber;
        private Bar bar;
        public String getSubscriberNumber() {
            return subscriberNumber;
        }
        public void setSubscriberNumber(String subscriberNumber) {
            this.subscriberNumber = subscriberNumber;
        }
        public Bar getBar() {
            return bar;
        }
        public void setBar(Bar bar) {
            this.bar = bar;
        }
        @Override
        public String toString() {
            return "Foo [subscriberNumber=" + subscriberNumber + ", bar=" + bar + "]";
        }
    }

    public static class Bar {
        private List<String> numbers = Arrays.asList("");
        public List<String> getNumbers() {
            return numbers;
        }
        @Override
        public String toString() {
            return "Bar [numbers=" + numbers + "]";
        }
    }

    // added after OP reported on
    // https://stackoverflow.com/questions/44530112/how-to-get-jxpath-to-cleanly-set-list-collection-entries
    public static void main(String[] args) {
        Request request = new Request();
        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 no longer fails
        System.out.println(request);
    }

    public static void main2(String[] args) {
        Phone p1 = new Phone(1);
        Phone p2 = new Phone(2);
        List<Phone> phones = new ArrayList<>();
        phones.add(p1);
        phones.add(p2);

        JXPathContext ctx = JXPathContext.newContext(phones);
        System.out.println(phones);
        long phone1 = (long) ctx.getValue("/*[type='br.eti.kinoshita.commons.jxpath.Phone']");
        System.out.println(phone1);
    }
}
公共类TestsJxpath{
公共静态类请求{
私人富福;
公共Foo getFoo(){
返回foo;
}
公共无效设置Foo(Foo-Foo){
this.foo=foo;
}
@凌驾
公共字符串toString(){
返回“请求[foo=“+foo+”]”;
}
}
公共静态类Foo{
私有字符串subscriberNumber;
私人酒吧;
公共字符串getSubscriberNumber(){
返回subscriberNumber;
}
public void setSubscriberNumber(字符串subscriberNumber){
this.subscriberNumber=subscriberNumber;
}
公共酒吧{
返回杆;
}
公共空间立根杆(杆){
这个.bar=bar;
}
@凌驾
公共字符串toString(){
返回“Foo[subscriberNumber=“+subscriberNumber+”,bar=“+bar+””;
}
}
公共静态类栏{
私有列表编号=Arrays.asList(“”);
公共列表getNumbers(){
返回号码;
}
@凌驾
公共字符串toString(){
返回“条[numbers=“+numbers+”]”;
}
}
//在上报告OP后添加
// https://stackoverflow.com/questions/44530112/how-to-get-jxpath-to-cleanly-set-list-collection-entries
公共静态void main(字符串[]args){
请求=新请求();
JXPathContext=JXPathContext.newContext(请求);
setValue(“foo”,新的foo());
setValue(“foo/subscriberNumber”,“1234567890”);
setValue(“foo/bar”,newbar());
setValue(“foo/bar/numbers[1],“123”);//这不再失败
系统输出打印项次(请求);
}
公共静态void main2(字符串[]args){
电话p1=新电话(1);
电话p2=新电话(2);
列表电话=新的ArrayList();
电话。添加(p1);
电话。添加(p2);
JXPathContext ctx=JXPathContext.newContext(电话);
System.out.println(电话);
long phone1=(long)ctx.getValue(“/*[type='br.eti.kinoshita.commons.jxpath.Phone']);
System.out.println(phone1);
}
}
当Apache Commons JXPath找到一个集合(更具体地说是java.util.List的实例)时,它将调用set方法。不管我们怎么努力。您可以尝试使用工厂,或者使用静态方法调用的其他黑客。。。。但是,如果您的案例足够简单,您事先知道列表将包含多少元素,那么您可以使用上述方法,即

private List<String> numbers = Arrays.asList("");
private List number=Arrays.asList(“”);
使用空元素初始化列表,以便
list#set(int,E)
不会引发异常

希望有帮助,
布鲁诺

嗯,确实很棘手。首先,离题

(奇怪的是,他们选择使用基于1的索引)

这就是XPath的工作方式。有很多原因,但我不确定为什么。Lua编程语言也使用1表示数组

下面是基于您的示例的一些代码(也在中)

public class TestsJxpath {

    public static class Request {
        private Foo foo;
        public Foo getFoo() {
            return foo;
        }
        public void setFoo(Foo foo) {
            this.foo = foo;
        }
        @Override
        public String toString() {
            return "Request [foo=" + foo + "]";
        }
    }

    public static class Foo {
        private String subscriberNumber;
        private Bar bar;
        public String getSubscriberNumber() {
            return subscriberNumber;
        }
        public void setSubscriberNumber(String subscriberNumber) {
            this.subscriberNumber = subscriberNumber;
        }
        public Bar getBar() {
            return bar;
        }
        public void setBar(Bar bar) {
            this.bar = bar;
        }
        @Override
        public String toString() {
            return "Foo [subscriberNumber=" + subscriberNumber + ", bar=" + bar + "]";
        }
    }

    public static class Bar {
        private List<String> numbers = Arrays.asList("");
        public List<String> getNumbers() {
            return numbers;
        }
        @Override
        public String toString() {
            return "Bar [numbers=" + numbers + "]";
        }
    }

    // added after OP reported on
    // https://stackoverflow.com/questions/44530112/how-to-get-jxpath-to-cleanly-set-list-collection-entries
    public static void main(String[] args) {
        Request request = new Request();
        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 no longer fails
        System.out.println(request);
    }

    public static void main2(String[] args) {
        Phone p1 = new Phone(1);
        Phone p2 = new Phone(2);
        List<Phone> phones = new ArrayList<>();
        phones.add(p1);
        phones.add(p2);

        JXPathContext ctx = JXPathContext.newContext(phones);
        System.out.println(phones);
        long phone1 = (long) ctx.getValue("/*[type='br.eti.kinoshita.commons.jxpath.Phone']");
        System.out.println(phone1);
    }
}
公共类TestsJxpath{
公共静态类请求{
私人富福;
公共Foo getFoo(){
返回foo;
}
公共无效设置Foo(Foo-Foo){
this.foo=foo;
}
@凌驾
公共字符串toString(){
返回“请求[foo=“+foo+”]”;
}
}
公共静态类Foo{
私有字符串subscriberNumber;
私人酒吧;
公共字符串getSubscriberNumber(){
返回subscriberNumber;
}
public void setSubscriberNumber(字符串subscriberNumber){
this.subscriberNumber=subscriberNumber;
}
公共酒吧{
返回杆;
}
公共空间立根杆(杆){
这个.bar=bar;
}
@凌驾
公共字符串toString(){
返回“Foo[subscriberNumber=“+subscriberNumber+”,bar=“+bar+””;
}
}
公共静态类栏{
私有列表编号=Arrays.asList(“”);
公共列表getNumbers(){
返回号码;
}
@凌驾
公共字符串toString(){
返回“条[numbers=“+numbers+”]”;
}
}
//在上报告OP后添加
// https://stackoverflow.com/questions/44530112/how-to-get-jxpath-to-cleanly-set-list-collection-entries
公共静态void main(字符串[]args){
请求=新请求();
JXPathContext上下文=JXP