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