legacy/src/main/java/thredds/crawlabledataset/s3/S3URI.java
public S3URI getChild(String relativePath) throws IllegalArgumentException {
        Preconditions.checkNotNull(relativePath, "relativePath must be non-null.");

        if (relativePath.isEmpty()) {
            return this;
        } else if (relativePath.startsWith(S3_DELIMITER)) {
            throw new IllegalArgumentException(String.format(
                    "Path '%s' should be relative but begins with the delimiter string '%s'.",
                    relativePath, S3_DELIMITER));
        }

        if (key == null) {
            return new S3URI(bucket, relativePath);
        } else {
            return new S3URI(bucket, key + S3_DELIMITER + relativePath);
        }
    }
public S3URI getChild(String relativePath) throws IllegalArgumentException {
        Preconditions.checkNotNull(relativePath, "relativePath must be non-null.");

        if (relativePath.isEmpty()) {
            return this;
        } else if (relativePath.startsWith(S3_DELIMITER)) {
            throw new IllegalArgumentException(String.format(
                    "Path '%s' should be relative but begins with the delimiter string '%s'.",
                    relativePath, S3_DELIMITER));
        }

        if (key == null) {
            return new S3URI(bucket, relativePath);
        } else {
            return new S3URI(bucket, key + S3_DELIMITER + relativePath);
        }
    }
Creates a new URI by resolving the specified path relative to {@code this}. If {@code key == null}, the key
of the returned URI will simply be {@code relativePath}.

@param relativePath  a path relative to {@code this}. Must be non-null.
@return  the child URI.
@throws IllegalArgumentException  if the path starts with a {@link #S3_DELIMITER delimiter}.
The path must be relative.