diff --git a/pom.xml b/pom.xml index 9e9d0f8b7..e02f84973 100644 --- a/pom.xml +++ b/pom.xml @@ -21,13 +21,15 @@ under the License. org.apache.commons commons-parent - 10 + 11 4.0.0 commons-jxpath commons-jxpath Commons JXPath - 1.3-SNAPSHOT + + 1.3 A Java-based implementation of XPath 1.0 that, in addition to XML processing, can inspect/modify Java object graphs (the library's explicit purpose) and even mixed Java/XML structures. http://commons.apache.org/jxpath/ @@ -62,7 +64,8 @@ under the License. jxpath - 1.2 + + 1.3 JXPATH 12310480 @@ -98,20 +101,32 @@ under the License. gnu + + org.apache.maven.plugins + maven-compiler-plugin + + 1.5 + 1.5 + + + + + + commons-logging + commons-logging + 1.1.1 + runtime + + + - - commons-logging - commons-logging - 1.1.1 - true - runtime - xerces xercesImpl 2.4.0 + provided true @@ -153,13 +168,6 @@ under the License. 1.7.0 true - - commons-collections - commons-collections - 3.2 - true - runtime - com.mockrunner mockrunner-jdk1.3-j2ee1.3 diff --git a/src/assembly/src.xml b/src/assembly/src.xml index 558c9955a..5e9f37a9f 100644 --- a/src/assembly/src.xml +++ b/src/assembly/src.xml @@ -44,5 +44,8 @@ xdocs + + conf + diff --git a/src/java/org/apache/commons/jxpath/JXPathBasicBeanInfo.java b/src/java/org/apache/commons/jxpath/JXPathBasicBeanInfo.java index 7c0db8906..31eb20c99 100644 --- a/src/java/org/apache/commons/jxpath/JXPathBasicBeanInfo.java +++ b/src/java/org/apache/commons/jxpath/JXPathBasicBeanInfo.java @@ -23,153 +23,165 @@ import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; +import java.util.Map; /** * An implementation of JXPathBeanInfo based on JavaBeans' BeanInfo. Properties * advertised by JXPathBasicBeanInfo are the same as those advertised by * BeanInfo for the corresponding class. * - * @see java.beans.BeanInfo - * @see java.beans.Introspector - * * @author Dmitri Plotnikov * @version $Revision$ $Date$ + * @see java.beans.BeanInfo + * @see java.beans.Introspector */ +@SuppressWarnings({"unchecked", "WeakerAccess"}) public class JXPathBasicBeanInfo implements JXPathBeanInfo { - private static final long serialVersionUID = -3863803443111484155L; - private static final Comparator PROPERTY_DESCRIPTOR_COMPARATOR = new Comparator() { - public int compare(Object left, Object right) { - return ((PropertyDescriptor) left).getName().compareTo( - ((PropertyDescriptor) right).getName()); - } - }; - - private boolean atomic = false; - private Class clazz; - private Class dynamicPropertyHandlerClass; - private transient PropertyDescriptor[] propertyDescriptors; - private transient HashMap propertyDescriptorMap; - - /** - * Create a new JXPathBasicBeanInfo. - * @param clazz bean class - */ - public JXPathBasicBeanInfo(Class clazz) { - this.clazz = clazz; - } + private static final long serialVersionUID = -3863803443111484155L; - /** - * Create a new JXPathBasicBeanInfo. - * @param clazz bean class - * @param atomic whether objects of this class are treated as atomic - * objects which have no properties of their own. - */ - public JXPathBasicBeanInfo(Class clazz, boolean atomic) { - this.clazz = clazz; - this.atomic = atomic; - } + private static final Comparator PROPERTY_DESCRIPTOR_COMPARATOR = + Comparator.comparing(left -> ((PropertyDescriptor) left).getName()); - /** - * Create a new JXPathBasicBeanInfo. - * @param clazz bean class - * @param dynamicPropertyHandlerClass dynamic property handler class - */ - public JXPathBasicBeanInfo(Class clazz, Class dynamicPropertyHandlerClass) { - this.clazz = clazz; - this.atomic = false; - this.dynamicPropertyHandlerClass = dynamicPropertyHandlerClass; - } + private boolean atomic = false; + private Class clazz; + private Class dynamicPropertyHandlerClass; + private transient volatile PropertyDescriptor[] propertyDescriptors; + private transient volatile Map propertyDescriptorMap; - /** - * Returns true if objects of this class are treated as atomic - * objects which have no properties of their own. - * @return boolean - */ - public boolean isAtomic() { - return atomic; - } + /** + * Create a new JXPathBasicBeanInfo. + * + * @param clazz bean class + */ + public JXPathBasicBeanInfo(Class clazz) { + this.clazz = clazz; + this.propertyDescriptors = descriptors(); + } + + /** + * Create a new JXPathBasicBeanInfo. + * + * @param clazz bean class + * @param atomic whether objects of this class are treated as atomic + * objects which have no properties of their own. + */ + public JXPathBasicBeanInfo(Class clazz, boolean atomic) { + this.clazz = clazz; + this.atomic = atomic; + this.propertyDescriptors = descriptors(); + } + + /** + * Create a new JXPathBasicBeanInfo. + * + * @param clazz bean class + * @param dynamicPropertyHandlerClass dynamic property handler class + */ + public JXPathBasicBeanInfo(Class clazz, Class dynamicPropertyHandlerClass) { + this.clazz = clazz; + this.atomic = false; + this.dynamicPropertyHandlerClass = dynamicPropertyHandlerClass; + this.propertyDescriptors = descriptors(); + } + + /** + * Returns true if objects of this class are treated as atomic + * objects which have no properties of their own. + * + * @return boolean + */ + public boolean isAtomic() { + return atomic; + } - /** - * Return true if the corresponding objects have dynamic properties. - * @return boolean - */ - public boolean isDynamic() { - return dynamicPropertyHandlerClass != null; + /** + * Return true if the corresponding objects have dynamic properties. + * + * @return boolean + */ + public boolean isDynamic() { + return dynamicPropertyHandlerClass != null; + } + + public PropertyDescriptor[] getPropertyDescriptors() { + if (this.propertyDescriptors == null) { + this.propertyDescriptors = descriptors(); } + return this.propertyDescriptors; + } - public synchronized PropertyDescriptor[] getPropertyDescriptors() { - if (propertyDescriptors == null) { - if (clazz == Object.class) { - propertyDescriptors = new PropertyDescriptor[0]; - } - else { - try { - BeanInfo bi = null; - if (clazz.isInterface()) { - bi = Introspector.getBeanInfo(clazz); - } - else { - bi = Introspector.getBeanInfo(clazz, Object.class); - } - PropertyDescriptor[] pds = bi.getPropertyDescriptors(); - PropertyDescriptor[] descriptors = new PropertyDescriptor[pds.length]; - System.arraycopy(pds, 0, descriptors, 0, pds.length); - Arrays.sort(descriptors, PROPERTY_DESCRIPTOR_COMPARATOR); - propertyDescriptors = descriptors; - } - catch (IntrospectionException ex) { - ex.printStackTrace(); - } - } - } - if (propertyDescriptors.length == 0) { - return propertyDescriptors; - } - PropertyDescriptor[] result = new PropertyDescriptor[propertyDescriptors.length]; - System.arraycopy(propertyDescriptors, 0, result, 0, propertyDescriptors.length); - return result; + public PropertyDescriptor getPropertyDescriptor(String propertyName) { + if (this.propertyDescriptorMap == null) { + this.propertyDescriptorMap = descriptorsMap(); } + return (PropertyDescriptor) propertyDescriptorMap.get(propertyName); + } - public synchronized PropertyDescriptor getPropertyDescriptor(String propertyName) { - if (propertyDescriptorMap == null) { - propertyDescriptorMap = new HashMap(); - PropertyDescriptor[] pds = getPropertyDescriptors(); - for (int i = 0; i < pds.length; i++) { - propertyDescriptorMap.put(pds[i].getName(), pds[i]); - } + /** + * For a dynamic class, returns the corresponding DynamicPropertyHandler + * class. + * + * @return Class + */ + public Class getDynamicPropertyHandlerClass() { + return dynamicPropertyHandlerClass; + } + + private PropertyDescriptor[] descriptors() { + if (clazz == Object.class) { + return new PropertyDescriptor[0]; + } else { + try { + BeanInfo bi; + if (clazz.isInterface()) { + bi = Introspector.getBeanInfo(clazz); + } else { + bi = Introspector.getBeanInfo(clazz, Object.class); } - return (PropertyDescriptor) propertyDescriptorMap.get(propertyName); + PropertyDescriptor[] pds = bi.getPropertyDescriptors(); + PropertyDescriptor[] descriptors = new PropertyDescriptor[pds.length]; + System.arraycopy(pds, 0, descriptors, 0, pds.length); + Arrays.sort(descriptors, PROPERTY_DESCRIPTOR_COMPARATOR); + return descriptors; + } catch (IntrospectionException ex) { + ex.printStackTrace(); + } } + return new PropertyDescriptor[0]; + } - /** - * For a dynamic class, returns the corresponding DynamicPropertyHandler - * class. - * @return Class - */ - public Class getDynamicPropertyHandlerClass() { - return dynamicPropertyHandlerClass; + private Map descriptorsMap() { + Map propertyDescriptorMap = new HashMap(); + PropertyDescriptor[] pds = getPropertyDescriptors(); + for (PropertyDescriptor pd : pds) { + propertyDescriptorMap.put(pd.getName(), pd); } + return propertyDescriptorMap; + } - public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append("BeanInfo [class = "); - buffer.append(clazz.getName()); - if (isDynamic()) { - buffer.append(", dynamic"); - } - if (isAtomic()) { - buffer.append(", atomic"); - } - buffer.append(", properties = "); - PropertyDescriptor[] jpds = getPropertyDescriptors(); - for (int i = 0; i < jpds.length; i++) { - buffer.append("\n "); - buffer.append(jpds[i].getPropertyType()); - buffer.append(": "); - buffer.append(jpds[i].getName()); - } - buffer.append("]"); - return buffer.toString(); + + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("BeanInfo [class = "); + buffer.append(clazz.getName()); + if (isDynamic()) { + buffer.append(", dynamic"); + } + if (isAtomic()) { + buffer.append(", atomic"); } + buffer.append(", properties = "); + PropertyDescriptor[] jpds = getPropertyDescriptors(); + for (PropertyDescriptor jpd : jpds) { + buffer.append("\n "); + buffer.append(jpd.getPropertyType()); + buffer.append(": "); + buffer.append(jpd.getName()); + } + buffer.append("]"); + return buffer.toString(); + } + + } diff --git a/src/java/org/apache/commons/jxpath/JXPathIntrospector.java b/src/java/org/apache/commons/jxpath/JXPathIntrospector.java index c52ff31ec..6c5f3757c 100644 --- a/src/java/org/apache/commons/jxpath/JXPathIntrospector.java +++ b/src/java/org/apache/commons/jxpath/JXPathIntrospector.java @@ -18,7 +18,7 @@ import java.util.Date; import java.util.Map; -import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; /** * JXPathIntrospector maintains a registry of {@link JXPathBeanInfo @@ -29,8 +29,8 @@ */ public class JXPathIntrospector { - private static HashMap byClass = new HashMap(); - private static HashMap byInterface = new HashMap(); + private static Map byClass = new ConcurrentHashMap(); + private static Map byInterface = new ConcurrentHashMap(); static { registerAtomicClass(Class.class); @@ -163,7 +163,7 @@ private static JXPathBeanInfo findDynamicBeanInfo(Class beanClass) { * @param beanClass for which to look for an info provider * @return JXPathBeanInfo instance or null if none found */ - private static synchronized JXPathBeanInfo findInformant(Class beanClass) { + private static JXPathBeanInfo findInformant(Class beanClass) { String name = beanClass.getName() + "XBeanInfo"; try { return (JXPathBeanInfo) instantiate(beanClass, name); diff --git a/src/java/org/apache/commons/jxpath/ri/compiler/Path.java b/src/java/org/apache/commons/jxpath/ri/compiler/Path.java index 221140296..2aa476a6d 100644 --- a/src/java/org/apache/commons/jxpath/ri/compiler/Path.java +++ b/src/java/org/apache/commons/jxpath/ri/compiler/Path.java @@ -196,7 +196,7 @@ protected Pointer getSingleNodePointerForSteps(EvalContext context) { * @param context evaluation context * @return Pointer */ - private Pointer searchForPath(EvalContext context) { + protected Pointer searchForPath(EvalContext context) { EvalContext ctx = buildContextChain(context, steps.length, true); Pointer pointer = ctx.getSingleNodePointer(); @@ -245,7 +245,7 @@ protected EvalContext evalSteps(EvalContext context) { * @param createInitialContext whether to create the initial context * @return created context */ - private EvalContext buildContextChain( + protected EvalContext buildContextChain( EvalContext context, int stepCount, boolean createInitialContext) { diff --git a/src/java/org/apache/commons/jxpath/ri/model/beans/BeanPropertyPointer.java b/src/java/org/apache/commons/jxpath/ri/model/beans/BeanPropertyPointer.java index caf9e4f19..cf1fa961c 100644 --- a/src/java/org/apache/commons/jxpath/ri/model/beans/BeanPropertyPointer.java +++ b/src/java/org/apache/commons/jxpath/ri/model/beans/BeanPropertyPointer.java @@ -303,7 +303,7 @@ private PropertyDescriptor getPropertyDescriptor() { * Get all PropertyDescriptors. * @return PropertyDescriptor[] */ - protected synchronized PropertyDescriptor[] getPropertyDescriptors() { + protected PropertyDescriptor[] getPropertyDescriptors() { if (propertyDescriptors == null) { propertyDescriptors = beanInfo.getPropertyDescriptors(); } diff --git a/src/java/org/apache/commons/jxpath/util/ValueUtils.java b/src/java/org/apache/commons/jxpath/util/ValueUtils.java index 7b288a650..0d489b0f0 100644 --- a/src/java/org/apache/commons/jxpath/util/ValueUtils.java +++ b/src/java/org/apache/commons/jxpath/util/ValueUtils.java @@ -41,621 +41,621 @@ * @version $Revision$ $Date$ */ public class ValueUtils { - private static Map dynamicPropertyHandlerMap = new HashMap(); - private static final int UNKNOWN_LENGTH_MAX_COUNT = 16000; - - /** - * Returns true if the object is an array or a Collection. - * @param value to test - * @return boolean - */ - public static boolean isCollection(Object value) { - value = getValue(value); - if (value == null) { - return false; - } - if (value.getClass().isArray()) { - return true; - } - if (value instanceof Collection) { - return true; - } - return false; - } - - /** - * Returns 1 if the type is a collection, - * -1 if it is definitely not - * and 0 if it may be a collection in some cases. - * @param clazz to test - * @return int - */ - public static int getCollectionHint(Class clazz) { - if (clazz.isArray()) { - return 1; - } + private static Map dynamicPropertyHandlerMap = new HashMap(); + private static final int UNKNOWN_LENGTH_MAX_COUNT = 16000; + + /** + * Returns true if the object is an array or a Collection. + * @param value to test + * @return boolean + */ + public static boolean isCollection(Object value) { + value = getValue(value); + if (value == null) { + return false; + } + if (value.getClass().isArray()) { + return true; + } + if (value instanceof Collection) { + return true; + } + return false; + } + + /** + * Returns 1 if the type is a collection, + * -1 if it is definitely not + * and 0 if it may be a collection in some cases. + * @param clazz to test + * @return int + */ + public static int getCollectionHint(Class clazz) { + if (clazz.isArray()) { + return 1; + } - if (Collection.class.isAssignableFrom(clazz)) { - return 1; - } + if (Collection.class.isAssignableFrom(clazz)) { + return 1; + } - if (clazz.isPrimitive()) { - return -1; - } + if (clazz.isPrimitive()) { + return -1; + } - if (clazz.isInterface()) { - return 0; - } + if (clazz.isInterface()) { + return 0; + } - if (Modifier.isFinal(clazz.getModifiers())) { - return -1; - } + if (Modifier.isFinal(clazz.getModifiers())) { + return -1; + } - return 0; - } - - /** - * If there is a regular non-indexed read method for this property, - * uses this method to obtain the collection and then returns its - * length. - * Otherwise, attempts to guess the length of the collection by - * calling the indexed get method repeatedly. The method is supposed - * to throw an exception if the index is out of bounds. - * @param object collection - * @param pd IndexedPropertyDescriptor - * @return int - */ - public static int getIndexedPropertyLength(Object object, - IndexedPropertyDescriptor pd) { - if (pd.getReadMethod() != null) { - return getLength(getValue(object, pd)); - } + return 0; + } + + /** + * If there is a regular non-indexed read method for this property, + * uses this method to obtain the collection and then returns its + * length. + * Otherwise, attempts to guess the length of the collection by + * calling the indexed get method repeatedly. The method is supposed + * to throw an exception if the index is out of bounds. + * @param object collection + * @param pd IndexedPropertyDescriptor + * @return int + */ + public static int getIndexedPropertyLength(Object object, + IndexedPropertyDescriptor pd) { + if (pd.getReadMethod() != null) { + return getLength(getValue(object, pd)); + } - Method readMethod = pd.getIndexedReadMethod(); - if (readMethod == null) { - throw new JXPathException( - "No indexed read method for property " + pd.getName()); - } + Method readMethod = pd.getIndexedReadMethod(); + if (readMethod == null) { + throw new JXPathException( + "No indexed read method for property " + pd.getName()); + } - for (int i = 0; i < UNKNOWN_LENGTH_MAX_COUNT; i++) { - try { - readMethod.invoke(object, new Object[] { new Integer(i)}); - } - catch (Throwable t) { - return i; - } - } + for (int i = 0; i < UNKNOWN_LENGTH_MAX_COUNT; i++) { + try { + readMethod.invoke(object, i); + } + catch (Throwable t) { + return i; + } + } - throw new JXPathException( - "Cannot determine the length of the indexed property " - + pd.getName()); - } - - /** - * Returns the length of the supplied collection. If the supplied object - * is not a collection, returns 1. If collection is null, returns 0. - * @param collection to check - * @return int - */ - public static int getLength(Object collection) { - if (collection == null) { - return 0; - } - collection = getValue(collection); - if (collection.getClass().isArray()) { - return Array.getLength(collection); - } - if (collection instanceof Collection) { - return ((Collection) collection).size(); - } - return 1; - } - - /** - * Returns an iterator for the supplied collection. If the argument - * is null, returns an empty iterator. If the argument is not - * a collection, returns an iterator that produces just that one object. - * @param collection to iterate - * @return Iterator - */ - public static Iterator iterate(Object collection) { - if (collection == null) { - return Collections.EMPTY_LIST.iterator(); - } - if (collection.getClass().isArray()) { - int length = Array.getLength(collection); - if (length == 0) { - return Collections.EMPTY_LIST.iterator(); - } - ArrayList list = new ArrayList(); - for (int i = 0; i < length; i++) { - list.add(Array.get(collection, i)); - } - return list.iterator(); - } - if (collection instanceof Collection) { - return ((Collection) collection).iterator(); - } - return Collections.singletonList(collection).iterator(); - } - - /** - * Grows the collection if necessary to the specified size. Returns - * the new, expanded collection. - * @param collection to expand - * @param size desired size - * @return collection or array - */ - public static Object expandCollection(Object collection, int size) { - if (collection == null) { - return null; - } - if (size < getLength(collection)) { - throw new JXPathException("adjustment of " + collection - + " to size " + size + " is not an expansion"); + throw new JXPathException( + "Cannot determine the length of the indexed property " + + pd.getName()); + } + + /** + * Returns the length of the supplied collection. If the supplied object + * is not a collection, returns 1. If collection is null, returns 0. + * @param collection to check + * @return int + */ + public static int getLength(Object collection) { + if (collection == null) { + return 0; + } + collection = getValue(collection); + if (collection.getClass().isArray()) { + return Array.getLength(collection); + } + if (collection instanceof Collection) { + return ((Collection) collection).size(); + } + return 1; + } + + /** + * Returns an iterator for the supplied collection. If the argument + * is null, returns an empty iterator. If the argument is not + * a collection, returns an iterator that produces just that one object. + * @param collection to iterate + * @return Iterator + */ + public static Iterator iterate(Object collection) { + if (collection == null) { + return Collections.EMPTY_LIST.iterator(); + } + if (collection.getClass().isArray()) { + int length = Array.getLength(collection); + if (length == 0) { + return Collections.EMPTY_LIST.iterator(); + } + ArrayList list = new ArrayList(); + for (int i = 0; i < length; i++) { + list.add(Array.get(collection, i)); + } + return list.iterator(); + } + if (collection instanceof Collection) { + return ((Collection) collection).iterator(); + } + return Collections.singletonList(collection).iterator(); + } + + /** + * Grows the collection if necessary to the specified size. Returns + * the new, expanded collection. + * @param collection to expand + * @param size desired size + * @return collection or array + */ + public static Object expandCollection(Object collection, int size) { + if (collection == null) { + return null; + } + if (size < getLength(collection)) { + throw new JXPathException("adjustment of " + collection + + " to size " + size + " is not an expansion"); + } + if (collection.getClass().isArray()) { + Object bigger = + Array.newInstance( + collection.getClass().getComponentType(), + size); + System.arraycopy( + collection, + 0, + bigger, + 0, + Array.getLength(collection)); + return bigger; + } + if (collection instanceof Collection) { + while (((Collection) collection).size() < size) { + ((Collection) collection).add(null); + } + return collection; + } + throw new JXPathException( + "Cannot turn " + + collection.getClass().getName() + + " into a collection of size " + + size); + } + + /** + * Remove the index'th element from the supplied collection. + * @param collection to edit + * @param index int + * @return the resulting collection + */ + public static Object remove(Object collection, int index) { + collection = getValue(collection); + if (collection == null) { + return null; + } + if (index >= getLength(collection)) { + throw new JXPathException("No such element at index " + index); + } + if (collection.getClass().isArray()) { + int length = Array.getLength(collection); + Object smaller = + Array.newInstance( + collection.getClass().getComponentType(), + length - 1); + if (index > 0) { + System.arraycopy(collection, 0, smaller, 0, index); + } + if (index < length - 1) { + System.arraycopy( + collection, + index + 1, + smaller, + index, + length - index - 1); + } + return smaller; + } + if (collection instanceof List) { + int size = ((List) collection).size(); + if (index < size) { + ((List) collection).remove(index); + } + return collection; + } + if (collection instanceof Collection) { + Iterator it = ((Collection) collection).iterator(); + for (int i = 0; i < index; i++) { + if (!it.hasNext()) { + break; + } + it.next(); + } + if (it.hasNext()) { + it.next(); + it.remove(); + } + return collection; + } + throw new JXPathException( + "Cannot remove " + + collection.getClass().getName() + + "[" + + index + + "]"); + } + + /** + * Returns the index'th element of the supplied collection. + * @param collection to read + * @param index int + * @return collection[index] + */ + public static Object getValue(Object collection, int index) { + collection = getValue(collection); + Object value = collection; + if (collection != null) { + if (collection.getClass().isArray()) { + if (index < 0 || index >= Array.getLength(collection)) { + return null; + } + value = Array.get(collection, index); + } + else if (collection instanceof List) { + if (index < 0 || index >= ((List) collection).size()) { + return null; + } + value = ((List) collection).get(index); + } + else if (collection instanceof Collection) { + int i = 0; + Iterator it = ((Collection) collection).iterator(); + for (; i < index; i++) { + it.next(); + } + if (it.hasNext()) { + value = it.next(); } - if (collection.getClass().isArray()) { - Object bigger = - Array.newInstance( - collection.getClass().getComponentType(), - size); - System.arraycopy( - collection, - 0, - bigger, - 0, - Array.getLength(collection)); - return bigger; + else { + value = null; } - if (collection instanceof Collection) { - while (((Collection) collection).size() < size) { - ((Collection) collection).add(null); - } - return collection; + } + } + return value; + } + + /** + * Modifies the index'th element of the supplied collection. + * Converts the value to the required type if necessary. + * @param collection to edit + * @param index to replace + * @param value new value + */ + public static void setValue(Object collection, int index, Object value) { + collection = getValue(collection); + if (collection != null) { + if (collection.getClass().isArray()) { + Array.set( + collection, + index, + convert(value, collection.getClass().getComponentType())); + } + else if (collection instanceof List) { + ((List) collection).set(index, value); + } + else if (collection instanceof Collection) { + throw new UnsupportedOperationException( + "Cannot set value of an element of a " + + collection.getClass().getName()); + } + } + } + + /** + * Returns the value of the bean's property represented by + * the supplied property descriptor. + * @param bean to read + * @param propertyDescriptor indicating what to read + * @return Object value + */ + public static Object getValue(Object bean, + PropertyDescriptor propertyDescriptor) { + Object value; + try { + Method method = + getAccessibleMethod(propertyDescriptor.getReadMethod()); + if (method == null) { + throw new JXPathException("No read method"); + } + value = method.invoke(bean, new Object[0]); + } + catch (Exception ex) { + throw new JXPathException( + "Cannot access property: " + + (bean == null ? "null" : bean.getClass().getName()) + + "." + + propertyDescriptor.getName(), + ex); + } + return value; + } + + /** + * Modifies the value of the bean's property represented by + * the supplied property descriptor. + * @param bean to read + * @param propertyDescriptor indicating what to read + * @param value to set + */ + public static void setValue(Object bean, + PropertyDescriptor propertyDescriptor, Object value) { + try { + Method method = + getAccessibleMethod(propertyDescriptor.getWriteMethod()); + if (method == null) { + throw new JXPathException("No write method"); + } + value = convert(value, propertyDescriptor.getPropertyType()); + method.invoke(bean, new Object[] { value }); + } + catch (Exception ex) { + throw new JXPathException( + "Cannot modify property: " + + (bean == null ? "null" : bean.getClass().getName()) + + "." + + propertyDescriptor.getName(), + ex); + } + } + + /** + * Convert value to type. + * @param value Object + * @param type destination + * @return conversion result + */ + private static Object convert(Object value, Class type) { + try { + return TypeUtils.convert(value, type); + } + catch (Exception ex) { + throw new JXPathException( + "Cannot convert value of class " + + (value == null ? "null" : value.getClass().getName()) + + " to type " + + type, + ex); + } + } + + /** + * Returns the index'th element of the bean's property represented by + * the supplied property descriptor. + * @param bean to read + * @param propertyDescriptor indicating what to read + * @param index int + * @return Object + */ + public static Object getValue(Object bean, + PropertyDescriptor propertyDescriptor, int index) { + if (propertyDescriptor instanceof IndexedPropertyDescriptor) { + try { + IndexedPropertyDescriptor ipd = + (IndexedPropertyDescriptor) propertyDescriptor; + Method method = ipd.getIndexedReadMethod(); + if (method != null) { + return method.invoke( + bean, + new Object[] { new Integer(index)}); + } + } + catch (InvocationTargetException ex) { + Throwable t = ex.getTargetException(); + if (t instanceof IndexOutOfBoundsException) { + return null; } throw new JXPathException( - "Cannot turn " - + collection.getClass().getName() - + " into a collection of size " - + size); - } - - /** - * Remove the index'th element from the supplied collection. - * @param collection to edit - * @param index int - * @return the resulting collection - */ - public static Object remove(Object collection, int index) { - collection = getValue(collection); - if (collection == null) { - return null; - } - if (index >= getLength(collection)) { - throw new JXPathException("No such element at index " + index); - } - if (collection.getClass().isArray()) { - int length = Array.getLength(collection); - Object smaller = - Array.newInstance( - collection.getClass().getComponentType(), - length - 1); - if (index > 0) { - System.arraycopy(collection, 0, smaller, 0, index); - } - if (index < length - 1) { - System.arraycopy( - collection, - index + 1, - smaller, - index, - length - index - 1); - } - return smaller; - } - if (collection instanceof List) { - int size = ((List) collection).size(); - if (index < size) { - ((List) collection).remove(index); - } - return collection; - } - if (collection instanceof Collection) { - Iterator it = ((Collection) collection).iterator(); - for (int i = 0; i < index; i++) { - if (!it.hasNext()) { - break; - } - it.next(); - } - if (it.hasNext()) { - it.next(); - it.remove(); - } - return collection; - } + "Cannot access property: " + propertyDescriptor.getName(), + t); + } + catch (Throwable ex) { throw new JXPathException( - "Cannot remove " - + collection.getClass().getName() - + "[" - + index - + "]"); - } - - /** - * Returns the index'th element of the supplied collection. - * @param collection to read - * @param index int - * @return collection[index] - */ - public static Object getValue(Object collection, int index) { - collection = getValue(collection); - Object value = collection; - if (collection != null) { - if (collection.getClass().isArray()) { - if (index < 0 || index >= Array.getLength(collection)) { - return null; - } - value = Array.get(collection, index); - } - else if (collection instanceof List) { - if (index < 0 || index >= ((List) collection).size()) { - return null; - } - value = ((List) collection).get(index); - } - else if (collection instanceof Collection) { - int i = 0; - Iterator it = ((Collection) collection).iterator(); - for (; i < index; i++) { - it.next(); - } - if (it.hasNext()) { - value = it.next(); - } - else { - value = null; - } - } - } - return value; - } - - /** - * Modifies the index'th element of the supplied collection. - * Converts the value to the required type if necessary. - * @param collection to edit - * @param index to replace - * @param value new value - */ - public static void setValue(Object collection, int index, Object value) { - collection = getValue(collection); - if (collection != null) { - if (collection.getClass().isArray()) { - Array.set( - collection, - index, - convert(value, collection.getClass().getComponentType())); - } - else if (collection instanceof List) { - ((List) collection).set(index, value); - } - else if (collection instanceof Collection) { - throw new UnsupportedOperationException( - "Cannot set value of an element of a " - + collection.getClass().getName()); - } - } + "Cannot access property: " + propertyDescriptor.getName(), + ex); + } } - /** - * Returns the value of the bean's property represented by - * the supplied property descriptor. - * @param bean to read - * @param propertyDescriptor indicating what to read - * @return Object value - */ - public static Object getValue(Object bean, - PropertyDescriptor propertyDescriptor) { - Object value; - try { - Method method = - getAccessibleMethod(propertyDescriptor.getReadMethod()); - if (method == null) { - throw new JXPathException("No read method"); - } - value = method.invoke(bean, new Object[0]); - } - catch (Exception ex) { - throw new JXPathException( - "Cannot access property: " - + (bean == null ? "null" : bean.getClass().getName()) - + "." - + propertyDescriptor.getName(), - ex); - } - return value; - } - - /** - * Modifies the value of the bean's property represented by - * the supplied property descriptor. - * @param bean to read - * @param propertyDescriptor indicating what to read - * @param value to set - */ - public static void setValue(Object bean, - PropertyDescriptor propertyDescriptor, Object value) { - try { - Method method = - getAccessibleMethod(propertyDescriptor.getWriteMethod()); - if (method == null) { - throw new JXPathException("No write method"); - } - value = convert(value, propertyDescriptor.getPropertyType()); - method.invoke(bean, new Object[] { value }); - } - catch (Exception ex) { - throw new JXPathException( - "Cannot modify property: " - + (bean == null ? "null" : bean.getClass().getName()) - + "." - + propertyDescriptor.getName(), - ex); - } + // We will fall through if there is no indexed read + + return getValue(getValue(bean, propertyDescriptor), index); + } + + /** + * Modifies the index'th element of the bean's property represented by + * the supplied property descriptor. Converts the value to the required + * type if necessary. + * @param bean to edit + * @param propertyDescriptor indicating what to set + * @param index int + * @param value to set + */ + public static void setValue(Object bean, + PropertyDescriptor propertyDescriptor, int index, Object value) { + if (propertyDescriptor instanceof IndexedPropertyDescriptor) { + try { + IndexedPropertyDescriptor ipd = + (IndexedPropertyDescriptor) propertyDescriptor; + Method method = ipd.getIndexedWriteMethod(); + if (method != null) { + method.invoke( + bean, + new Object[] { + new Integer(index), + convert(value, ipd.getIndexedPropertyType())}); + return; + } + } + catch (Exception ex) { + throw new RuntimeException( + "Cannot access property: " + + propertyDescriptor.getName() + + ", " + + ex.getMessage()); + } } - - /** - * Convert value to type. - * @param value Object - * @param type destination - * @return conversion result - */ - private static Object convert(Object value, Class type) { - try { - return TypeUtils.convert(value, type); - } - catch (Exception ex) { - throw new JXPathException( - "Cannot convert value of class " - + (value == null ? "null" : value.getClass().getName()) - + " to type " - + type, - ex); - } + // We will fall through if there is no indexed read + Object collection = getValue(bean, propertyDescriptor); + if (isCollection(collection)) { + setValue(collection, index, value); } - - /** - * Returns the index'th element of the bean's property represented by - * the supplied property descriptor. - * @param bean to read - * @param propertyDescriptor indicating what to read - * @param index int - * @return Object - */ - public static Object getValue(Object bean, - PropertyDescriptor propertyDescriptor, int index) { - if (propertyDescriptor instanceof IndexedPropertyDescriptor) { - try { - IndexedPropertyDescriptor ipd = - (IndexedPropertyDescriptor) propertyDescriptor; - Method method = ipd.getIndexedReadMethod(); - if (method != null) { - return method.invoke( - bean, - new Object[] { new Integer(index)}); - } - } - catch (InvocationTargetException ex) { - Throwable t = ex.getTargetException(); - if (t instanceof IndexOutOfBoundsException) { - return null; - } - throw new JXPathException( - "Cannot access property: " + propertyDescriptor.getName(), - t); - } - catch (Throwable ex) { - throw new JXPathException( - "Cannot access property: " + propertyDescriptor.getName(), - ex); - } - } - - // We will fall through if there is no indexed read - - return getValue(getValue(bean, propertyDescriptor), index); - } - - /** - * Modifies the index'th element of the bean's property represented by - * the supplied property descriptor. Converts the value to the required - * type if necessary. - * @param bean to edit - * @param propertyDescriptor indicating what to set - * @param index int - * @param value to set - */ - public static void setValue(Object bean, - PropertyDescriptor propertyDescriptor, int index, Object value) { - if (propertyDescriptor instanceof IndexedPropertyDescriptor) { - try { - IndexedPropertyDescriptor ipd = - (IndexedPropertyDescriptor) propertyDescriptor; - Method method = ipd.getIndexedWriteMethod(); - if (method != null) { - method.invoke( - bean, - new Object[] { - new Integer(index), - convert(value, ipd.getIndexedPropertyType())}); - return; - } - } - catch (Exception ex) { - throw new RuntimeException( - "Cannot access property: " - + propertyDescriptor.getName() - + ", " - + ex.getMessage()); - } - } - // We will fall through if there is no indexed read - Object collection = getValue(bean, propertyDescriptor); - if (isCollection(collection)) { - setValue(collection, index, value); - } - else if (index == 0) { - setValue(bean, propertyDescriptor, value); - } - else { - throw new RuntimeException( - "Not a collection: " + propertyDescriptor.getName()); - } + else if (index == 0) { + setValue(bean, propertyDescriptor, value); + } + else { + throw new RuntimeException( + "Not a collection: " + propertyDescriptor.getName()); + } + } + + /** + * If the parameter is a container, opens the container and + * return the contents. The method is recursive. + * @param object to read + * @return Object + */ + public static Object getValue(Object object) { + while (object instanceof Container) { + object = ((Container) object).getValue(); + } + return object; + } + + /** + * Returns a shared instance of the dynamic property handler class + * returned by getDynamicPropertyHandlerClass(). + * @param clazz to handle + * @return DynamicPropertyHandler + */ + public static DynamicPropertyHandler getDynamicPropertyHandler(Class clazz) { + DynamicPropertyHandler handler = + (DynamicPropertyHandler) dynamicPropertyHandlerMap.get(clazz); + if (handler == null) { + try { + handler = (DynamicPropertyHandler) clazz.newInstance(); + } + catch (Exception ex) { + throw new JXPathException( + "Cannot allocate dynamic property handler of class " + + clazz.getName(), + ex); + } + dynamicPropertyHandlerMap.put(clazz, handler); + } + return handler; + } + + // -------------------------------------------------------- Private Methods + // + // The rest of the code in this file was copied FROM + // org.apache.commons.beanutils.PropertyUtil. We don't want to introduce + // a dependency on BeanUtils yet - DP. + // + + /** + * Return an accessible method (that is, one that can be invoked via + * reflection) that implements the specified Method. If no such method + * can be found, return null. + * + * @param method The method that we wish to call + * @return Method + */ + public static Method getAccessibleMethod(Method method) { + + // Make sure we have a method to check + if (method == null) { + return (null); } - /** - * If the parameter is a container, opens the container and - * return the contents. The method is recursive. - * @param object to read - * @return Object - */ - public static Object getValue(Object object) { - while (object instanceof Container) { - object = ((Container) object).getValue(); - } - return object; - } - - /** - * Returns a shared instance of the dynamic property handler class - * returned by getDynamicPropertyHandlerClass(). - * @param clazz to handle - * @return DynamicPropertyHandler - */ - public static DynamicPropertyHandler getDynamicPropertyHandler(Class clazz) { - DynamicPropertyHandler handler = - (DynamicPropertyHandler) dynamicPropertyHandlerMap.get(clazz); - if (handler == null) { - try { - handler = (DynamicPropertyHandler) clazz.newInstance(); - } - catch (Exception ex) { - throw new JXPathException( - "Cannot allocate dynamic property handler of class " - + clazz.getName(), - ex); - } - dynamicPropertyHandlerMap.put(clazz, handler); - } - return handler; - } - - // -------------------------------------------------------- Private Methods - // - // The rest of the code in this file was copied FROM - // org.apache.commons.beanutils.PropertyUtil. We don't want to introduce - // a dependency on BeanUtils yet - DP. - // - - /** - * Return an accessible method (that is, one that can be invoked via - * reflection) that implements the specified Method. If no such method - * can be found, return null. - * - * @param method The method that we wish to call - * @return Method - */ - public static Method getAccessibleMethod(Method method) { - - // Make sure we have a method to check - if (method == null) { - return (null); - } - - // If the requested method is not public we cannot call it - if (!Modifier.isPublic(method.getModifiers())) { - return (null); - } + // If the requested method is not public we cannot call it + if (!Modifier.isPublic(method.getModifiers())) { + return (null); + } - // If the declaring class is public, we are done - Class clazz = method.getDeclaringClass(); - if (Modifier.isPublic(clazz.getModifiers())) { - return (method); - } + // If the declaring class is public, we are done + Class clazz = method.getDeclaringClass(); + if (Modifier.isPublic(clazz.getModifiers())) { + return (method); + } - String name = method.getName(); - Class[] parameterTypes = method.getParameterTypes(); - while (clazz != null) { - // Check the implemented interfaces and subinterfaces - Method aMethod = getAccessibleMethodFromInterfaceNest(clazz, - name, parameterTypes); - if (aMethod != null) { - return aMethod; - } - - clazz = clazz.getSuperclass(); - if (clazz != null && Modifier.isPublic(clazz.getModifiers())) { - try { - return clazz.getDeclaredMethod(name, parameterTypes); - } - catch (NoSuchMethodException e) { //NOPMD - //ignore - } - } + String name = method.getName(); + Class[] parameterTypes = method.getParameterTypes(); + while (clazz != null) { + // Check the implemented interfaces and subinterfaces + Method aMethod = getAccessibleMethodFromInterfaceNest(clazz, + name, parameterTypes); + if (aMethod != null) { + return aMethod; + } + + clazz = clazz.getSuperclass(); + if (clazz != null && Modifier.isPublic(clazz.getModifiers())) { + try { + return clazz.getDeclaredMethod(name, parameterTypes); } - return null; - } - - /** - * Return an accessible method (that is, one that can be invoked via - * reflection) that implements the specified method, by scanning through - * all implemented interfaces and subinterfaces. If no such Method - * can be found, return null. - * - * @param clazz Parent class for the interfaces to be checked - * @param methodName Method name of the method we wish to call - * @param parameterTypes The parameter type signatures - * @return Method - */ - private static Method getAccessibleMethodFromInterfaceNest(Class clazz, - String methodName, Class[] parameterTypes) { - - Method method = null; - - // Check the implemented interfaces of the parent class - Class[] interfaces = clazz.getInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - - // Is this interface public? - if (!Modifier.isPublic(interfaces[i].getModifiers())) { - continue; - } - - // Does the method exist on this interface? - try { - method = - interfaces[i].getDeclaredMethod(methodName, parameterTypes); - } - catch (NoSuchMethodException e) { //NOPMD - //ignore - } - if (method != null) { - break; - } - - // Recursively check our parent interfaces - method = - getAccessibleMethodFromInterfaceNest( - interfaces[i], - methodName, - parameterTypes); - if (method != null) { - break; - } + catch (NoSuchMethodException e) { //NOPMD + //ignore } - - // Return whatever we have found - return (method); + } + } + return null; + } + + /** + * Return an accessible method (that is, one that can be invoked via + * reflection) that implements the specified method, by scanning through + * all implemented interfaces and subinterfaces. If no such Method + * can be found, return null. + * + * @param clazz Parent class for the interfaces to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return Method + */ + private static Method getAccessibleMethodFromInterfaceNest(Class clazz, + String methodName, Class[] parameterTypes) { + + Method method = null; + + // Check the implemented interfaces of the parent class + Class[] interfaces = clazz.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + + // Is this interface public? + if (!Modifier.isPublic(interfaces[i].getModifiers())) { + continue; + } + + // Does the method exist on this interface? + try { + method = + interfaces[i].getDeclaredMethod(methodName, parameterTypes); + } + catch (NoSuchMethodException e) { //NOPMD + //ignore + } + if (method != null) { + break; + } + + // Recursively check our parent interfaces + method = + getAccessibleMethodFromInterfaceNest( + interfaces[i], + methodName, + parameterTypes); + if (method != null) { + break; + } } + + // Return whatever we have found + return (method); + } } diff --git a/xdocs/download_jxpath.xml b/xdocs/download_jxpath.xml index 599536b82..82a25b5d0 100644 --- a/xdocs/download_jxpath.xml +++ b/xdocs/download_jxpath.xml @@ -102,17 +102,17 @@ limitations under the License.