jdbc-protolib/src/main/java/com/streamsets/pipeline/lib/jdbc/multithread/util/OffsetQueryUtil.java
public static Map<String, String> getOffsetsFromSourceKeyRepresentation(String offsets) {
    final Map<String, String> offsetMap = new HashMap<>();
    if (StringUtils.isNotBlank(offsets)) {
      for (String col : StringUtils.splitByWholeSeparator(offsets, OFFSET_KEY_COLUMN_SEPARATOR)) {
        final String[] parts = StringUtils.splitByWholeSeparator(col, OFFSET_KEY_COLUMN_NAME_VALUE_SEPARATOR, 2);

        if (parts.length != 2) {
          throw new IllegalArgumentException(String.format(
              "Invalid column offset of \"%s\" seen.  Expected colName%svalue.  Full offsets representation: %s",
              col,
              OFFSET_KEY_COLUMN_NAME_VALUE_SEPARATOR,
              offsets
          ));
        }

        offsetMap.put(parts[0], parts[1]);
      }
    }
    return offsetMap;
  }
public static Map<String, String> getOffsetsFromSourceKeyRepresentation(String offsets) {
    final Map<String, String> offsetMap = new HashMap<>();
    if (StringUtils.isNotBlank(offsets)) {
      for (String col : StringUtils.splitByWholeSeparator(offsets, OFFSET_KEY_COLUMN_SEPARATOR)) {
        final String[] parts = StringUtils.splitByWholeSeparator(col, OFFSET_KEY_COLUMN_NAME_VALUE_SEPARATOR, 2);

        if (parts.length != 2) {
          throw new IllegalArgumentException(String.format(
              "Invalid column offset of \"%s\" seen.  Expected colName%svalue.  Full offsets representation: %s",
              col,
              OFFSET_KEY_COLUMN_NAME_VALUE_SEPARATOR,
              offsets
          ));
        }

        offsetMap.put(parts[0], parts[1]);
      }
    }
    return offsetMap;
  }
This is the inverse of {@link #getSourceKeyOffsetsRepresentation(Map)}.

@param offsets the String representation of source key offsets
@return the {@link Map} of the offsets reconstructed from the supplied representation