欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

hessian——序列化

程序员文章站 2024-03-24 11:59:28
...

当方法返回的类型未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。