001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.jxpath; 018 019import java.beans.BeanInfo; 020import java.beans.IntrospectionException; 021import java.beans.Introspector; 022import java.beans.PropertyDescriptor; 023import java.util.Arrays; 024import java.util.Comparator; 025import java.util.HashMap; 026 027/** 028 * An implementation of JXPathBeanInfo based on JavaBeans' BeanInfo. Properties 029 * advertised by JXPathBasicBeanInfo are the same as those advertised by 030 * BeanInfo for the corresponding class. 031 * 032 * @see java.beans.BeanInfo 033 * @see java.beans.Introspector 034 * 035 * @author Dmitri Plotnikov 036 * @version $Revision: 1190145 $ $Date: 2011-10-28 05:36:24 +0200 (Fr, 28 Okt 2011) $ 037 */ 038public class JXPathBasicBeanInfo implements JXPathBeanInfo { 039 private static final long serialVersionUID = -3863803443111484155L; 040 041 private static final Comparator PROPERTY_DESCRIPTOR_COMPARATOR = new Comparator() { 042 public int compare(Object left, Object right) { 043 return ((PropertyDescriptor) left).getName().compareTo( 044 ((PropertyDescriptor) right).getName()); 045 } 046 }; 047 048 private boolean atomic = false; 049 private Class clazz; 050 private Class dynamicPropertyHandlerClass; 051 private transient PropertyDescriptor[] propertyDescriptors; 052 private transient HashMap propertyDescriptorMap; 053 054 /** 055 * Create a new JXPathBasicBeanInfo. 056 * @param clazz bean class 057 */ 058 public JXPathBasicBeanInfo(Class clazz) { 059 this.clazz = clazz; 060 } 061 062 /** 063 * Create a new JXPathBasicBeanInfo. 064 * @param clazz bean class 065 * @param atomic whether objects of this class are treated as atomic 066 * objects which have no properties of their own. 067 */ 068 public JXPathBasicBeanInfo(Class clazz, boolean atomic) { 069 this.clazz = clazz; 070 this.atomic = atomic; 071 } 072 073 /** 074 * Create a new JXPathBasicBeanInfo. 075 * @param clazz bean class 076 * @param dynamicPropertyHandlerClass dynamic property handler class 077 */ 078 public JXPathBasicBeanInfo(Class clazz, Class dynamicPropertyHandlerClass) { 079 this.clazz = clazz; 080 this.atomic = false; 081 this.dynamicPropertyHandlerClass = dynamicPropertyHandlerClass; 082 } 083 084 /** 085 * Returns true if objects of this class are treated as atomic 086 * objects which have no properties of their own. 087 * @return boolean 088 */ 089 public boolean isAtomic() { 090 return atomic; 091 } 092 093 /** 094 * Return true if the corresponding objects have dynamic properties. 095 * @return boolean 096 */ 097 public boolean isDynamic() { 098 return dynamicPropertyHandlerClass != null; 099 } 100 101 public synchronized PropertyDescriptor[] getPropertyDescriptors() { 102 if (propertyDescriptors == null) { 103 if (clazz == Object.class) { 104 propertyDescriptors = new PropertyDescriptor[0]; 105 } 106 else { 107 try { 108 BeanInfo bi = null; 109 if (clazz.isInterface()) { 110 bi = Introspector.getBeanInfo(clazz); 111 } 112 else { 113 bi = Introspector.getBeanInfo(clazz, Object.class); 114 } 115 PropertyDescriptor[] pds = bi.getPropertyDescriptors(); 116 PropertyDescriptor[] descriptors = new PropertyDescriptor[pds.length]; 117 System.arraycopy(pds, 0, descriptors, 0, pds.length); 118 Arrays.sort(descriptors, PROPERTY_DESCRIPTOR_COMPARATOR); 119 propertyDescriptors = descriptors; 120 } 121 catch (IntrospectionException ex) { 122 ex.printStackTrace(); 123 return new PropertyDescriptor[0]; 124 } 125 } 126 } 127 if (propertyDescriptors.length == 0) { 128 return propertyDescriptors; 129 } 130 PropertyDescriptor[] result = new PropertyDescriptor[propertyDescriptors.length]; 131 System.arraycopy(propertyDescriptors, 0, result, 0, propertyDescriptors.length); 132 return result; 133 } 134 135 public synchronized PropertyDescriptor getPropertyDescriptor(String propertyName) { 136 if (propertyDescriptorMap == null) { 137 propertyDescriptorMap = new HashMap(); 138 PropertyDescriptor[] pds = getPropertyDescriptors(); 139 for (int i = 0; i < pds.length; i++) { 140 propertyDescriptorMap.put(pds[i].getName(), pds[i]); 141 } 142 } 143 return (PropertyDescriptor) propertyDescriptorMap.get(propertyName); 144 } 145 146 /** 147 * For a dynamic class, returns the corresponding DynamicPropertyHandler 148 * class. 149 * @return Class 150 */ 151 public Class getDynamicPropertyHandlerClass() { 152 return dynamicPropertyHandlerClass; 153 } 154 155 public String toString() { 156 StringBuffer buffer = new StringBuffer(); 157 buffer.append("BeanInfo [class = "); 158 buffer.append(clazz.getName()); 159 if (isDynamic()) { 160 buffer.append(", dynamic"); 161 } 162 if (isAtomic()) { 163 buffer.append(", atomic"); 164 } 165 buffer.append(", properties = "); 166 PropertyDescriptor[] jpds = getPropertyDescriptors(); 167 for (int i = 0; i < jpds.length; i++) { 168 buffer.append("\n "); 169 buffer.append(jpds[i].getPropertyType()); 170 buffer.append(": "); 171 buffer.append(jpds[i].getName()); 172 } 173 buffer.append("]"); 174 return buffer.toString(); 175 } 176}