View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jxpath;
18  
19  import java.beans.BeanInfo;
20  import java.beans.IntrospectionException;
21  import java.beans.Introspector;
22  import java.beans.PropertyDescriptor;
23  import java.util.Arrays;
24  import java.util.Comparator;
25  import java.util.HashMap;
26  
27  /**
28   * An implementation of JXPathBeanInfo based on JavaBeans' BeanInfo. Properties
29   * advertised by JXPathBasicBeanInfo are the same as those advertised by
30   * BeanInfo for the corresponding class.
31   *
32   * @see java.beans.BeanInfo
33   * @see java.beans.Introspector
34   *
35   * @author Dmitri Plotnikov
36   * @version $Revision: 1190145 $ $Date: 2011-10-28 05:36:24 +0200 (Fr, 28 Okt 2011) $
37   */
38  public class JXPathBasicBeanInfo implements JXPathBeanInfo {
39      private static final long serialVersionUID = -3863803443111484155L;
40  
41      private static final Comparator PROPERTY_DESCRIPTOR_COMPARATOR = new Comparator() {
42          public int compare(Object left, Object right) {
43              return ((PropertyDescriptor) left).getName().compareTo(
44                  ((PropertyDescriptor) right).getName());
45          }
46      };
47  
48      private boolean atomic = false;
49      private Class clazz;
50      private Class dynamicPropertyHandlerClass;
51      private transient PropertyDescriptor[] propertyDescriptors;
52      private transient HashMap propertyDescriptorMap;
53  
54      /**
55       * Create a new JXPathBasicBeanInfo.
56       * @param clazz bean class
57       */
58      public JXPathBasicBeanInfo(Class clazz) {
59          this.clazz = clazz;
60      }
61  
62      /**
63       * Create a new JXPathBasicBeanInfo.
64       * @param clazz bean class
65       * @param atomic whether objects of this class are treated as atomic
66       *               objects which have no properties of their own.
67       */
68      public JXPathBasicBeanInfo(Class clazz, boolean atomic) {
69          this.clazz = clazz;
70          this.atomic = atomic;
71      }
72  
73      /**
74       * Create a new JXPathBasicBeanInfo.
75       * @param clazz bean class
76       * @param dynamicPropertyHandlerClass dynamic property handler class
77       */
78      public JXPathBasicBeanInfo(Class clazz, Class dynamicPropertyHandlerClass) {
79          this.clazz = clazz;
80          this.atomic = false;
81          this.dynamicPropertyHandlerClass = dynamicPropertyHandlerClass;
82      }
83  
84      /**
85       * Returns true if objects of this class are treated as atomic
86       * objects which have no properties of their own.
87       * @return boolean
88       */
89      public boolean isAtomic() {
90          return atomic;
91      }
92  
93      /**
94       * Return true if the corresponding objects have dynamic properties.
95       * @return boolean
96       */
97      public boolean isDynamic() {
98          return dynamicPropertyHandlerClass != null;
99      }
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 }