public void defaultWriteObject(Object toWrite, FSTClazzInfo serializationInfo)
     throws IOException {
   if (serializationInfo.isExternalizable()) {
     codec.ensureFree(writeExternalWriteAhead);
     ((Externalizable) toWrite).writeExternal(this);
   } else {
     FSTClazzInfo.FSTFieldInfo[] fieldInfo = serializationInfo.getFieldInfo();
     writeObjectFields(toWrite, serializationInfo, fieldInfo, 0, 0);
   }
 }
 /** if class is same as last referenced, returned cached clzinfo, else do a lookup */
 protected FSTClazzInfo getFstClazzInfo(FSTClazzInfo.FSTFieldInfo referencee, Class clazz) {
   FSTClazzInfo serializationInfo = null;
   FSTClazzInfo lastInfo = referencee.lastInfo;
   if (lastInfo != null && lastInfo.getClazz() == clazz) {
     serializationInfo = lastInfo;
   } else {
     serializationInfo = getClassInfoRegistry().getCLInfo(clazz);
     referencee.lastInfo = serializationInfo;
   }
   return serializationInfo;
 }
 /**
  * @param clsInfo
  * @param referencee
  * @param toWrite
  * @return true if header already wrote object
  * @throws IOException
  */
 protected boolean writeObjectHeader(
     final FSTClazzInfo clsInfo, final FSTClazzInfo.FSTFieldInfo referencee, final Object toWrite)
     throws IOException {
   if (toWrite.getClass() == referencee.getType() && !clsInfo.useCompatibleMode()) {
     return codec.writeTag(TYPED, clsInfo, 0, toWrite);
   } else {
     final Class[] possibleClasses = referencee.getPossibleClasses();
     if (possibleClasses == null) {
       if (!codec.writeTag(OBJECT, clsInfo, 0, toWrite)) {
         codec.writeClass(clsInfo);
         return false;
       } else {
         return true;
       }
     } else {
       final int length = possibleClasses.length;
       for (int j = 0; j < length; j++) {
         final Class possibleClass = possibleClasses[j];
         if (possibleClass == toWrite.getClass()) {
           codec.writeFByte(j + 1);
           return false;
         }
       }
       if (!codec.writeTag(OBJECT, clsInfo, 0, toWrite)) {
         codec.writeClass(clsInfo);
         return false;
       } else {
         return true;
       }
     }
   }
 }
 protected void writeObjectCompatible(
     FSTClazzInfo.FSTFieldInfo referencee, Object toWrite, FSTClazzInfo serializationInfo)
     throws IOException {
   // Object header (nothing written till here)
   writeObjectHeader(serializationInfo, referencee, toWrite);
   Class cl = serializationInfo.getClazz();
   writeObjectCompatibleRecursive(referencee, toWrite, serializationInfo, cl);
 }
  // splitting this slows down ...
  protected void writeObjectWithContext(FSTClazzInfo.FSTFieldInfo referencee, Object toWrite)
      throws IOException {
    int startPosition = codec.getWritten();
    boolean dontShare = objects.disabled;
    objectWillBeWritten(toWrite, startPosition);

    try {
      if (toWrite == null) {
        codec.writeTag(NULL, null, 0, toWrite);
        return;
      }
      final Class clazz = toWrite.getClass();
      if (clazz == String.class) {
        String[] oneOf = referencee.getOneOf();
        if (oneOf != null) {
          for (int i = 0; i < oneOf.length; i++) {
            String s = oneOf[i];
            if (s.equals(toWrite)) {
              codec.writeTag(ONE_OF, oneOf, i, toWrite);
              codec.writeFByte(i);
              return;
            }
          }
        }
        if (dontShare) {
          codec.writeTag(STRING, toWrite, 0, toWrite);
          codec.writeStringUTF((String) toWrite);
          return;
        }
      } else if (clazz == Integer.class) {
        codec.writeTag(BIG_INT, null, 0, toWrite);
        codec.writeFInt(((Integer) toWrite).intValue());
        return;
      } else if (clazz == Long.class) {
        codec.writeTag(BIG_LONG, null, 0, toWrite);
        codec.writeFLong(((Long) toWrite).longValue());
        return;
      } else if (clazz == Boolean.class) {
        codec.writeTag(
            ((Boolean) toWrite).booleanValue() ? BIG_BOOLEAN_TRUE : BIG_BOOLEAN_FALSE,
            null,
            0,
            toWrite);
        return;
      } else if ((referencee.getType() != null && referencee.getType().isEnum())
          || toWrite instanceof Enum) {
        if (!codec.writeTag(ENUM, toWrite, 0, toWrite)) {
          boolean isEnumClass = toWrite.getClass().isEnum();
          if (!isEnumClass) {
            // weird stuff ..
            Class c = toWrite.getClass();
            while (c != null && !c.isEnum()) {
              c = toWrite.getClass().getEnclosingClass();
            }
            if (c == null) {
              throw new RuntimeException("Can't handle this enum: " + toWrite.getClass());
            }
            codec.writeClass(c);
          } else {
            codec.writeClass(getFstClazzInfo(referencee, toWrite.getClass()));
          }
          codec.writeFInt(((Enum) toWrite).ordinal());
        }
        return;
      }

      FSTClazzInfo serializationInfo = getFstClazzInfo(referencee, clazz);
      // check for identical / equal objects
      FSTObjectSerializer ser = serializationInfo.getSer();
      if (!dontShare
          && !referencee.isFlat()
          && !serializationInfo.isFlat()
          && (ser == null || !ser.alwaysCopy())) {
        int handle =
            objects.registerObjectForWrite(toWrite, codec.getWritten(), serializationInfo, tmp);
        // determine class header
        if (handle >= 0) {
          final boolean isIdentical =
              tmp[0] == 0; // objects.getReadRegisteredObject(handle) == toWrite;
          if (isIdentical) {
            //                        System.out.println("POK writeHandle"+handle+"
            // "+toWrite.getClass().getName());
            if (!codec.writeTag(HANDLE, null, handle, toWrite)) codec.writeFInt(handle);
            return;
          }
        }
      }
      if (clazz.isArray()) {
        if (codec.writeTag(ARRAY, toWrite, 0, toWrite))
          return; // some codecs handle primitive arrays like an primitive type
        writeArray(referencee, toWrite);
      } else if (ser == null) {
        // default write object wihtout custom serializer
        // handle write replace
        if (!dontShare) {
          if (serializationInfo.getWriteReplaceMethod() != null) {
            Object replaced = null;
            try {
              replaced = serializationInfo.getWriteReplaceMethod().invoke(toWrite);
            } catch (Exception e) {
              throw FSTUtil.rethrow(e);
            }
            if (replaced != toWrite) {
              toWrite = replaced;
              serializationInfo = getClassInfoRegistry().getCLInfo(toWrite.getClass());
              // fixme: update object map ?
            }
          }
          // clazz uses some JDK special stuff (frequently slow)
          if (serializationInfo.useCompatibleMode() && !serializationInfo.isExternalizable()) {
            writeObjectCompatible(referencee, toWrite, serializationInfo);
            return;
          }
        }
        if (!writeObjectHeader(
            serializationInfo,
            referencee,
            toWrite)) { // skip in case codec can write object as primitive
          defaultWriteObject(toWrite, serializationInfo);
          if (serializationInfo.isExternalizable()) codec.externalEnd(serializationInfo);
        }
      } else { // object has custom serializer
        // Object header (nothing written till here)
        int pos = codec.getWritten();
        if (!writeObjectHeader(
            serializationInfo,
            referencee,
            toWrite)) { // skip in case code can write object as primitive
          // write object depending on type (custom, externalizable, serializable/java, default)
          ser.writeObject(this, toWrite, serializationInfo, referencee, pos);
          codec.externalEnd(serializationInfo);
        }
      }
    } finally {
      objectHasBeenWritten(toWrite, startPosition, codec.getWritten());
    }
  }