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.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 TransformedBy transformerAnnotation = writeMethod.getAnnotation(TransformedBy.class);
168 transformerClass = transformerAnnotation == null ? null : (Class<Node2BeanTransformer>) transformerAnnotation.value();
169 transformer = transformerClass == null ? null : Components.getComponentProvider().newInstance(transformerClass);
170 }
171 if (transformer == null) {
172 try {
173 transformerClass = (Class<Node2BeanTransformer>) Class.forName(beanClass.getName() + "Transformer");
174 transformer = Components.getComponent(transformerClass);
175 } catch (ClassNotFoundException e) {
176 log.debug("No transformer found for bean [{}]", beanClass);
177 }
178 }
179 return transformer;
180 }
181 return null;
182 }
183
184
185
186
187 private TypeDescriptor getTypeDescriptor(Class<?> beanClass, Method method) {
188 TypeDescriptor dscr = types.get(beanClass);
189
190 if(dscr != null){
191 return dscr;
192 }
193 dscr = new TypeDescriptor();
194 dscr.setType(beanClass);
195 dscr.setMap(Map.class.isAssignableFrom(beanClass));
196 dscr.setCollection(Collection.class.isAssignableFrom(beanClass));
197 dscr.setArray(beanClass.isArray());
198 try {
199 dscr.setTransformer(resolveTransformer(beanClass, method));
200 } catch (Node2BeanException e) {
201 log.error("Can't create transformer for bean [" + beanClass + "]", e);
202 }
203
204 types.put(beanClass, dscr);
205
206 return dscr;
207 }
208
209 @Override
210 public TypeDescriptor getTypeDescriptor(Class<?> beanClass) {
211 return getTypeDescriptor(beanClass, null);
212 }
213
214
215
216
217
218 public Method getAddMethod(Class<?> type, String name, int numberOfParameters) {
219 name = StringUtils.capitalize(name);
220 Method method = getExactMethod(type, "add" + name, numberOfParameters);
221 if (method == null) {
222 method = getExactMethod(type, "add" + StringUtils.removeEnd(name, "s"), numberOfParameters);
223 }
224
225 if (method == null) {
226 method = getExactMethod(type, "add" + StringUtils.removeEnd(name, "es"), numberOfParameters);
227 }
228
229 if (method == null) {
230 method = getExactMethod(type, "add" + StringUtils.removeEnd(name, "ren"), numberOfParameters);
231 }
232
233 if (method == null) {
234 method = getExactMethod(type, "add" + StringUtils.removeEnd(name, "ies") + "y", numberOfParameters);
235 }
236 return method;
237 }
238
239
240
241
242
243
244
245 protected Method getExactMethod(Class<?> type, String name, int numberOfParameters) {
246 Method[] methods = type.getMethods();
247 for (int i = 0; i < methods.length; i++) {
248 Method method = methods[i];
249 if (method.getName().equals(name)) {
250
251
252
253
254
255 if (method.getParameterTypes().length == numberOfParameters) {
256 return method;
257 }
258 }
259 }
260 return null;
261 }
262
263 }