hessian——シーケンス化
12453 ワード
メソッドが返すタイプがimplement javaでない場合.io.Serializableの場合、throw exception;
理由:SerializerFactoryでは、次の方法があります.
そのうち_isAllowNonSerializableのデフォルトはfalseです.もし戻るタイプがimplement javaしたくないなら.io.Serializableはどうしますか?
SerializerFactoryのコードは変更されていません.isAllowNonSerializableの値、つまりwebを通過できません.xmlでの設定でこのスイッチを設定したので、自分でHessianServeretを継承したservletしか使えなくなり、カスタムservletでSerializerFactoryの_isAllowNonSerializable値をtrueに変更します.
public boolean isAllowNonSerializable()
{
return _isAllowNonSerializable;
}
isAllowNonSerializable()が呼び出された場合、オブジェクトに呼び出されていないことがわかります.説明_isAllowNonSerializableはgetDefaultSerializer()メソッドでのみ機能し、hessianのシーケンス化とjavaについても別の側面から説明する.io.Serializableは関係なく、ただ一つの_isAllowNonSerializableのスイッチだけで、hessianは自分のシリアル番号方式を実現しました.
Hessian2Output.java:
UnsafeSerializer.java:
基本タイプ対応BasicSerializerのserializer(out,obj)メソッド:
基本的なタイプをoutがどのように書くかを見てみましょう.
可視項目bufferにデータを書く前に、すべて判断します.offsetは大文字で、十分大きい場合はflushBufferです.
理由: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はどうしますか?
SerializerFactoryのコードは変更されていません.isAllowNonSerializableの値、つまりwebを通過できません.xmlでの設定でこのスイッチを設定したので、自分でHessianServeretを継承した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() + "
class: "
+ obj.getClass().getName()
+ " (object=" + obj + ")",
e);
} catch (IOException e) {
throw new IOExceptionWrapper(e.getMessage() + "
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() + "
field: " + _field.getDeclaringClass().getName() + '.' + _field.getName(), e); } catch (IOException e) { throw new IOExceptionWrapper(e.getMessage() + "
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です.