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 */
017 package org.apache.commons.jxpath;
018
019 import java.beans.BeanInfo;
020 import java.beans.IntrospectionException;
021 import java.beans.Introspector;
022 import java.beans.PropertyDescriptor;
023 import java.util.Arrays;
024 import java.util.Comparator;
025 import 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: 668329 $ $Date: 2008-06-16 16:59:48 -0500 (Mon, 16 Jun 2008) $
037 */
038 public 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 }
124 }
125 }
126 if (propertyDescriptors.length == 0) {
127 return propertyDescriptors;
128 }
129 PropertyDescriptor[] result = new PropertyDescriptor[propertyDescriptors.length];
130 System.arraycopy(propertyDescriptors, 0, result, 0, propertyDescriptors.length);
131 return result;
132 }
133
134 public synchronized PropertyDescriptor getPropertyDescriptor(String propertyName) {
135 if (propertyDescriptorMap == null) {
136 propertyDescriptorMap = new HashMap();
137 PropertyDescriptor[] pds = getPropertyDescriptors();
138 for (int i = 0; i < pds.length; i++) {
139 propertyDescriptorMap.put(pds[i].getName(), pds[i]);
140 }
141 }
142 return (PropertyDescriptor) propertyDescriptorMap.get(propertyName);
143 }
144
145 /**
146 * For a dynamic class, returns the corresponding DynamicPropertyHandler
147 * class.
148 * @return Class
149 */
150 public Class getDynamicPropertyHandlerClass() {
151 return dynamicPropertyHandlerClass;
152 }
153
154 public String toString() {
155 StringBuffer buffer = new StringBuffer();
156 buffer.append("BeanInfo [class = ");
157 buffer.append(clazz.getName());
158 if (isDynamic()) {
159 buffer.append(", dynamic");
160 }
161 if (isAtomic()) {
162 buffer.append(", atomic");
163 }
164 buffer.append(", properties = ");
165 PropertyDescriptor[] jpds = getPropertyDescriptors();
166 for (int i = 0; i < jpds.length; i++) {
167 buffer.append("\n ");
168 buffer.append(jpds[i].getPropertyType());
169 buffer.append(": ");
170 buffer.append(jpds[i].getName());
171 }
172 buffer.append("]");
173 return buffer.toString();
174 }
175 }