hessian——シーケンス化

12453 ワード

メソッドが返すタイプが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はどうしますか?
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(BasicSerializerserialize(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です.