docs: public static String generateDirectoryHash(String rootDir, String chaincodeDir, String hash) throws IOException {
          // Generate the project directory
          Path projectPath = null;
          if (rootDir == null) {
              projectPath = Paths.get(chaincodeDir);
          } else {
              projectPath = Paths.get(rootDir, chaincodeDir);
          }
  
          File dir = projectPath.toFile();
          if (!dir.exists() || !dir.isDirectory()) {
              throw new IOException(format("The chaincode path \"%s\" is invalid", projectPath));
          }
  
          StringBuilder hashBuilder = new StringBuilder(hash);
          Files.walk(projectPath)
                  .sorted(Comparator.naturalOrder())
                  .filter(Files::isRegularFile)
                  .map(Path::toFile)
                  .forEach(file -> {
                      try {
                          byte[] buf = readFile(file);
                          byte[] toHash = Arrays.concatenate(buf, hashBuilder.toString().getBytes(UTF_8));
                          hashBuilder.setLength(0);
                          hashBuilder.append(Hex.toHexString(hash(toHash, new SHA3Digest())));
                      } catch (IOException ex) {
                          throw new RuntimeException(format("Error while reading file %s", file.getAbsolutePath()), ex);
                      }
                  });
  
          // If original hash and final hash are the same, it indicates that no new contents were found
          if (hashBuilder.toString().equals(hash)) {
              throw new IOException(format("The chaincode directory \"%s\" has no files", projectPath));
          }
          return hashBuilder.toString();
      }