Commons JXPath - Modifying Object Graphs

JXPath 除了可以 XPath 语法访问 JavaBeans、DOM/JDOM,也可以对其属性赋值。

 

以下面的 JavaBeans 为例。

package com.huey.jxpath;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {

    private String title;
    private Author[] authors;
    private Publisher publisher;
    private String isbn;
    private double price;
    
}
Book.java
package com.huey.jxpath;

import java.util.Date;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Author {

    private String firstName;
    private String lastName;
    private char gender;
    private Date birthday;
    
}
Author.java
package com.huey.jxpath;

import java.util.Map;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Publisher {

    private String name;
    private String address;
    private Map<String, String> contacts;
    
}
Publisher.java

初始化:

Author[] authors;
Publisher publisher;
Book book;

authors = new Author[] {
    new Author("Eric", "Freeman", 'F', new Date()),
    new Author("ElElisabeth", "Freeman", 'M', new Date())
};

Map<String, String> contacts = new HashMap<String, String>();
contacts.put("tel", "010-12345678");
contacts.put("fax", "010-87654321");
contacts.put("email", "test@163.com");
publisher = new Publisher("中国电力出版社", "北京市XX区YY路Z号", contacts);

book = new Book("Head First Design Patterns", authors, publisher, "9787508353937", 98.0);

 

Setting Properties

JXPathContext context = JXPathContext.newContext(book);
context.setValue("publisher/name", "人民邮电出版社");
context.setValue("publisher/contacts/attribute::email", "test@gmail.com");

 

Creating Objects

当对 JavaBean 的复杂数据类型属性设置值时,如果属性没有实例化,则会抛出一个 JXPathException 异常。实现 AbstractFactory 接口后,再调用 context.createPath 方法,能够在复杂数据类型对象为 null 时,为其实例化。context.createPathAndSetValue 方法能够在实例化对象的同时设置值。

package com.huey.jxpath;

import java.lang.reflect.Array;
import java.util.HashMap;

import org.apache.commons.jxpath.AbstractFactory;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.Pointer;

public class BookFactory extends AbstractFactory {

    @Override
    public boolean createObject(JXPathContext context, Pointer pointer,
            Object parent, String name, int index) {
        
        if (parent instanceof Book && "authors".equals(name)) {    
            Book book = (Book) parent;
            if (book.getAuthors() == null) {
                book.setAuthors(new Author[]{});
            }
            int newSize = index + 1;
            int oldSize = book.getAuthors().length;
            if (newSize > oldSize) {
                Author[] newAuthors = (Author[]) resizeArray(book.getAuthors(), newSize);
                book.setAuthors(newAuthors);
            }
            return true;
        }
        if (parent instanceof Book && "publisher".equals(name)) {
            ((Book)parent).setPublisher(new Publisher());
            return true;
        }
        if (parent instanceof Publisher && "contacts".equals(name)) {
            ((Publisher)parent).setContacts(new HashMap<String, String>());
            return true;
        }
        return false;
    }
    
    /**
     * 调整数组长度,当新的数组长度大于旧的数组长度时,实例化所有新增的元素
     * @param oldArray
     * @param newSize
     * @return
     */
    private Object resizeArray (Object oldArray, int newSize) {
        int oldSize = Array.getLength(oldArray);
        Class<?> elementType = oldArray.getClass().getComponentType();
        
        Object newArray = Array.newInstance(elementType, newSize);
        int preserveLength = Math.min(oldSize, newSize);
        if (preserveLength > 0) {
            System.arraycopy(oldArray, 0, newArray, 0, preserveLength);
        }
        try {
            for (int i = preserveLength; i < newSize; i++) {
                Array.set(newArray, i, elementType.newInstance());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return newArray;
    }
    
}
JXPathContext context = JXPathContext.newContext(new Book());
context.setFactory(new BookFactory());
context.createPathAndSetValue("title", "hello jxpath");
context.createPathAndSetValue("authors[1]/gender", 'F');
// Map 对象的 xpath 必须使用 contacts/email 或 contacts/child::email 而不能使用 contacts[@email] 或 contacts/attribute::email
context.createPathAndSetValue("publisher/contacts/child::email", "test@gmial.com");

 

posted on 2015-08-03 14:07  huey2672  阅读(468)  评论(0编辑  收藏  举报