`
goon
  • 浏览: 181105 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

hessian——序列化

 
阅读更多

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

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics