@Override
  @SuppressWarnings({"rawtypes", "unchecked"})
  public <V> V unmarshall(
      Class<?> type, DataInput dataInput, SerializationContext serializationContext)
      throws IOException {
    if (isNull(dataInput)) {
      return null;
    }

    int size = dataInput.readInt();
    Map map = new LinkedHashMap(size);
    if (size > 0) {
      for (int i = 0; i < size; i++) {
        Object key = null;
        if (!isNull(dataInput)) {
          long keyClassId = dataInput.readLong();
          ClassDefinition keyClassDefinition =
              serializationContext.getClassDefinitionContainer().getClassDefinitionById(keyClassId);

          Marshaller keyMarshaller;
          if (mapKeyType != null) {
            ensureMarshallersInitialized(serializationContext);
            keyMarshaller = mapKeyTypeMarshaller;
          } else {
            keyMarshaller = serializationContext.findMarshaller(keyClassDefinition.getType());
          }

          key =
              keyMarshaller.unmarshall(
                  keyClassDefinition.getType(), dataInput, serializationContext);
        }

        Object value = null;
        if (!isNull(dataInput)) {
          long valueClassId = dataInput.readLong();
          ClassDefinition valueClassDefinition =
              serializationContext
                  .getClassDefinitionContainer()
                  .getClassDefinitionById(valueClassId);

          Marshaller valueMarshaller;
          if (mapKeyType != null) {
            ensureMarshallersInitialized(serializationContext);
            valueMarshaller = mapValueTypeMarshaller;
          } else {
            valueMarshaller = serializationContext.findMarshaller(valueClassDefinition.getType());
          }

          value =
              valueMarshaller.unmarshall(
                  valueClassDefinition.getType(), dataInput, serializationContext);
        }

        map.put(key, value);
      }
    }

    return (V) map;
  }
  @Override
  public void marshall(
      Object value, Class<?> type, DataOutput dataOutput, SerializationContext serializationContext)
      throws IOException {
    writePossibleNull(value, dataOutput);

    Map<?, ?> map = (Map<?, ?>) value;
    dataOutput.writeInt(map.size());
    for (Entry<?, ?> entry : map.entrySet()) {
      Marshaller keyMarshaller;
      Marshaller valueMarshaller;
      if (mapKeyType != null) {
        ensureMarshallersInitialized(serializationContext);
        keyMarshaller = mapKeyTypeMarshaller;
        valueMarshaller = mapValueTypeMarshaller;
      } else {
        keyMarshaller =
            entry.getKey() != null
                ? serializationContext.findMarshaller(entry.getKey().getClass())
                : null;
        valueMarshaller =
            entry.getValue() != null
                ? serializationContext.findMarshaller(entry.getValue().getClass())
                : null;
      }

      if (writePossibleNull(entry.getKey(), dataOutput)) {
        ClassDefinition keyClassDefinition =
            serializationContext
                .getClassDefinitionContainer()
                .getClassDefinitionByType(entry.getKey().getClass());
        dataOutput.writeLong(keyClassDefinition.getId());
        keyMarshaller.marshall(
            entry.getKey(), entry.getKey().getClass(), dataOutput, serializationContext);
      }

      if (writePossibleNull(entry.getValue(), dataOutput)) {
        ClassDefinition valueClassDefinition =
            serializationContext
                .getClassDefinitionContainer()
                .getClassDefinitionByType(entry.getValue().getClass());
        dataOutput.writeLong(valueClassDefinition.getId());
        valueMarshaller.marshall(
            entry.getValue(), entry.getValue().getClass(), dataOutput, serializationContext);
      }
    }
  }
  private void ensureMarshallersInitialized(SerializationContext serializationContext) {
    if (mapKeyTypeMarshaller != null && mapValueTypeMarshaller != null) return;

    mapKeyTypeMarshaller = serializationContext.findMarshaller(mapKeyType);
    mapValueTypeMarshaller = serializationContext.findMarshaller(mapValueType);
  }