@Override
 public OffHeapEmbeddedMetadata readObject(ObjectInput input)
     throws IOException, ClassNotFoundException {
   int number = input.readUnsignedByte();
   switch (number) {
     case IMMORTAL:
       return new OffHeapEmbeddedMetadata((EntryVersion) input.readObject());
     case EXPIRABLE:
       long lifespan = input.readLong();
       long maxIdle = input.readLong();
       EntryVersion version = (EntryVersion) input.readObject();
       return new OffHeapEmbeddedExpirableMetadata(
           lifespan, TimeUnit.MILLISECONDS, maxIdle, TimeUnit.MILLISECONDS, version);
     default:
       throw new IllegalStateException("Unknown metadata type " + number);
   }
 }
 @Override
 public Map readObject(ObjectInput input) throws IOException, ClassNotFoundException {
   int magicNumber = input.readUnsignedByte();
   Map subject = null;
   switch (magicNumber) {
     case HASHMAP:
       subject = new HashMap();
       break;
     case TREEMAP:
       subject = new TreeMap();
       break;
     case FASTCOPYHASHMAP:
       subject = new FastCopyHashMap();
       break;
   }
   MarshallUtil.unmarshallMap(subject, input);
   return subject;
 }
  @Override
  public Set readObject(ObjectInput input) throws IOException, ClassNotFoundException {
    int magicNumber = input.readUnsignedByte();
    if (magicNumber == UNKNOWN_ENUM_SET) return (Set) input.readObject();

    AbstractSet<Enum> enumSet = null;
    int size = UnsignedNumeric.readUnsignedInt(input);
    for (int i = 0; i < size; i++) {
      switch (magicNumber) {
        case ENUM_SET:
        case REGULAR_ENUM_SET:
        case JUMBO_ENUM_SET:
          if (i == 0) enumSet = EnumSet.of((Enum) input.readObject());
          else enumSet.add((Enum) input.readObject());
          break;
      }
    }

    return enumSet;
  }
  /**
   * Note the use of rawData: we reuse the array if the incoming array is the same length or smaller
   * than the array length.
   *
   * @see java.io.Externalizable#readExternal
   */
  public void readExternal(ObjectInput in) throws IOException {
    // clear the previous value to ensure that the
    // rawData value will be used
    value = null;

    rawScale = in.readUnsignedByte();
    int size = in.readUnsignedByte();

    /*
    ** Allocate a new array if the data to read
    ** is larger than the existing array, or if
    ** we don't have an array yet.

          Need to use readFully below and NOT just read because read does not
          guarantee getting size bytes back, whereas readFully does (unless EOF).
          */
    if ((rawData == null) || size != rawData.length) {
      rawData = new byte[size];
    }
    in.readFully(rawData);
  }