1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.velocity.tools.generic.introspection;
18
19 import java.lang.reflect.Array;
20 import java.lang.reflect.Field;
21
22 import org.apache.velocity.util.introspection.Info;
23 import org.apache.velocity.util.introspection.UberspectImpl;
24 import org.apache.velocity.util.introspection.VelPropertyGet;
25 import org.apache.velocity.util.introspection.VelPropertySet;
26
27 /***
28 * Uberspect implementation that exposes public fields.
29 * Also exposes the explicit "length" field of arrays.
30 *
31 * <p>To use, tell Velocity to use this class for introspection
32 * by adding the following to your velocity.properties:<br />
33 *
34 * <code>
35 * runtime.introspector.uberspect = org.apache.velocity.tools.generic.introspection.PublicFieldUberspect
36 * </code>
37 * </p>
38 *
39 * @author <a href="mailto:shinobu@ieee.org">Shinobu Kawai</a>
40 * @version $Id: $
41 */
42 public class PublicFieldUberspect extends UberspectImpl
43 {
44
45 /***
46 * Default constructor.
47 */
48 public PublicFieldUberspect()
49 {
50 }
51
52 /***
53 * Property getter - returns VelPropertyGet appropos for #set($foo = $bar.woogie).
54 * <br />
55 * Returns a special {@link VelPropertyGet} for the <code>length</code> property of arrays.
56 * Otherwise tries the regular routine. If a getter was not found,
57 * returns a {@link VelPropertyGet} that gets from public fields.
58 *
59 * @param obj the object
60 * @param identifier the name of the property
61 * @param i a bunch of information.
62 * @return a valid <code>VelPropertyGet</code>, if it was found.
63 * @throws Exception failed to create a valid <code>VelPropertyGet</code>.
64 */
65 public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i)
66 throws Exception
67 {
68 Class clazz = obj.getClass();
69 boolean isArray = clazz.isArray();
70 boolean isLength = identifier.equals("length");
71 if (isArray && isLength)
72 {
73 return new ArrayLengthGetter();
74 }
75
76 VelPropertyGet getter = super.getPropertyGet(obj, identifier, i);
77
78
79 try
80 {
81 getter.getMethodName();
82 return getter;
83 }
84 catch (NullPointerException notFound)
85 {
86 }
87
88 Field field = obj.getClass().getField(identifier);
89 if (field != null)
90 {
91 return new PublicFieldGetter(field);
92 }
93
94 return null;
95 }
96
97 /***
98 * Property setter - returns VelPropertySet appropos for #set($foo.bar = "geir").
99 * <br />
100 * First tries the regular routine. If a setter was not found,
101 * returns a {@link VelPropertySet} that sets to public fields.
102 *
103 * @param obj the object
104 * @param identifier the name of the property
105 * @param arg the value to set to the property
106 * @param i a bunch of information.
107 * @return a valid <code>VelPropertySet</code>, if it was found.
108 * @throws Exception failed to create a valid <code>VelPropertySet</code>.
109 */
110 public VelPropertySet getPropertySet(Object obj, String identifier,
111 Object arg, Info i) throws Exception
112 {
113 VelPropertySet setter = super.getPropertySet(obj, identifier, arg, i);
114 if (setter != null)
115 {
116 return setter;
117 }
118
119 Field field = obj.getClass().getField(identifier);
120 if (field != null)
121 {
122 return new PublicFieldSetter(field);
123 }
124
125 return null;
126 }
127
128 /***
129 * Implementation of {@link VelPropertyGet} that gets from public fields.
130 *
131 * @author <a href="mailto:shinobu@ieee.org">Shinobu Kawai</a>
132 * @version $Id: $
133 */
134 protected class PublicFieldGetter implements VelPropertyGet
135 {
136 /*** The <code>Field</code> object representing the property. */
137 private Field field = null;
138
139 /***
140 * Constructor.
141 *
142 * @param field The <code>Field</code> object representing the property.
143 */
144 public PublicFieldGetter(Field field)
145 {
146 this.field = field;
147 }
148
149 /***
150 * Returns the value of the public field.
151 *
152 * @param o the object
153 * @return the value
154 * @throws Exception failed to get the value from the object
155 */
156 public Object invoke(Object o) throws Exception
157 {
158 return this.field.get(o);
159 }
160
161 /***
162 * This class is cacheable, so it returns <code>true</code>.
163 *
164 * @return <code>true</code>.
165 */
166 public boolean isCacheable()
167 {
168 return true;
169 }
170
171 /***
172 * Returns <code>"public field getter"</code>, since there is no method.
173 *
174 * @return <code>"public field getter"</code>
175 */
176 public String getMethodName()
177 {
178 return "public field getter";
179 }
180 }
181
182 /***
183 * Implementation of {@link VelPropertyGet} that gets length from arrays.
184 *
185 * @author <a href="mailto:shinobu@ieee.org">Shinobu Kawai</a>
186 * @version $Id: $
187 */
188 protected class ArrayLengthGetter implements VelPropertyGet
189 {
190 /***
191 * Constructor.
192 */
193 public ArrayLengthGetter()
194 {
195 }
196
197 /***
198 * Returns the length of the array.
199 *
200 * @param o the array
201 * @return the length
202 * @throws Exception failed to get the length from the array
203 */
204 public Object invoke(Object o) throws Exception
205 {
206
207 return new Integer(Array.getLength(o));
208 }
209
210 /***
211 * This class is cacheable, so it returns <code>true</code>.
212 *
213 * @return <code>true</code>.
214 */
215 public boolean isCacheable()
216 {
217 return true;
218 }
219
220 /***
221 * Returns <code>"array length getter"</code>, since there is no method.
222 *
223 * @return <code>"array length getter"</code>
224 */
225 public String getMethodName()
226 {
227 return "array length getter";
228 }
229 }
230
231 /***
232 * Implementation of {@link VelPropertySet} that sets to public fields.
233 *
234 * @author <a href="mailto:shinobu@ieee.org">Shinobu Kawai</a>
235 * @version $Id: $
236 */
237 protected class PublicFieldSetter implements VelPropertySet
238 {
239 /*** The <code>Field</code> object representing the property. */
240 private Field field = null;
241
242 /***
243 * Constructor.
244 *
245 * @param field The <code>Field</code> object representing the property.
246 */
247 public PublicFieldSetter(Field field)
248 {
249 this.field = field;
250 }
251
252 /***
253 * Sets the value to the public field.
254 *
255 * @param o the object
256 * @param value the value to set
257 * @return always <code>null</code>
258 * @throws Exception failed to set the value to the object
259 */
260 public Object invoke(Object o, Object value) throws Exception
261 {
262 this.field.set(o, value);
263 return null;
264 }
265
266 /***
267 * This class is cacheable, so it returns <code>true</code>.
268 *
269 * @return <code>true</code>.
270 */
271 public boolean isCacheable()
272 {
273 return true;
274 }
275
276 /***
277 * Returns <code>"public field setter"</code>, since there is no method.
278 *
279 * @return <code>"public field setter"</code>
280 */
281 public String getMethodName()
282 {
283 return "public field setter";
284 }
285 }
286
287 }