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