View Javadoc

1   package org.apache.commons.ognl;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.beans.IntrospectionException;
23  import java.beans.PropertyDescriptor;
24  import java.lang.reflect.Method;
25  
26  /**
27   * <p>
28   * PropertyDescriptor subclass that describes an indexed set of read/write methods to get a property. Unlike
29   * IndexedPropertyDescriptor this allows the "key" to be an arbitrary object rather than just an int. Consequently it
30   * does not have a "readMethod" or "writeMethod" because it only expects a pattern like:
31   * </p>
32   * 
33   * <pre>
34   *    public void set<i>Property</i>(<i>KeyType</i>, <i>ValueType</i>);
35   *    public <i>ValueType</i> get<i>Property</i>(<i>KeyType</i>);
36   * </pre>
37   * <p>
38   * and does not require the methods that access it as an array. OGNL can get away with this without losing functionality
39   * because if the object does expose the properties they are most probably in a Map and that case is handled by the
40   * normal OGNL property accessors.
41   * </p>
42   * <p>
43   * For example, if an object were to have methods that accessed and "attributes" property it would be natural to index
44   * them by String rather than by integer and expose the attributes as a map with a different property name:
45   * 
46   * <pre>
47   * public void setAttribute( String name, Object value );
48   * 
49   * public Object getAttribute( String name );
50   * 
51   * public Map getAttributes();
52   * </pre>
53   * <p>
54   * Note that the index get/set is called get/set <code>Attribute</code> whereas the collection getter is called
55   * <code>Attributes</code>. This case is handled unambiguously by the OGNL property accessors because the set/get
56   * <code>Attribute</code> methods are detected by this object and the "attributes" case is handled by the
57   * <code>MapPropertyAccessor</code>. Therefore OGNL expressions calling this code would be handled in the following way:
58   * </p>
59   * <table>
60   * <tr>
61   * <th>OGNL Expression</th>
62   * <th>Handling</th>
63   * </tr>
64   * <tr>
65   * <td><code>attribute["name"]</code></td>
66   * <td>Handled by an index getter, like <code>getAttribute(String)</code>.</td>
67   * </tr>
68   * <tr>
69   * <td><code>attribute["name"] = value</code></td>
70   * <td>Handled by an index setter, like <code>setAttribute(String, Object)</code>.</td>
71   * </tr>
72   * <tr>
73   * <td><code>attributes["name"]</code></td>
74   * <td>Handled by <code>MapPropertyAccessor</code> via a <code>Map.get()</code>. This will <b>not</b> go through the
75   * index get accessor.</td>
76   * </tr>
77   * <tr>
78   * <td><code>attributes["name"] = value</code></td>
79   * <td>Handled by <code>MapPropertyAccessor</code> via a <code>Map.put()</code>. This will <b>not</b> go through the
80   * index set accessor.</td>
81   * </tr>
82   * </table>
83   * 
84   * @author Luke Blanshard (blanshlu@netscape.net)
85   * @author Drew Davidson (drew@ognl.org)
86   */
87  public class ObjectIndexedPropertyDescriptor
88      extends PropertyDescriptor
89  {
90      private Method indexedReadMethod;
91  
92      private Method indexedWriteMethod;
93  
94      private Class<?> propertyType;
95  
96      public ObjectIndexedPropertyDescriptor( String propertyName, Class<?> propertyType, Method indexedReadMethod,
97                                              Method indexedWriteMethod )
98          throws IntrospectionException
99      {
100         super( propertyName, null, null );
101         this.propertyType = propertyType;
102         this.indexedReadMethod = indexedReadMethod;
103         this.indexedWriteMethod = indexedWriteMethod;
104     }
105 
106     public Method getIndexedReadMethod()
107     {
108         return indexedReadMethod;
109     }
110 
111     public Method getIndexedWriteMethod()
112     {
113         return indexedWriteMethod;
114     }
115 
116     @Override
117     public Class<?> getPropertyType()
118     {
119         return propertyType;
120     }
121 
122     @Override
123     public boolean equals(Object o) {
124         if (this == o)
125         {
126             return true;
127         }
128 
129         if (!(o instanceof ObjectIndexedPropertyDescriptor))
130         {
131             return false;
132         }
133 
134         if (!super.equals(o))
135         {
136             return false;
137         }
138 
139         ObjectIndexedPropertyDescriptor that = (ObjectIndexedPropertyDescriptor) o;
140 
141         if (indexedReadMethod != null ? !indexedReadMethod.equals(that.indexedReadMethod) : that.indexedReadMethod != null)
142         {
143             return false;
144         }
145 
146         if (indexedWriteMethod != null ? !indexedWriteMethod.equals(that.indexedWriteMethod) : that.indexedWriteMethod != null)
147         {
148             return false;
149         }
150 
151         if (propertyType != null ? !propertyType.equals(that.propertyType) : that.propertyType != null)
152         {
153             return false;
154         }
155 
156         return true;
157     }
158 
159     @Override
160     public int hashCode() {
161         int result = super.hashCode();
162         result = 31 * result + (indexedReadMethod != null ? indexedReadMethod.hashCode() : 0);
163         result = 31 * result + (indexedWriteMethod != null ? indexedWriteMethod.hashCode() : 0);
164         result = 31 * result + (propertyType != null ? propertyType.hashCode() : 0);
165         return result;
166     }
167 }