1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jxpath.ri.model.beans;
19
20 import java.beans.IndexedPropertyDescriptor;
21 import java.beans.PropertyDescriptor;
22
23 import org.apache.commons.jxpath.JXPathBeanInfo;
24 import org.apache.commons.jxpath.JXPathContext;
25 import org.apache.commons.jxpath.JXPathInvalidAccessException;
26 import org.apache.commons.jxpath.ri.model.NodePointer;
27 import org.apache.commons.jxpath.util.ValueUtils;
28
29
30
31
32 public class BeanPropertyPointer extends PropertyPointer {
33
34 private static final long serialVersionUID = -6008991447676468786L;
35
36
37
38
39 private static final Object UNINITIALIZED = new Object();
40
41
42
43
44 private String propertyName;
45
46
47
48
49 private final JXPathBeanInfo beanInfo;
50
51
52
53
54 private Object baseValue = UNINITIALIZED;
55
56
57
58
59
60 private Object value = UNINITIALIZED;
61
62
63
64
65 private transient String[] names;
66
67
68
69
70 private transient PropertyDescriptor[] propertyDescriptors;
71
72
73
74
75 private transient PropertyDescriptor propertyDescriptor;
76
77
78
79
80
81
82
83 public BeanPropertyPointer(final NodePointer parent, final JXPathBeanInfo beanInfo) {
84 super(parent);
85 this.beanInfo = beanInfo;
86 }
87
88 @Override
89 public NodePointer createPath(final JXPathContext context) {
90 if (getImmediateNode() == null) {
91 super.createPath(context);
92 baseValue = UNINITIALIZED;
93 value = UNINITIALIZED;
94 }
95 return this;
96 }
97
98
99
100
101
102
103 @Override
104 public Object getBaseValue() {
105 if (baseValue == UNINITIALIZED) {
106 final PropertyDescriptor pd = getPropertyDescriptor();
107 if (pd == null) {
108 return null;
109 }
110 baseValue = ValueUtils.getValue(getBean(), pd);
111 }
112 return baseValue;
113 }
114
115
116
117
118
119
120
121 @Override
122 public Object getImmediateNode() {
123 if (value == UNINITIALIZED) {
124 if (index == WHOLE_COLLECTION) {
125 value = ValueUtils.getValue(getBaseValue());
126 } else {
127 final PropertyDescriptor pd = getPropertyDescriptor();
128 if (pd == null) {
129 value = null;
130 } else {
131 value = ValueUtils.getValue(getBean(), pd, index);
132 }
133 }
134 }
135 return value;
136 }
137
138
139
140
141
142
143 @Override
144 public int getLength() {
145 final PropertyDescriptor pd = getPropertyDescriptor();
146 if (pd == null) {
147 return 1;
148 }
149 if (pd instanceof IndexedPropertyDescriptor) {
150 return ValueUtils.getIndexedPropertyLength(getBean(), (IndexedPropertyDescriptor) pd);
151 }
152 final int hint = ValueUtils.getCollectionHint(pd.getPropertyType());
153 if (hint == -1) {
154 return 1;
155 }
156 return super.getLength();
157 }
158
159 @Override
160 public int getPropertyCount() {
161 if (beanInfo.isAtomic()) {
162 return 0;
163 }
164 return getPropertyDescriptors().length;
165 }
166
167
168
169
170
171
172 private PropertyDescriptor getPropertyDescriptor() {
173 if (propertyDescriptor == null) {
174 final int inx = getPropertyIndex();
175 if (inx == UNSPECIFIED_PROPERTY) {
176 propertyDescriptor = beanInfo.getPropertyDescriptor(propertyName);
177 } else {
178 final PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors();
179 if (inx >= 0 && inx < propertyDescriptors.length) {
180 propertyDescriptor = propertyDescriptors[inx];
181 } else {
182 propertyDescriptor = null;
183 }
184 }
185 }
186 return propertyDescriptor;
187 }
188
189
190
191
192
193
194 protected synchronized PropertyDescriptor[] getPropertyDescriptors() {
195 if (propertyDescriptors == null) {
196 propertyDescriptors = beanInfo.getPropertyDescriptors();
197 }
198 return propertyDescriptors;
199 }
200
201
202
203
204
205
206 @Override
207 public String getPropertyName() {
208 if (propertyName == null) {
209 final PropertyDescriptor pd = getPropertyDescriptor();
210 if (pd != null) {
211 propertyName = pd.getName();
212 }
213 }
214 return propertyName != null ? propertyName : "*";
215 }
216
217
218
219
220
221
222 @Override
223 public String[] getPropertyNames() {
224 if (names == null) {
225 final PropertyDescriptor[] pds = getPropertyDescriptors();
226 names = new String[pds.length];
227 for (int i = 0; i < names.length; i++) {
228 names[i] = pds[i].getName();
229 }
230 }
231 return names;
232 }
233
234 @Override
235 protected boolean isActualProperty() {
236 return getPropertyDescriptor() != null;
237 }
238
239 @Override
240 public boolean isCollection() {
241 final PropertyDescriptor pd = getPropertyDescriptor();
242 if (pd == null) {
243 return false;
244 }
245 if (pd instanceof IndexedPropertyDescriptor) {
246 return true;
247 }
248 final int hint = ValueUtils.getCollectionHint(pd.getPropertyType());
249 if (hint == -1) {
250 return false;
251 }
252 if (hint == 1) {
253 return true;
254 }
255 final Object value = getBaseValue();
256 return value != null && ValueUtils.isCollection(value);
257 }
258
259
260
261
262
263
264 @Override
265 public boolean isContainer() {
266 return true;
267 }
268
269 @Override
270 public void remove() {
271 if (index == WHOLE_COLLECTION) {
272 setValue(null);
273 } else if (isCollection()) {
274 final Object o = getBaseValue();
275 final Object collection = ValueUtils.remove(getBaseValue(), index);
276 if (collection != o) {
277 ValueUtils.setValue(getBean(), getPropertyDescriptor(), collection);
278 }
279 } else if (index == 0) {
280 index = WHOLE_COLLECTION;
281 setValue(null);
282 }
283 }
284
285 @Override
286 public void setIndex(final int index) {
287 if (this.index == index) {
288 return;
289 }
290
291
292 if (this.index != WHOLE_COLLECTION || index != 0 || isCollection()) {
293 super.setIndex(index);
294 value = UNINITIALIZED;
295 }
296 }
297
298
299
300
301
302
303 @Override
304 public void setPropertyIndex(final int index) {
305 if (propertyIndex != index) {
306 super.setPropertyIndex(index);
307 propertyName = null;
308 propertyDescriptor = null;
309 baseValue = UNINITIALIZED;
310 value = UNINITIALIZED;
311 }
312 }
313
314
315
316
317
318
319 @Override
320 public void setPropertyName(final String propertyName) {
321 setPropertyIndex(UNSPECIFIED_PROPERTY);
322 this.propertyName = propertyName;
323 }
324
325
326
327
328
329
330
331 @Override
332 public void setValue(final Object value) {
333 final PropertyDescriptor pd = getPropertyDescriptor();
334 if (pd == null) {
335 throw new JXPathInvalidAccessException("Cannot set property: " + asPath() + " - no such property");
336 }
337 if (index == WHOLE_COLLECTION) {
338 ValueUtils.setValue(getBean(), pd, value);
339 } else {
340 ValueUtils.setValue(getBean(), pd, index, value);
341 }
342 this.value = value;
343 }
344 }