public static Put toPut(final MutationProto proto, final CellScanner cellScanner)
    throws IOException {
    // TODO: Server-side at least why do we convert back to the Client types? Why not just pb it?
    MutationType type = proto.getMutateType();
    assert type == MutationType.PUT : type.name();
    long timestamp = proto.hasTimestamp() ? proto.getTimestamp() : HConstants.LATEST_TIMESTAMP;
    Put put = proto.hasRow() ? new Put(proto.getRow().toByteArray(), timestamp) : null;
    int cellCount = proto.hasAssociatedCellCount() ? proto.getAssociatedCellCount() : 0;
    if (cellCount > 0) {
      // The proto has metadata only and the data is separate to be found in the cellScanner.
      if (cellScanner == null) {
        throw new DoNotRetryIOException(
          "Cell count of " + cellCount + " but no cellScanner: " + toShortString(proto));
      }
      for (int i = 0; i < cellCount; i++) {
        if (!cellScanner.advance()) {
          throw new DoNotRetryIOException("Cell count of " + cellCount + " but at index " + i
            + " no cell returned: " + toShortString(proto));
        }
        Cell cell = cellScanner.current();
        if (put == null) {
          put = new Put(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(), timestamp);
        }
        put.add(cell);
      }
    } else {
      if (put == null) {
        throw new IllegalArgumentException("row cannot be null");
      }
      // The proto has the metadata and the data itself
      ExtendedCellBuilder cellBuilder =
        ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY);
      for (ColumnValue column : proto.getColumnValueList()) {
        byte[] family = column.getFamily().toByteArray();
        for (QualifierValue qv : column.getQualifierValueList()) {
          if (!qv.hasValue()) {
            throw new DoNotRetryIOException("Missing required field: qualifier value");
          }
          long ts = timestamp;
          if (qv.hasTimestamp()) {
            ts = qv.getTimestamp();
          }
          byte[] allTagsBytes;
          if (qv.hasTags()) {
            allTagsBytes = qv.getTags().toByteArray();
            if (qv.hasDeleteType()) {
              put.add(cellBuilder.clear().setRow(proto.getRow().toByteArray()).setFamily(family)
                .setQualifier(qv.hasQualifier() ? qv.getQualifier().toByteArray() : null)
                .setTimestamp(ts).setType(fromDeleteType(qv.getDeleteType()).getCode())
                .setTags(allTagsBytes).build());
            } else {
              put.add(cellBuilder.clear().setRow(put.getRow()).setFamily(family)
                .setQualifier(qv.hasQualifier() ? qv.getQualifier().toByteArray() : null)
                .setTimestamp(ts).setType(Cell.Type.Put)
                .setValue(qv.hasValue() ? qv.getValue().toByteArray() : null).setTags(allTagsBytes)
                .build());
            }
          } else {
            if (qv.hasDeleteType()) {
              put.add(cellBuilder.clear().setRow(put.getRow()).setFamily(family)
                .setQualifier(qv.hasQualifier() ? qv.getQualifier().toByteArray() : null)
                .setTimestamp(ts).setType(fromDeleteType(qv.getDeleteType()).getCode()).build());
            } else {
              put.add(cellBuilder.clear().setRow(put.getRow()).setFamily(family)
                .setQualifier(qv.hasQualifier() ? qv.getQualifier().toByteArray() : null)
                .setTimestamp(ts).setType(Cell.Type.Put)
                .setValue(qv.hasValue() ? qv.getValue().toByteArray() : null).build());
            }
          }
        }
      }
    }
    put.setDurability(toDurability(proto.getDurability()));
    for (NameBytesPair attribute : proto.getAttributeList()) {
      put.setAttribute(attribute.getName(), attribute.getValue().toByteArray());
    }
    return put;
  }
Convert a protocol buffer Mutate to a Put.
@param proto       The protocol buffer MutationProto to convert
@param cellScanner If non-null, the Cell data that goes with this proto.
@return A client Put.
hbase-client/src/main/java/org/apache/hadoop/hbase/shaded/protobuf/ProtobufUtil.java