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