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