docs: public GatewayMessage decode(ByteBuf byteBuf) throws MessageCodecException {
      try (InputStream stream = new ByteBufInputStream(byteBuf, true)) {
        JsonParser jp = jsonFactory.createParser(stream);
        GatewayMessage.Builder result = GatewayMessage.builder();
  
        JsonToken current = jp.nextToken();
        if (current != JsonToken.START_OBJECT) {
          throw new MessageCodecException("Root should be object", null);
        }
        long dataStart = 0;
        long dataEnd = 0;
        while ((jp.nextToken()) != JsonToken.END_OBJECT) {
          String fieldName = jp.getCurrentName();
          current = jp.nextToken();
          if (current == VALUE_NULL) {
            continue;
          }
  
          if (fieldName.equals(DATA_FIELD)) {
            dataStart = jp.getTokenLocation().getByteOffset();
            if (current.isScalarValue()) {
              if (!current.isNumeric() && !current.isBoolean()) {
                jp.getValueAsString();
              }
            } else if (current.isStructStart()) {
              jp.skipChildren();
            }
            dataEnd = jp.getCurrentLocation().getByteOffset();
          } else {
            // headers
            result.header(fieldName, jp.getValueAsString());
          }
        }
        // data
        if (dataEnd > dataStart) {
          result.data(byteBuf.copy((int) dataStart, (int) (dataEnd - dataStart)));
        }
        return result.build();
      } catch (Throwable ex) {
        throw new MessageCodecException("Failed to decode message", ex);
      }
    }