static <K> DataExternalizerEx<K> adapt(@NotNull DataExternalizer<K> oldSchoolDescriptor) {

    if (oldSchoolDescriptor instanceof @NotNull KeyDescriptor<K>) {
      return KeyDescriptorEx.adapt((KeyDescriptor<K>)oldSchoolDescriptor);
    }

    //Do not wrap, if oldSchoolDescriptor already implements new interface
    // -> allows for 'bilingual' implementation (that implements both old&new
    // ifaces) to work efficiently
    if (oldSchoolDescriptor instanceof DataExternalizerEx<?>) {
      //noinspection unchecked
      return (DataExternalizerEx<K>)oldSchoolDescriptor;
    }

    return new DataExternalizerEx<>() {
      // Serialization/deserialization just bridges between ByteBuffer and ByteArrayInput/OutputStream

      //MAYBE RC: one allocation & one copy could be removed by implementing something like ByteBufferBacked[Input|Output]Stream
      //          instead of UnsyncByteArray[Input|Output]Stream

      @Override
      public K read(@NotNull ByteBuffer input) throws IOException {
        int bytesAvailable = input.remaining();
        byte[] contentAsArray = new byte[bytesAvailable];
        input.get(contentAsArray);
        return oldSchoolDescriptor.read(new DataInputStream(new UnsyncByteArrayInputStream(contentAsArray)));
      }


      @Override
      public KnownSizeRecordWriter writerFor(@NotNull K key) throws IOException {
        UnsyncByteArrayOutputStream stream = new UnsyncByteArrayOutputStream(64);
        try (DataOutputStream os = new DataOutputStream(stream)) {
          oldSchoolDescriptor.save(os, key);
        }

        return new ByteArrayWriter(stream.toByteArray());
      }

      @Override
      public String toString() {
        return "DataExternalizerAdapter[adapted: " + oldSchoolDescriptor + "]";
      }
    };
  }
static <K> DataExternalizerEx<K> adapt(@NotNull DataExternalizer<K> oldSchoolDescriptor)