1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.struts2.views.xslt;
22
23 import java.beans.IntrospectionException;
24 import java.beans.Introspector;
25 import java.beans.PropertyDescriptor;
26 import java.lang.reflect.InvocationTargetException;
27 import java.lang.reflect.Method;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Map;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.struts2.StrutsException;
36 import org.w3c.dom.Node;
37 import org.w3c.dom.NodeList;
38
39
40 /***
41 * This class is the most general type of adapter, utilizing reflective introspection to present a DOM view of all of
42 * the public properties of its value. For example, a property returning a JavaBean such as:
43 *
44 * <pre>
45 * public Person getMyPerson() { ... }
46 * ...
47 * class Person {
48 * public String getFirstName();
49 * public String getLastName();
50 * }
51 * </pre>
52 *
53 * would be rendered as: <myPerson> <firstName>...</firstName> <lastName>...</lastName> </myPerson>
54 */
55 public class BeanAdapter extends AbstractAdapterElement {
56
57
58 private static final Object[] NULLPARAMS = new Object[0];
59
60 /***
61 * Cache can savely be static because the cached information is the same for all instances of this class.
62 */
63 private static Map<Class, PropertyDescriptor[]> propertyDescriptorCache;
64
65
66
67 private Log log = LogFactory.getLog(this.getClass());
68
69
70
71 public BeanAdapter() {
72 }
73
74 public BeanAdapter(
75 AdapterFactory adapterFactory, AdapterNode parent, String propertyName, Object value) {
76 setContext(adapterFactory, parent, propertyName, value);
77 }
78
79
80
81 public String getTagName() {
82 return getPropertyName();
83 }
84
85 public NodeList getChildNodes() {
86 NodeList nl = super.getChildNodes();
87
88 if (log.isDebugEnabled() && nl != null) {
89 log.debug("BeanAdapter getChildNodes for: " + getTagName());
90 log.debug(nl.toString());
91 }
92 return nl;
93 }
94
95 protected List<Node> buildChildAdapters() {
96 log.debug("BeanAdapter building children. PropName = " + getPropertyName());
97 List<Node> newAdapters = new ArrayList<Node>();
98 Class type = getPropertyValue().getClass();
99 PropertyDescriptor[] props = getPropertyDescriptors(getPropertyValue());
100
101 if (props.length > 0) {
102 for (PropertyDescriptor prop : props) {
103 Method m = prop.getReadMethod();
104
105 if (m == null) {
106
107 continue;
108 }
109 log.debug("Bean reading property method: " + m.getName());
110
111 String propertyName = prop.getName();
112 Object propertyValue;
113
114
115
116
117
118
119 try {
120 propertyValue = m.invoke(getPropertyValue(), NULLPARAMS);
121 } catch (Exception e) {
122 if (e instanceof InvocationTargetException)
123 e = (Exception) ((InvocationTargetException) e).getTargetException();
124 log.error(e);
125 continue;
126 }
127
128 Node childAdapter;
129
130 if (propertyValue == null) {
131 childAdapter = getAdapterFactory().adaptNullValue(this, propertyName);
132 } else {
133 childAdapter = getAdapterFactory().adaptNode(this, propertyName, propertyValue);
134 }
135
136 if (childAdapter != null)
137 newAdapters.add(childAdapter);
138
139 if (log.isDebugEnabled()) {
140 log.debug(this + " adding adapter: " + childAdapter);
141 }
142 }
143 } else {
144
145 log.info(
146 "Class " + type.getName() + " has no readable properties, " + " trying to adapt " + getPropertyName() + " with StringAdapter...");
147 }
148
149 return newAdapters;
150 }
151
152 /***
153 * Caching facade method to Introspector.getBeanInfo(Class, Class).getPropertyDescriptors();
154 */
155 private synchronized PropertyDescriptor[] getPropertyDescriptors(Object bean) {
156 try {
157 if (propertyDescriptorCache == null) {
158 propertyDescriptorCache = new HashMap<Class, PropertyDescriptor[]>();
159 }
160
161 PropertyDescriptor[] props = propertyDescriptorCache.get(bean.getClass());
162
163 if (props == null) {
164 log.debug("Caching property descriptor for " + bean.getClass().getName());
165 props = Introspector.getBeanInfo(bean.getClass(), Object.class).getPropertyDescriptors();
166 propertyDescriptorCache.put(bean.getClass(), props);
167 }
168
169 return props;
170 } catch (IntrospectionException e) {
171 e.printStackTrace();
172 throw new StrutsException("Error getting property descriptors for " + bean + " : " + e.getMessage());
173 }
174 }
175 }