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.content2bean.impl;
35
36 import info.magnolia.cms.core.SystemProperty;
37 import info.magnolia.content2bean.Content2BeanTransformer;
38 import info.magnolia.content2bean.PropertyTypeDescriptor;
39 import info.magnolia.content2bean.TypeDescriptor;
40 import info.magnolia.content2bean.TypeMapping;
41 import info.magnolia.objectfactory.ClassFactory;
42 import info.magnolia.objectfactory.Classes;
43
44 import java.beans.PropertyDescriptor;
45 import java.lang.reflect.Method;
46 import java.util.Collection;
47 import java.util.HashMap;
48 import java.util.Map;
49
50 import javax.inject.Singleton;
51
52 import org.apache.commons.beanutils.PropertyUtils;
53 import org.apache.commons.lang.StringUtils;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57
58
59
60
61
62
63
64 @Singleton
65 public class TypeMappingImpl implements TypeMapping {
66
67 private static Logger log = LoggerFactory.getLogger(TypeMappingImpl.class);
68
69
70
71
72 private final Map<String, PropertyTypeDescriptor> propertyTypes = new HashMap<String, PropertyTypeDescriptor>();
73
74
75
76
77 private final Map<Class<?>, TypeDescriptor> types = new HashMap<Class<?>, TypeDescriptor>();
78
79
80
81
82 public Method getAddMethod(Class<?> type, String name, int numberOfParameters) {
83 name = StringUtils.capitalize(name);
84 Method method = getExactMethod(type, "add" + name, numberOfParameters);
85 if (method == null) {
86 method = getExactMethod(type, "add" + StringUtils.removeEnd(name, "s"), numberOfParameters);
87 }
88
89 if (method == null) {
90 method = getExactMethod(type, "add" + StringUtils.removeEnd(name, "es"), numberOfParameters);
91 }
92
93 if (method == null) {
94 method = getExactMethod(type, "add" + StringUtils.removeEnd(name, "ren"), numberOfParameters);
95 }
96
97 if (method == null) {
98 method = getExactMethod(type, "add" + StringUtils.removeEnd(name, "ies") + "y", numberOfParameters);
99 }
100 return method;
101 }
102
103
104
105
106
107 @Override
108 public PropertyTypeDescriptor getPropertyTypeDescriptor(Class<?> beanClass, String propName) {
109 PropertyTypeDescriptor dscr;
110 String key = beanClass.getName() + "." + propName;
111
112 dscr = propertyTypes.get(key);
113 if(dscr != null){
114 return dscr;
115 }
116
117
118
119
120
121
122
123
124
125
126 dscr = new PropertyTypeDescriptor();
127 dscr.setName(propName);
128
129 PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(beanClass);
130 for (int i = 0; i < descriptors.length; i++) {
131 PropertyDescriptor descriptor = descriptors[i];
132 if (descriptor.getName().equals(propName)) {
133 Class<?> propertytype = descriptor.getPropertyType();
134 if (propertytype != null) {
135 dscr.setType(getTypeDescriptor(propertytype));
136 }
137 break;
138 }
139 }
140
141 if(dscr.getType() != null){
142 if(dscr.isMap() || dscr.isCollection()){
143 int numberOfParameters = dscr.isMap() ? 2 : 1;
144 Method method = getAddMethod(beanClass, propName, numberOfParameters);
145 if(method != null){
146 dscr.setAddMethod(method);
147 if(dscr.isMap()){
148 dscr.setCollectionKeyType(getTypeDescriptor(method.getParameterTypes()[0]));
149 dscr.setCollectionEntryType(getTypeDescriptor(method.getParameterTypes()[1]));
150 }
151 else{
152 dscr.setCollectionEntryType(getTypeDescriptor(method.getParameterTypes()[0]));
153 }
154 }
155 }
156 }
157
158
159 propertyTypes.put(key, dscr);
160
161 return dscr;
162 }
163
164 @Override
165 public void addPropertyTypeDescriptor(Class<?> beanClass, String propName, PropertyTypeDescriptor dscr) {
166 propertyTypes.put(beanClass.getName() + "." + propName, dscr);
167 }
168
169 @Override
170 public void addTypeDescriptor(Class<?> beanClass, TypeDescriptor dscr) {
171 types.put(beanClass, dscr);
172 }
173
174 @Override
175 public TypeDescriptor getTypeDescriptor(Class<?> beanClass) {
176 TypeDescriptor dscr = types.get(beanClass);
177
178 if(dscr != null){
179 return dscr;
180 }
181 dscr = new TypeDescriptor();
182 dscr.setType(beanClass);
183 dscr.setMap(Map.class.isAssignableFrom(beanClass));
184 dscr.setCollection(beanClass.isArray() || Collection.class.isAssignableFrom(beanClass));
185 types.put(beanClass, dscr);
186
187 if (!beanClass.isArray() && !beanClass.isPrimitive()) {
188 Content2BeanTransformer transformer = null;
189 try {
190 if (transformer == null) {
191 transformer = findTransformerByNamingConvention(beanClass);
192 }
193 if (transformer == null) {
194 transformer = findTransformerViaProperty(beanClass);
195 }
196 } catch (Exception e) {
197
198 log.debug("No custom transformer class {}Transformer class found", beanClass.getName());
199 }
200 dscr.setTransformer(transformer);
201 }
202 return dscr;
203 }
204
205
206
207
208 protected Content2BeanTransformer findTransformerByNamingConvention(Class<?> beanClass) {
209 final String transformerClassName = beanClass.getName() + "Transformer";
210 try {
211 return instantiateTransformer(beanClass, transformerClassName);
212 } catch (ClassNotFoundException e) {
213 log.debug("No transformer found by naming convention for {} (attempted to load {})", beanClass, transformerClassName);
214 return null;
215 }
216 }
217
218
219
220
221
222 protected Content2BeanTransformer findTransformerViaProperty(Class<?> beanClass) throws ClassNotFoundException {
223 final String property = SystemProperty.getProperty(beanClass.getName() + ".transformer");
224 if (property != null) {
225 return instantiateTransformer(beanClass,property);
226 }
227 return null;
228 }
229
230 protected Content2BeanTransformer instantiateTransformer(Class<?> beanClass, String transformerClassName) throws ClassNotFoundException {
231 final ClassFactory classFactory = Classes.getClassFactory();
232 final Class<Content2BeanTransformer> transformerClass = classFactory.forName(transformerClassName);
233
234 if (Content2BeanTransformer.class.isAssignableFrom(transformerClass)) {
235 try {
236 log.debug("Found a custom transformer [{" + transformerClass + "}] for [{" + beanClass + "}]");
237
238 return classFactory.newInstance(transformerClass);
239 } catch (Exception e) {
240 log.error("Can't instantiate custom transformer [{" + transformerClass + "}] for [{" + beanClass + "}]", e);
241 }
242 }
243 return null;
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 if (method.getParameterTypes().length == numberOfParameters) {
260 return method;
261 }
262 }
263 }
264 return null;
265 }
266
267 }