当方法返回的类型未implement java.io.Serializable时,会throw exception;
原因: SerializerFactory中以下方法:
/** * Returns the default serializer for a class that isn't matched * directly. Application can override this method to produce * bean-style serialization instead of field serialization. * * @param cl the class of the object that needs to be serialized. * * @return a serializer object for the serialization. */ protected Serializer getDefaultSerializer(Class cl) { if (_defaultSerializer != null) return _defaultSerializer; if (! Serializable.class.isAssignableFrom(cl) && ! _isAllowNonSerializable) { throw new IllegalStateException("Serialized class " + cl.getName() + " must implement java.io.Serializable"); } if (_isEnableUnsafeSerializer && JavaSerializer.getWriteReplace(cl) == null) { return UnsafeSerializer.create(cl); } else return JavaSerializer.create(cl); }
其中_isAllowNonSerializable默认为false。那如果返回的类型不想implement java.io.Serializable 怎么办呢?
查看HessianServlet中的代码,没有修改SerializerFactory的_isAllowNonSerializable的值,也就是不能通过web.xml中的配置来设置这个开关了,所以只能使用自己继承HessianServlet的servlet了,然后在自定义的servlet中把SerializerFactory的_isAllowNonSerializable值改为true;
public boolean isAllowNonSerializable()
{
return _isAllowNonSerializable;
}
再看看isAllowNonSerializable()被调用的情况,发现没有被任何对象调用,说明_isAllowNonSerializable只会在getDefaultSerializer()方法中起作用,也从另一方面说明hessian的序列化跟java.io.Serializable无关,只是有个_isAllowNonSerializable的开关而已,hessian实现了自己的序列号方式:
Hessian2Output.java:
/** * Writes any object to the output stream. */ public void writeObject(Object object) throws IOException { if (object == null) { writeNull(); return; } Serializer serializer = findSerializerFactory().getObjectSerializer(object.getClass()); serializer.writeObject(object, this); }
UnsafeSerializer.java:
public void writeObject(Object obj, AbstractHessianOutput out) throws IOException { if (out.addRef(obj)) { return; } Class<?> cl = obj.getClass(); int ref = out.writeObjectBegin(cl.getName()); if (ref >= 0) { writeInstance(obj, out); } else if (ref == -1) { writeDefinition20(out); out.writeObjectBegin(cl.getName()); writeInstance(obj, out); } else { writeObject10(obj, out); } } final public void writeInstance(Object obj, AbstractHessianOutput out) throws IOException { try { FieldSerializer []fieldSerializers = _fieldSerializers; int length = fieldSerializers.length; for (int i = 0; i < length; i++) { fieldSerializers[i].serialize(out, obj); //序列化方法返回结果到输出流 } } catch (RuntimeException e) { throw new RuntimeException(e.getMessage() + "\n class: " + obj.getClass().getName() + " (object=" + obj + ")", e); } catch (IOException e) { throw new IOExceptionWrapper(e.getMessage() + "\n class: " + obj.getClass().getName() + " (object=" + obj + ")", e); } } @Override final void serialize(AbstractHessianOutput out, Object obj) throws IOException { try { Object value = _unsafe.getObject(obj, _offset); //获取obj对象中的属性值 out.writeObject(value);//把属性值写入out,由于属性值是基本类型(比如:字符串),则writeObject会调用字符串相应的serializer(BasicSerializer)的serialize(out, obj)方法(见后面)
} catch (RuntimeException e) { throw new RuntimeException(e.getMessage() + "\n field: " + _field.getDeclaringClass().getName() + '.' + _field.getName(), e); } catch (IOException e) { throw new IOExceptionWrapper(e.getMessage() + "\n field: " + _field.getDeclaringClass().getName() + '.' + _field.getName(), e); } }
基本类型对应的BasicSerializer的serializer(out,obj)方法:
public void writeObject(Object obj, AbstractHessianOutput out) throws IOException { switch (_code) { case BOOLEAN: out.writeBoolean(((Boolean) obj).booleanValue()); break; case BYTE: case SHORT: case INTEGER: out.writeInt(((Number) obj).intValue()); break; case LONG: out.writeLong(((Number) obj).longValue()); break; case FLOAT: case DOUBLE: out.writeDouble(((Number) obj).doubleValue()); break; case CHARACTER: case CHARACTER_OBJECT: out.writeString(String.valueOf(obj)); break; case STRING: out.writeString((String) obj); break; case DATE: out.writeUTCDate(((Date) obj).getTime()); break; case BOOLEAN_ARRAY: { if (out.addRef(obj)) return; boolean []data = (boolean []) obj; boolean hasEnd = out.writeListBegin(data.length, "[boolean"); for (int i = 0; i < data.length; i++) out.writeBoolean(data[i]); if (hasEnd) out.writeListEnd(); break; } case BYTE_ARRAY: { byte []data = (byte []) obj; out.writeBytes(data, 0, data.length); break; } case SHORT_ARRAY: { if (out.addRef(obj)) return; short []data = (short []) obj; boolean hasEnd = out.writeListBegin(data.length, "[short"); for (int i = 0; i < data.length; i++) out.writeInt(data[i]); if (hasEnd) out.writeListEnd(); break; } case INTEGER_ARRAY: { if (out.addRef(obj)) return; int []data = (int []) obj; boolean hasEnd = out.writeListBegin(data.length, "[int"); for (int i = 0; i < data.length; i++) out.writeInt(data[i]); if (hasEnd) out.writeListEnd(); break; } case LONG_ARRAY: { if (out.addRef(obj)) return; long []data = (long []) obj; boolean hasEnd = out.writeListBegin(data.length, "[long"); for (int i = 0; i < data.length; i++) out.writeLong(data[i]); if (hasEnd) out.writeListEnd(); break; } case FLOAT_ARRAY: { if (out.addRef(obj)) return; float []data = (float []) obj; boolean hasEnd = out.writeListBegin(data.length, "[float"); for (int i = 0; i < data.length; i++) out.writeDouble(data[i]); if (hasEnd) out.writeListEnd(); break; } case DOUBLE_ARRAY: { if (out.addRef(obj)) return; double []data = (double []) obj; boolean hasEnd = out.writeListBegin(data.length, "[double"); for (int i = 0; i < data.length; i++) out.writeDouble(data[i]); if (hasEnd) out.writeListEnd(); break; } case STRING_ARRAY: { if (out.addRef(obj)) return; String []data = (String []) obj; boolean hasEnd = out.writeListBegin(data.length, "[string"); for (int i = 0; i < data.length; i++) { out.writeString(data[i]); } if (hasEnd) out.writeListEnd(); break; } case CHARACTER_ARRAY: { char []data = (char []) obj; out.writeString(data, 0, data.length); break; } case OBJECT_ARRAY: { if (out.addRef(obj)) return; Object []data = (Object []) obj; boolean hasEnd = out.writeListBegin(data.length, "[object"); for (int i = 0; i < data.length; i++) { out.writeObject(data[i]); } if (hasEnd) out.writeListEnd(); break; } case NULL: out.writeNull(); break; case OBJECT: ObjectHandleSerializer.SER.writeObject(obj, out); break; case BYTE_HANDLE: out.writeObject(new ByteHandle((Byte) obj)); break; case SHORT_HANDLE: out.writeObject(new ShortHandle((Short) obj)); break; case FLOAT_HANDLE: out.writeObject(new FloatHandle((Float) obj)); break; default: throw new RuntimeException(_code + " unknown code for " + obj.getClass()); } }
再看看out怎么写基本类型的:
public void writeBoolean(boolean value) throws IOException { if (SIZE < _offset + 16) flushBuffer(); if (value) _buffer[_offset++] = (byte) 'T'; else _buffer[_offset++] = (byte) 'F'; } public void writeInt(int value) throws IOException { int offset = _offset; byte []buffer = _buffer; if (SIZE <= offset + 16) { flushBuffer(); offset = _offset; } if (INT_DIRECT_MIN <= value && value <= INT_DIRECT_MAX) buffer[offset++] = (byte) (value + BC_INT_ZERO); else if (INT_BYTE_MIN <= value && value <= INT_BYTE_MAX) { buffer[offset++] = (byte) (BC_INT_BYTE_ZERO + (value >> 8)); buffer[offset++] = (byte) (value); } else if (INT_SHORT_MIN <= value && value <= INT_SHORT_MAX) { buffer[offset++] = (byte) (BC_INT_SHORT_ZERO + (value >> 16)); buffer[offset++] = (byte) (value >> 8); buffer[offset++] = (byte) (value); } else { buffer[offset++] = (byte) ('I'); buffer[offset++] = (byte) (value >> 24); buffer[offset++] = (byte) (value >> 16); buffer[offset++] = (byte) (value >> 8); buffer[offset++] = (byte) (value); } _offset = offset; } public final void flushBuffer() throws IOException { int offset = _offset; OutputStream os = _os; if (! _isPacket && offset > 0) { _offset = 0; if (os != null) os.write(_buffer, 0, offset); } else if (_isPacket && offset > 3) { int len = offset - 3; _buffer[0] = (byte) 0x80; _buffer[1] = (byte) (0x80 + ((len >> 7) & 0x7f)); _buffer[2] = (byte) (len & 0x7f); _offset = 3; if (os != null) os.write(_buffer, 0, offset); _buffer[0] = (byte) 0x56; _buffer[1] = (byte) 0x56; _buffer[2] = (byte) 0x56; } } public final static int SIZE = 4096;
可见项buffer中写数据前,都会判断_offset大写,如果足够大,则flushBuffer。