1 | // Copyright 2004-2007 Jean-Francois Poilpret |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | // Original Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved. |
16 | // The Apache Software License, Version 1.1 |
17 | |
18 | package net.sourceforge.hiveremoting.caucho; |
19 | |
20 | import java.io.IOException; |
21 | import java.lang.reflect.Field; |
22 | import java.lang.reflect.Method; |
23 | import java.lang.reflect.Modifier; |
24 | import java.util.ArrayList; |
25 | import java.util.List; |
26 | import java.util.logging.Level; |
27 | import java.util.logging.Logger; |
28 | |
29 | import com.caucho.hessian.io.AbstractHessianOutput; |
30 | import com.caucho.hessian.io.AbstractSerializer; |
31 | |
32 | /** |
33 | * Serializing an object for known object types. |
34 | */ |
35 | public class NonSerializableClassSerializer extends AbstractSerializer |
36 | { |
37 | private static final Logger _log = |
38 | Logger.getLogger(NonSerializableClassSerializer.class.getName()); |
39 | |
40 | public NonSerializableClassSerializer(Class cl) |
41 | { |
42 | _writeReplace = getWriteReplace(cl); |
43 | if (_writeReplace != null) |
44 | { |
45 | _writeReplace.setAccessible(true); |
46 | } |
47 | |
48 | List<Field> primitiveFields = new ArrayList<Field>(); |
49 | List<Field> compoundFields = new ArrayList<Field>(); |
50 | for (; cl != null; cl = cl.getSuperclass()) |
51 | { |
52 | Field[] fields = cl.getDeclaredFields(); |
53 | for (int i = 0; i < fields.length; i++) |
54 | { |
55 | Field field = fields[i]; |
56 | |
57 | if ( Modifier.isTransient(field.getModifiers()) |
58 | || Modifier.isStatic(field.getModifiers())) |
59 | { |
60 | continue; |
61 | } |
62 | // XXX: could parameterize the handler to only deal with public |
63 | field.setAccessible(true); |
64 | |
65 | if ( field.getType().isPrimitive() |
66 | || field.getType().getName().startsWith("java.lang.") |
67 | && !field.getType().equals(Object.class)) |
68 | { |
69 | primitiveFields.add(field); |
70 | } |
71 | else |
72 | { |
73 | compoundFields.add(field); |
74 | } |
75 | } |
76 | } |
77 | |
78 | List<Field> fields = new ArrayList<Field>(); |
79 | fields.addAll(primitiveFields); |
80 | fields.addAll(compoundFields); |
81 | _fields = new Field[fields.size()]; |
82 | fields.toArray(_fields); |
83 | _fieldSerializers = new FieldSerializer[_fields.length]; |
84 | for (int i = 0; i < _fields.length; i++) |
85 | { |
86 | _fieldSerializers[i] = getFieldSerializer(_fields[i].getType()); |
87 | } |
88 | } |
89 | |
90 | /** |
91 | * Returns the writeReplace method |
92 | */ |
93 | protected Method getWriteReplace(Class cl) |
94 | { |
95 | for (; cl != null; cl = cl.getSuperclass()) |
96 | { |
97 | Method[] methods = cl.getDeclaredMethods(); |
98 | for (int i = 0; i < methods.length; i++) |
99 | { |
100 | Method method = methods[i]; |
101 | if ( method.getName().equals("writeReplace") |
102 | && method.getParameterTypes().length == 0) |
103 | { |
104 | return method; |
105 | } |
106 | } |
107 | } |
108 | return null; |
109 | } |
110 | |
111 | @Override public void writeObject(Object obj, AbstractHessianOutput out) |
112 | throws IOException |
113 | { |
114 | if (out.addRef(obj)) |
115 | { |
116 | return; |
117 | } |
118 | |
119 | Class cl = obj.getClass(); |
120 | // CSOFF: IllegalCatchCheck |
121 | try |
122 | { |
123 | if (_writeReplace != null) |
124 | { |
125 | Object repl = _writeReplace.invoke(obj, new Object[0]); |
126 | out.removeRef(obj); |
127 | out.writeObject(repl); |
128 | out.replaceRef(repl, obj); |
129 | return; |
130 | } |
131 | } |
132 | catch (Exception e) |
133 | { |
134 | _log.log(Level.FINE, e.toString(), e); |
135 | } |
136 | // CSON: IllegalCatchCheck |
137 | |
138 | int ref = out.writeObjectBegin(cl.getName()); |
139 | if (ref < 0) |
140 | { |
141 | writeObject10(obj, out); |
142 | } |
143 | else |
144 | { |
145 | if (ref == 0) |
146 | { |
147 | writeDefinition20(out); |
148 | } |
149 | writeInstance(obj, out); |
150 | } |
151 | } |
152 | |
153 | private void writeObject10(Object obj, AbstractHessianOutput out) |
154 | throws IOException |
155 | { |
156 | for (int i = 0; i < _fields.length; i++) |
157 | { |
158 | Field field = _fields[i]; |
159 | out.writeString(field.getName()); |
160 | _fieldSerializers[i].serialize(out, obj, field); |
161 | } |
162 | out.writeMapEnd(); |
163 | } |
164 | |
165 | private void writeDefinition20(AbstractHessianOutput out) |
166 | throws IOException |
167 | { |
168 | out.writeClassFieldLength(_fields.length); |
169 | for (int i = 0; i < _fields.length; i++) |
170 | { |
171 | Field field = _fields[i]; |
172 | out.writeString(field.getName()); |
173 | } |
174 | } |
175 | |
176 | public void writeInstance(Object obj, AbstractHessianOutput out) |
177 | throws IOException |
178 | { |
179 | for (int i = 0; i < _fields.length; i++) |
180 | { |
181 | Field field = _fields[i]; |
182 | _fieldSerializers[i].serialize(out, obj, field); |
183 | } |
184 | } |
185 | |
186 | private static FieldSerializer getFieldSerializer(Class type) |
187 | { |
188 | if ( int.class.equals(type) |
189 | || byte.class.equals(type) |
190 | || short.class.equals(type) |
191 | || int.class.equals(type)) |
192 | { |
193 | return IntFieldSerializer.SER; |
194 | } |
195 | else if (long.class.equals(type)) |
196 | { |
197 | return LongFieldSerializer.SER; |
198 | } |
199 | else if ( double.class.equals(type) |
200 | || float.class.equals(type)) |
201 | { |
202 | return DoubleFieldSerializer.SER; |
203 | } |
204 | else if (boolean.class.equals(type)) |
205 | { |
206 | return BooleanFieldSerializer.SER; |
207 | } |
208 | else if (String.class.equals(type)) |
209 | { |
210 | return StringFieldSerializer.SER; |
211 | } |
212 | else |
213 | { |
214 | return FieldSerializer.SER; |
215 | } |
216 | } |
217 | |
218 | static class FieldSerializer |
219 | { |
220 | static final FieldSerializer SER = new FieldSerializer(); |
221 | |
222 | void serialize(AbstractHessianOutput out, Object obj, Field field) |
223 | throws IOException |
224 | { |
225 | Object value = null; |
226 | try |
227 | { |
228 | value = field.get(obj); |
229 | } |
230 | catch (IllegalAccessException e) |
231 | { |
232 | _log.log(Level.FINE, e.toString(), e); |
233 | } |
234 | out.writeObject(value); |
235 | } |
236 | } |
237 | |
238 | static class BooleanFieldSerializer extends FieldSerializer |
239 | { |
240 | static final FieldSerializer SER = new BooleanFieldSerializer(); |
241 | |
242 | @Override void serialize(AbstractHessianOutput out, Object obj, Field field) |
243 | throws IOException |
244 | { |
245 | boolean value = false; |
246 | try |
247 | { |
248 | value = field.getBoolean(obj); |
249 | } |
250 | catch (IllegalAccessException e) |
251 | { |
252 | _log.log(Level.FINE, e.toString(), e); |
253 | } |
254 | out.writeBoolean(value); |
255 | } |
256 | } |
257 | |
258 | static class IntFieldSerializer extends FieldSerializer |
259 | { |
260 | static final FieldSerializer SER = new IntFieldSerializer(); |
261 | |
262 | @Override void serialize(AbstractHessianOutput out, Object obj, Field field) |
263 | throws IOException |
264 | { |
265 | int value = 0; |
266 | try |
267 | { |
268 | value = field.getInt(obj); |
269 | } |
270 | catch (IllegalAccessException e) |
271 | { |
272 | _log.log(Level.FINE, e.toString(), e); |
273 | } |
274 | out.writeInt(value); |
275 | } |
276 | } |
277 | |
278 | static class LongFieldSerializer extends FieldSerializer |
279 | { |
280 | static final FieldSerializer SER = new LongFieldSerializer(); |
281 | |
282 | @Override void serialize(AbstractHessianOutput out, Object obj, Field field) |
283 | throws IOException |
284 | { |
285 | long value = 0; |
286 | try |
287 | { |
288 | value = field.getLong(obj); |
289 | } |
290 | catch (IllegalAccessException e) |
291 | { |
292 | _log.log(Level.FINE, e.toString(), e); |
293 | } |
294 | out.writeLong(value); |
295 | } |
296 | } |
297 | |
298 | static class DoubleFieldSerializer extends FieldSerializer |
299 | { |
300 | static final FieldSerializer SER = new DoubleFieldSerializer(); |
301 | |
302 | @Override void serialize(AbstractHessianOutput out, Object obj, Field field) |
303 | throws IOException |
304 | { |
305 | double value = 0; |
306 | try |
307 | { |
308 | value = field.getDouble(obj); |
309 | } |
310 | catch (IllegalAccessException e) |
311 | { |
312 | _log.log(Level.FINE, e.toString(), e); |
313 | } |
314 | out.writeDouble(value); |
315 | } |
316 | } |
317 | |
318 | static class StringFieldSerializer extends FieldSerializer |
319 | { |
320 | static final FieldSerializer SER = new StringFieldSerializer(); |
321 | |
322 | @Override void serialize(AbstractHessianOutput out, Object obj, Field field) |
323 | throws IOException |
324 | { |
325 | String value = null; |
326 | try |
327 | { |
328 | value = (String) field.get(obj); |
329 | } |
330 | catch (IllegalAccessException e) |
331 | { |
332 | _log.log(Level.FINE, e.toString(), e); |
333 | } |
334 | out.writeString(value); |
335 | } |
336 | } |
337 | |
338 | private Field[] _fields; |
339 | private FieldSerializer[] _fieldSerializers; |
340 | private Method _writeReplace; |
341 | } |