1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.util.ajax;
16
17 import java.lang.reflect.InvocationTargetException;
18 import java.lang.reflect.Method;
19 import java.lang.reflect.Modifier;
20 import java.util.Arrays;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.Map;
25 import java.util.Set;
26
27 import org.mortbay.log.Log;
28 import org.mortbay.util.ajax.JSON.Output;
29
30
31
32
33
34
35
36
37
38
39
40 public class JSONPojoConvertor implements JSON.Convertor
41 {
42
43 private static final Object[] __getterArg = new Object[]{};
44 private static final Map
45
46 public static NumberType getNumberType(Class clazz)
47 {
48 return (NumberType)__numberTypes.get(clazz);
49 }
50
51 protected boolean _fromJSON;
52 protected Class _pojoClass;
53 protected Map
54 protected Map
55 protected Set
56
57 public JSONPojoConvertor(Class pojoClass)
58 {
59 this(pojoClass, (Set)null, true);
60 }
61
62 public JSONPojoConvertor(Class pojoClass, String[] excluded)
63 {
64 this(pojoClass, new HashSet(Arrays.asList(excluded)), true);
65 }
66
67 public JSONPojoConvertor(Class pojoClass, Set excluded)
68 {
69 this(pojoClass, excluded, true);
70 }
71
72 public JSONPojoConvertor(Class pojoClass, Set excluded, boolean fromJSON)
73 {
74 _pojoClass = pojoClass;
75 _excluded = excluded;
76 _fromJSON = fromJSON;
77 init();
78 }
79
80 public JSONPojoConvertor(Class pojoClass, boolean fromJSON)
81 {
82 this(pojoClass, (Set)null, fromJSON);
83 }
84
85
86 protected void init()
87 {
88 Method[] methods = _pojoClass.getMethods();
89 for (int i=0;i<methods.length;i++)
90 {
91 Method m=methods[i];
92 if (!Modifier.isStatic(m.getModifiers()) && m.getDeclaringClass()!=Object.class)
93 {
94 String name=m.getName();
95 switch(m.getParameterTypes().length)
96 {
97 case 0:
98
99 if(m.getReturnType()!=null)
100 {
101 if (name.startsWith("is"))
102 name=name.substring(2,3).toLowerCase()+name.substring(3);
103 else if (name.startsWith("get"))
104 name=name.substring(3,4).toLowerCase()+name.substring(4);
105 else
106 break;
107 if(includeField(name, m))
108 _getters.put(name, m);
109 }
110 break;
111 case 1:
112 if (name.startsWith("set"))
113 {
114 name=name.substring(3,4).toLowerCase()+name.substring(4);
115 if(includeField(name, m))
116 _setters.put(name, new Setter(name, m));
117 }
118 break;
119 }
120 }
121 }
122 }
123
124
125 protected boolean includeField(String name, Method m)
126 {
127 return _excluded==null || !_excluded.contains(name);
128 }
129
130
131 protected int getExcludedCount()
132 {
133 return _excluded==null ? 0 : _excluded.size();
134 }
135
136
137 public Object fromJSON(Map object)
138 {
139 Object obj = null;
140 try
141 {
142 obj = _pojoClass.newInstance();
143 }
144 catch(Exception e)
145 {
146
147 throw new RuntimeException(e);
148 }
149
150 for(Iterator iterator = object.entrySet().iterator(); iterator.hasNext();)
151 {
152 Map.Entry entry = (Map.Entry)iterator.next();
153 Setter setter = (Setter)_setters.get(entry.getKey());
154 if(setter!=null)
155 {
156 try
157 {
158 setter.invoke(obj, entry.getValue());
159 }
160 catch(Exception e)
161 {
162
163 Log.warn("{} property '{}' not set. (errors)", _pojoClass.getName(),
164 setter.getPropertyName());
165 }
166 }
167 }
168
169 return obj;
170 }
171
172
173 public void toJSON(Object obj, Output out)
174 {
175 if(_fromJSON)
176 out.addClass(_pojoClass);
177 for(Iterator iterator = _getters.entrySet().iterator(); iterator.hasNext();)
178 {
179 Map.Entry entry = (Map.Entry)iterator.next();
180 try
181 {
182 out.add((String)entry.getKey(), ((Method)entry.getValue()).invoke(obj,
183 __getterArg));
184 }
185 catch(Exception e)
186 {
187
188 Log.warn("{} property '{}' excluded. (errors)", _pojoClass.getName(),
189 entry.getKey());
190 }
191 }
192 }
193
194 public static class Setter
195 {
196 private String _propertyName;
197 private Method _method;
198 private NumberType _numberType;
199
200 public Setter(String propertyName, Method method)
201 {
202 _propertyName = propertyName;
203 _method = method;
204 _numberType = (NumberType)__numberTypes.get(method.getParameterTypes()[0]);
205 }
206
207 public String getPropertyName()
208 {
209 return _propertyName;
210 }
211
212 public Method getMethod()
213 {
214 return _method;
215 }
216
217 public NumberType getNumberType()
218 {
219 return _numberType;
220 }
221
222 public boolean isPropertyNumber()
223 {
224 return _numberType!=null;
225 }
226
227 public void invoke(Object obj, Object value) throws IllegalArgumentException,
228 IllegalAccessException, InvocationTargetException
229 {
230 if(_numberType!=null && value instanceof Number)
231 _method.invoke(obj, new Object[]{_numberType.getActualValue((Number)value)});
232 else
233 _method.invoke(obj, new Object[]{value});
234 }
235 }
236
237 public interface NumberType
238 {
239 public Object getActualValue(Number number);
240 }
241
242 public static final NumberType SHORT = new NumberType()
243 {
244 public Object getActualValue(Number number)
245 {
246 return new Short(number.shortValue());
247 }
248 };
249
250 public static final NumberType INTEGER = new NumberType()
251 {
252 public Object getActualValue(Number number)
253 {
254 return new Integer(number.intValue());
255 }
256 };
257
258 public static final NumberType FLOAT = new NumberType()
259 {
260 public Object getActualValue(Number number)
261 {
262 return new Float(number.floatValue());
263 }
264 };
265
266 public static final NumberType LONG = new NumberType()
267 {
268 public Object getActualValue(Number number)
269 {
270 return number instanceof Long ? number : new Long(number.longValue());
271 }
272 };
273
274 public static final NumberType DOUBLE = new NumberType()
275 {
276 public Object getActualValue(Number number)
277 {
278 return number instanceof Double ? number : new Double(number.doubleValue());
279 }
280 };
281
282 static
283 {
284 __numberTypes.put(Short.class, SHORT);
285 __numberTypes.put(Short.TYPE, SHORT);
286 __numberTypes.put(Integer.class, INTEGER);
287 __numberTypes.put(Integer.TYPE, INTEGER);
288 __numberTypes.put(Long.class, LONG);
289 __numberTypes.put(Long.TYPE, LONG);
290 __numberTypes.put(Float.class, FLOAT);
291 __numberTypes.put(Float.TYPE, FLOAT);
292 __numberTypes.put(Double.class, DOUBLE);
293 __numberTypes.put(Double.TYPE, DOUBLE);
294 }
295 }