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