001: /*
002: * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
003: *
004: * The Apache Software License, Version 1.1
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution, if
019: * any, must include the following acknowlegement:
020: * "This product includes software developed by the
021: * Caucho Technology (http://www.caucho.com/)."
022: * Alternately, this acknowlegement may appear in the software itself,
023: * if and wherever such third-party acknowlegements normally appear.
024: *
025: * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
026: * endorse or promote products derived from this software without prior
027: * written permission. For written permission, please contact
028: * info@caucho.com.
029: *
030: * 5. Products derived from this software may not be called "Resin"
031: * nor may "Resin" appear in their names without prior written
032: * permission of Caucho Technology.
033: *
034: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
035: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
036: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
037: * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
038: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
039: * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
040: * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
041: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
042: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
043: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
044: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
045: *
046: * @author Scott Ferguson
047: */
048:
049: package com.caucho.hessian.io;
050:
051: import java.io.IOException;
052: import java.lang.reflect.Constructor;
053: import java.lang.reflect.Field;
054: import java.lang.reflect.InvocationTargetException;
055: import java.lang.reflect.Method;
056: import java.lang.reflect.Modifier;
057: import java.util.HashMap;
058:
059: import java.util.logging.*;
060:
061: /**
062: * Serializing an object for known object types.
063: */
064: public class JavaDeserializer extends AbstractMapDeserializer {
065: private static final Logger log = Logger
066: .getLogger(JavaDeserializer.class.getName());
067:
068: private Class _type;
069: private HashMap _fieldMap;
070: private Method _readResolve;
071: private Constructor _constructor;
072: private Object[] _constructorArgs;
073:
074: public JavaDeserializer(Class cl) {
075: _type = cl;
076: _fieldMap = getFieldMap(cl);
077:
078: _readResolve = getReadResolve(cl);
079:
080: if (_readResolve != null) {
081: _readResolve.setAccessible(true);
082: }
083:
084: Constructor[] constructors = cl.getDeclaredConstructors();
085: long bestCost = Long.MAX_VALUE;
086:
087: for (int i = 0; i < constructors.length; i++) {
088: Class[] param = constructors[i].getParameterTypes();
089: long cost = 0;
090:
091: for (int j = 0; j < param.length; j++) {
092: cost = 4 * cost;
093:
094: if (Object.class.equals(param[j]))
095: cost += 1;
096: else if (String.class.equals(param[j]))
097: cost += 2;
098: else if (int.class.equals(param[j]))
099: cost += 3;
100: else if (long.class.equals(param[j]))
101: cost += 4;
102: else if (param[j].isPrimitive())
103: cost += 5;
104: else
105: cost += 6;
106: }
107:
108: if (cost < 0 || cost > (1 << 48))
109: cost = 1 << 48;
110:
111: cost += param.length << 48;
112:
113: if (cost < bestCost) {
114: _constructor = constructors[i];
115: bestCost = cost;
116: }
117: }
118:
119: if (_constructor != null) {
120: _constructor.setAccessible(true);
121: Class[] params = _constructor.getParameterTypes();
122: _constructorArgs = new Object[params.length];
123: for (int i = 0; i < params.length; i++) {
124: _constructorArgs[i] = getParamArg(params[i]);
125: }
126: }
127: }
128:
129: public Class getType() {
130: return _type;
131: }
132:
133: public Object readMap(AbstractHessianInput in) throws IOException {
134: try {
135: Object obj = instantiate();
136:
137: return readMap(in, obj);
138: } catch (IOException e) {
139: throw e;
140: } catch (RuntimeException e) {
141: throw e;
142: } catch (Exception e) {
143: throw new IOExceptionWrapper(_type.getName() + ":"
144: + e.getMessage(), e);
145: }
146: }
147:
148: public Object readObject(AbstractHessianInput in,
149: String[] fieldNames) throws IOException {
150: try {
151: Object obj = instantiate();
152:
153: return readObject(in, obj, fieldNames);
154: } catch (IOException e) {
155: throw e;
156: } catch (RuntimeException e) {
157: throw e;
158: } catch (Exception e) {
159: throw new IOExceptionWrapper(_type.getName() + ":"
160: + e.getMessage(), e);
161: }
162: }
163:
164: /**
165: * Returns the readResolve method
166: */
167: protected Method getReadResolve(Class cl) {
168: for (; cl != null; cl = cl.getSuperclass()) {
169: Method[] methods = cl.getDeclaredMethods();
170:
171: for (int i = 0; i < methods.length; i++) {
172: Method method = methods[i];
173:
174: if (method.getName().equals("readResolve")
175: && method.getParameterTypes().length == 0)
176: return method;
177: }
178: }
179:
180: return null;
181: }
182:
183: public Object readMap(AbstractHessianInput in, Object obj)
184: throws IOException {
185: try {
186: int ref = in.addRef(obj);
187:
188: while (!in.isEnd()) {
189: Object key = in.readObject();
190:
191: FieldDeserializer deser = (FieldDeserializer) _fieldMap
192: .get(key);
193:
194: if (deser != null)
195: deser.deserialize(in, obj);
196: else
197: in.readObject();
198: }
199:
200: in.readMapEnd();
201:
202: Object resolve = resolve(obj);
203:
204: if (obj != resolve)
205: in.setRef(ref, resolve);
206:
207: return resolve;
208: } catch (IOException e) {
209: throw e;
210: } catch (Exception e) {
211: throw new IOExceptionWrapper(e);
212: }
213: }
214:
215: public Object readObject(AbstractHessianInput in, Object obj,
216: String[] fieldNames) throws IOException {
217: try {
218: int ref = in.addRef(obj);
219:
220: for (int i = 0; i < fieldNames.length; i++) {
221: String name = fieldNames[i];
222:
223: FieldDeserializer deser = (FieldDeserializer) _fieldMap
224: .get(name);
225:
226: if (deser != null)
227: deser.deserialize(in, obj);
228: else
229: in.readObject();
230: }
231:
232: Object resolve = resolve(obj);
233:
234: if (obj != resolve)
235: in.setRef(ref, resolve);
236:
237: return resolve;
238: } catch (IOException e) {
239: throw e;
240: } catch (Exception e) {
241: throw new IOExceptionWrapper(obj.getClass().getName() + ":"
242: + e, e);
243: }
244: }
245:
246: private Object resolve(Object obj) throws Exception {
247: // if there's a readResolve method, call it
248: try {
249: if (_readResolve != null)
250: return _readResolve.invoke(obj, new Object[0]);
251: } catch (InvocationTargetException e) {
252: if (e.getTargetException() != null)
253: throw e;
254: }
255:
256: return obj;
257: }
258:
259: protected Object instantiate() throws Exception {
260: try {
261: if (_constructor != null)
262: return _constructor.newInstance(_constructorArgs);
263: else
264: return _type.newInstance();
265: } catch (Exception e) {
266: throw new HessianProtocolException("'" + _type.getName()
267: + "' could not be instantiated", e);
268: }
269: }
270:
271: /**
272: * Creates a map of the classes fields.
273: */
274: protected HashMap getFieldMap(Class cl) {
275: HashMap fieldMap = new HashMap();
276:
277: for (; cl != null; cl = cl.getSuperclass()) {
278: Field[] fields = cl.getDeclaredFields();
279: for (int i = 0; i < fields.length; i++) {
280: Field field = fields[i];
281:
282: if (Modifier.isTransient(field.getModifiers())
283: || Modifier.isStatic(field.getModifiers()))
284: continue;
285: else if (fieldMap.get(field.getName()) != null)
286: continue;
287:
288: // XXX: could parameterize the handler to only deal with public
289: try {
290: field.setAccessible(true);
291: } catch (Throwable e) {
292: e.printStackTrace();
293: }
294:
295: Class type = field.getType();
296: FieldDeserializer deser;
297:
298: if (String.class.equals(type))
299: deser = new StringFieldDeserializer(field);
300: else if (byte.class.equals(type)) {
301: deser = new ByteFieldDeserializer(field);
302: } else if (short.class.equals(type)) {
303: deser = new ShortFieldDeserializer(field);
304: } else if (int.class.equals(type)) {
305: deser = new IntFieldDeserializer(field);
306: } else if (long.class.equals(type)) {
307: deser = new LongFieldDeserializer(field);
308: } else if (float.class.equals(type)) {
309: deser = new FloatFieldDeserializer(field);
310: } else if (double.class.equals(type)) {
311: deser = new DoubleFieldDeserializer(field);
312: } else if (boolean.class.equals(type)) {
313: deser = new BooleanFieldDeserializer(field);
314: } else {
315: deser = new ObjectFieldDeserializer(field);
316: }
317:
318: fieldMap.put(field.getName(), deser);
319: }
320: }
321:
322: return fieldMap;
323: }
324:
325: /**
326: * Creates a map of the classes fields.
327: */
328: protected static Object getParamArg(Class cl) {
329: if (!cl.isPrimitive())
330: return null;
331: else if (boolean.class.equals(cl))
332: return Boolean.FALSE;
333: else if (byte.class.equals(cl))
334: return new Byte((byte) 0);
335: else if (short.class.equals(cl))
336: return new Short((short) 0);
337: else if (char.class.equals(cl))
338: return new Character((char) 0);
339: else if (int.class.equals(cl))
340: return Integer.valueOf(0);
341: else if (long.class.equals(cl))
342: return Long.valueOf(0);
343: else if (float.class.equals(cl))
344: return Float.valueOf(0);
345: else if (double.class.equals(cl))
346: return Double.valueOf(0);
347: else
348: throw new UnsupportedOperationException();
349: }
350:
351: abstract static class FieldDeserializer {
352: abstract void deserialize(AbstractHessianInput in, Object obj)
353: throws IOException;
354: }
355:
356: static class ObjectFieldDeserializer extends FieldDeserializer {
357: private final Field _field;
358:
359: ObjectFieldDeserializer(Field field) {
360: _field = field;
361: }
362:
363: void deserialize(AbstractHessianInput in, Object obj)
364: throws IOException {
365: Object value = null;
366:
367: try {
368: value = in.readObject(_field.getType());
369:
370: _field.set(obj, value);
371: } catch (Exception e) {
372: logDeserializeError(_field, obj, value, e);
373: }
374: }
375: }
376:
377: static class BooleanFieldDeserializer extends FieldDeserializer {
378: private final Field _field;
379:
380: BooleanFieldDeserializer(Field field) {
381: _field = field;
382: }
383:
384: void deserialize(AbstractHessianInput in, Object obj)
385: throws IOException {
386: boolean value = false;
387:
388: try {
389: value = in.readBoolean();
390:
391: _field.setBoolean(obj, value);
392: } catch (Exception e) {
393: logDeserializeError(_field, obj, value, e);
394: }
395: }
396: }
397:
398: static class ByteFieldDeserializer extends FieldDeserializer {
399: private final Field _field;
400:
401: ByteFieldDeserializer(Field field) {
402: _field = field;
403: }
404:
405: void deserialize(AbstractHessianInput in, Object obj)
406: throws IOException {
407: int value = 0;
408:
409: try {
410: value = in.readInt();
411:
412: _field.setByte(obj, (byte) value);
413: } catch (Exception e) {
414: logDeserializeError(_field, obj, value, e);
415: }
416: }
417: }
418:
419: static class ShortFieldDeserializer extends FieldDeserializer {
420: private final Field _field;
421:
422: ShortFieldDeserializer(Field field) {
423: _field = field;
424: }
425:
426: void deserialize(AbstractHessianInput in, Object obj)
427: throws IOException {
428: int value = 0;
429:
430: try {
431: value = in.readInt();
432:
433: _field.setShort(obj, (short) value);
434: } catch (Exception e) {
435: logDeserializeError(_field, obj, value, e);
436: }
437: }
438: }
439:
440: static class IntFieldDeserializer extends FieldDeserializer {
441: private final Field _field;
442:
443: IntFieldDeserializer(Field field) {
444: _field = field;
445: }
446:
447: void deserialize(AbstractHessianInput in, Object obj)
448: throws IOException {
449: int value = 0;
450:
451: try {
452: value = in.readInt();
453:
454: _field.setInt(obj, value);
455: } catch (Exception e) {
456: logDeserializeError(_field, obj, value, e);
457: }
458: }
459: }
460:
461: static class LongFieldDeserializer extends FieldDeserializer {
462: private final Field _field;
463:
464: LongFieldDeserializer(Field field) {
465: _field = field;
466: }
467:
468: void deserialize(AbstractHessianInput in, Object obj)
469: throws IOException {
470: long value = 0;
471:
472: try {
473: value = in.readLong();
474:
475: _field.setLong(obj, value);
476: } catch (Exception e) {
477: logDeserializeError(_field, obj, value, e);
478: }
479: }
480: }
481:
482: static class FloatFieldDeserializer extends FieldDeserializer {
483: private final Field _field;
484:
485: FloatFieldDeserializer(Field field) {
486: _field = field;
487: }
488:
489: void deserialize(AbstractHessianInput in, Object obj)
490: throws IOException {
491: double value = 0;
492:
493: try {
494: value = in.readDouble();
495:
496: _field.setFloat(obj, (float) value);
497: } catch (Exception e) {
498: logDeserializeError(_field, obj, value, e);
499: }
500: }
501: }
502:
503: static class DoubleFieldDeserializer extends FieldDeserializer {
504: private final Field _field;
505:
506: DoubleFieldDeserializer(Field field) {
507: _field = field;
508: }
509:
510: void deserialize(AbstractHessianInput in, Object obj)
511: throws IOException {
512: double value = 0;
513:
514: try {
515: value = in.readDouble();
516:
517: _field.setDouble(obj, value);
518: } catch (Exception e) {
519: logDeserializeError(_field, obj, value, e);
520: }
521: }
522: }
523:
524: static class StringFieldDeserializer extends FieldDeserializer {
525: private final Field _field;
526:
527: StringFieldDeserializer(Field field) {
528: _field = field;
529: }
530:
531: void deserialize(AbstractHessianInput in, Object obj)
532: throws IOException {
533: String value = null;
534:
535: try {
536: value = in.readString();
537:
538: _field.set(obj, value);
539: } catch (Exception e) {
540: logDeserializeError(_field, obj, value, e);
541: }
542: }
543: }
544:
545: static void logDeserializeError(Field field, Object obj,
546: Object value, Throwable e) throws IOException {
547: String fieldName = (field.getDeclaringClass().getName() + "." + field
548: .getName());
549:
550: if (e instanceof HessianFieldException)
551: throw (HessianFieldException) e;
552: else if (e instanceof IOException)
553: throw new HessianFieldException(fieldName + ": "
554: + e.getMessage(), e);
555:
556: if (value != null)
557: throw new HessianFieldException(fieldName + ": "
558: + value.getClass().getName() + " (" + value + ")"
559: + " cannot be assigned to '"
560: + field.getType().getName() + "'");
561: else
562: throw new HessianFieldException(fieldName + ": "
563: + field.getType().getName()
564: + " cannot be assigned from null", e);
565: }
566: }
|