1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.jcr.node2bean.impl;
35
36 import info.magnolia.jcr.node2bean.Node2BeanException;
37 import info.magnolia.jcr.node2bean.Node2BeanTransformer;
38 import info.magnolia.jcr.node2bean.PropertyTypeDescriptor;
39 import info.magnolia.jcr.node2bean.TransformedBy;
40 import info.magnolia.jcr.node2bean.TypeDescriptor;
41 import info.magnolia.jcr.node2bean.TypeMapping;
42 import info.magnolia.objectfactory.Components;
43
44 import java.beans.PropertyDescriptor;
45 import java.lang.reflect.Method;
46 import java.lang.reflect.ParameterizedType;
47 import java.lang.reflect.Type;
48 import java.lang.reflect.WildcardType;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.Collection;
52 import java.util.HashMap;
53 import java.util.List;
54 import java.util.Map;
55
56 import org.apache.commons.beanutils.PropertyUtils;
57 import org.apache.commons.lang.StringUtils;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60
61
62
63
64 public class TypeMappingImpl implements TypeMapping {
65
66 private static Logger log = LoggerFactory.getLogger(TypeMappingImpl.class);
67
68 private final Map<String, PropertyTypeDescriptor> propertyTypes = new HashMap<String, PropertyTypeDescriptor>();
69 private final Map<Class<?>, TypeDescriptor> types = new HashMap<Class<?>, TypeDescriptor>();
70
71 @Override
72 public PropertyTypeDescriptor getPropertyTypeDescriptor(Class<?> beanClass, String propName) {
73 PropertyTypeDescriptor dscr = null;
74 String key = beanClass.getName() + "." + propName;
75
76 dscr = propertyTypes.get(key);
77
78 if (dscr != null) {
79 return dscr;
80 }
81
82 dscr = new PropertyTypeDescriptor();
83 dscr.setName(propName);
84
85 PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(beanClass);
86 Method writeMethod = null;
87 for (PropertyDescriptor descriptor : descriptors) {
88 if (descriptor.getName().equals(propName)) {
89
90 Class<?> propertyType = descriptor.getPropertyType();
91 writeMethod = descriptor.getWriteMethod();
92 if (propertyType != null) {
93 dscr.setType(getTypeDescriptor(propertyType, writeMethod));
94 }
95
96 dscr.setWriteMethod(writeMethod);
97
98 int numberOfParameters = dscr.isMap() ? 2 : 1;
99 dscr.setAddMethod(getAddMethod(beanClass, propName, numberOfParameters));
100
101 break;
102 }
103 }
104
105 if (dscr.getType() != null) {
106
107 if (dscr.isMap() || dscr.isCollection()) {
108 List<Class<?>> parameterTypes = new ArrayList<Class<?>>();
109 if (dscr.getWriteMethod() != null) {
110 parameterTypes = inferGenericTypes(dscr.getWriteMethod());
111 }
112 if (dscr.getAddMethod() != null && parameterTypes.size() == 0) {
113
114
115 parameterTypes = Arrays.asList(dscr.getAddMethod().getParameterTypes());
116
117 dscr.setWriteMethod(null);
118 }
119 if (parameterTypes.size() > 0) {
120
121 if (dscr.isMap()) {
122 dscr.setCollectionKeyType(getTypeDescriptor(parameterTypes.get(0)));
123 dscr.setCollectionEntryType(getTypeDescriptor(parameterTypes.get(1)));
124 } else {
125
126 dscr.setCollectionEntryType(getTypeDescriptor(parameterTypes.get(0)));
127 }
128 }
129 } else if (dscr.isArray()) {
130
131
132 dscr.setCollectionEntryType(getTypeDescriptor(dscr.getType().getType().getComponentType()));
133 }
134 }
135 propertyTypes.put(key, dscr);
136
137 return dscr;
138 }
139
140 private List<Class<?>> inferGenericTypes(Method method) {
141 List<Class<?>> inferredTypes = new ArrayList<Class<?>>();
142 Type[] parameterTypes = method.getGenericParameterTypes();
143 for (Type parameterType : parameterTypes) {
144 if (parameterType instanceof ParameterizedType) {
145 ParameterizedType type = (ParameterizedType) parameterType;
146 for (Type t : type.getActualTypeArguments()) {
147 if (t instanceof ParameterizedType) {
148
149
150 inferredTypes.add((Class<?>) ((ParameterizedType) t).getRawType());
151 } else if (t instanceof WildcardType) {
152 WildcardType wildcardType = (WildcardType) t;
153 if (wildcardType.getUpperBounds().length > 0) {
154
155 inferredTypes.add((Class<?>) wildcardType.getUpperBounds()[0]);
156 } else {
157
158 inferredTypes.add((Class<?>) wildcardType.getLowerBounds()[0]);
159 }
160 } else {
161 inferredTypes.add((Class<?>) t);
162 }
163 }
164 }
165 }
166 return inferredTypes;
167 }
168
169
170
171
172 private Node2BeanTransformer resolveTransformer(Class<?> beanClass, Method writeMethod) throws Node2BeanException {
173 if (!beanClass.isArray() && !beanClass.isPrimitive()) {
174 Class<Node2BeanTransformer> transformerClass = null;
175 Node2BeanTransformer transformer = null;
176 if (writeMethod != null) {
177 TransformedBy transformerAnnotation = writeMethod.getAnnotation(TransformedBy.class);
178 transformerClass = transformerAnnotation == null ? null : (Class<Node2BeanTransformer>) transformerAnnotation.value();
179 transformer = transformerClass == null ? null : Components.getComponentProvider().newInstance(transformerClass);
180 }
181 if (transformer == null) {
182 try {
183 transformerClass = (Class<Node2BeanTransformer>) Class.forName(beanClass.getName() + "Transformer");
184 transformer = Components.getComponent(transformerClass);
185 } catch (ClassNotFoundException e) {
186 log.debug("No transformer found for bean [{}]", beanClass);
187 }
188 }
189 return transformer;
190 }
191 return null;
192 }
193
194
195
196
197 private TypeDescriptor getTypeDescriptor(Class<?> beanClass, Method method) {
198 TypeDescriptor dscr = types.get(beanClass);
199
200 if(dscr != null){
201 return dscr;
202 }
203 dscr = new TypeDescriptor();
204 dscr.setType(beanClass);
205 dscr.setMap(Map.class.isAssignableFrom(beanClass));
206 dscr.setCollection(Collection.class.isAssignableFrom(beanClass));
207 dscr.setArray(beanClass.isArray());
208 try {
209 dscr.setTransformer(resolveTransformer(beanClass, method));
210 } catch (Node2BeanException e) {
211 log.error("Can't create transformer for bean [" + beanClass + "]", e);
212 }
213
214 types.put(beanClass, dscr);
215
216 return dscr;
217 }
218
219 @Override
220 public TypeDescriptor getTypeDescriptor(Class<?> beanClass) {
221 return getTypeDescriptor(beanClass, null);
222 }
223
224
225
226
227
228 public Method getAddMethod(Class<?> type, String name, int numberOfParameters) {
229 name = StringUtils.capitalize(name);
230 Method method = getExactMethod(type, "add" + name, numberOfParameters);
231 if (method == null) {
232 method = getExactMethod(type, "add" + StringUtils.removeEnd(name, "s"), numberOfParameters);
233 }
234
235 if (method == null) {
236 method = getExactMethod(type, "add" + StringUtils.removeEnd(name, "es"), numberOfParameters);
237 }
238
239 if (method == null) {
240 method = getExactMethod(type, "add" + StringUtils.removeEnd(name, "ren"), numberOfParameters);
241 }
242
243 if (method == null) {
244 method = getExactMethod(type, "add" + StringUtils.removeEnd(name, "ies") + "y", numberOfParameters);
245 }
246 return method;
247 }
248
249
250
251
252
253
254
255 protected Method getExactMethod(Class<?> type, String name, int numberOfParameters) {
256 Method[] methods = type.getMethods();
257 for (int i = 0; i < methods.length; i++) {
258 Method method = methods[i];
259 if (method.getName().equals(name)) {
260
261
262
263
264
265 if (method.getParameterTypes().length == numberOfParameters) {
266 return method;
267 }
268 }
269 }
270 return null;
271 }
272
273 }