public static URI relativize(URI base,URI target) {
        if(!base.getScheme().equals(target.getScheme())) {
            return target;
        }
        StringBuilder rel = new StringBuilder();
        String path = base.getPath();
        String separator = "/";
        StringTokenizer tokenizer = new StringTokenizer(target.getPath(), separator);
        String targetPart = "";
        if(tokenizer.hasMoreTokens()) {
            targetPart = tokenizer.nextToken();
        }
        if(path.startsWith(separator)) {
            path = path.substring(1);
        }
        StringTokenizer baseTokenizer = new StringTokenizer(path, separator, true);
        while(baseTokenizer.hasMoreTokens()) {
            String basePart = baseTokenizer.nextToken();
            if(baseTokenizer.hasMoreTokens()) {
                // Has a / after this folder name
                baseTokenizer.nextToken(); // return separator
                if(!basePart.isEmpty()) {
                    if(!basePart.equals(targetPart)) {
                        rel.append("..");
                        rel.append(separator);
                    } else if(tokenizer.hasMoreTokens()) {
                        targetPart = tokenizer.nextToken();
                    }
                }
            }
        }
        // Add part of target path that is not in base path
        rel.append(targetPart);
        while (tokenizer.hasMoreTokens()) {
            targetPart = tokenizer.nextToken();
            rel.append(separator);
            rel.append(targetPart);
        }
        try {
            return new URI(null, null, rel.toString(), null, null);
        } catch (URISyntaxException ex) {
            throw new IllegalArgumentException("Illegal URI provided:\n"+base.toString()+"\n"+target.toString());
        }
    }
public static URI relativize ( URI base , URI target ) { if ( ! base . getScheme ( ) . equals ( target . getScheme ( ) ) ) { return target ; } StringBuilder rel = new StringBuilder ( ) ; String path = base . getPath ( ) ; String separator = "/" ; StringTokenizer tokenizer = new StringTokenizer ( target . getPath ( ) , separator ) ; String targetPart = "" ; if ( tokenizer . hasMoreTokens ( ) ) { targetPart = tokenizer . nextToken ( ) ; } if ( path . startsWith ( separator ) ) { path = path . substring ( 1 ) ; } StringTokenizer baseTokenizer = new StringTokenizer ( path , separator , true ) ; while ( baseTokenizer . hasMoreTokens ( ) ) { String basePart = baseTokenizer . nextToken ( ) ; if ( baseTokenizer . hasMoreTokens ( ) ) { baseTokenizer . nextToken ( ) ; if ( ! basePart . isEmpty ( ) ) { if ( ! basePart . equals ( targetPart ) ) { rel . append ( ".." ) ; rel . append ( separator ) ; } else if ( tokenizer . hasMoreTokens ( ) ) { targetPart = tokenizer . nextToken ( ) ; } } } } rel . append ( targetPart ) ; while ( tokenizer . hasMoreTokens ( ) ) { targetPart = tokenizer . nextToken ( ) ; rel . append ( separator ) ; rel . append ( targetPart ) ; } try { return new URI ( null , null , rel . toString ( ) , null , null ) ; } catch ( URISyntaxException ex ) { throw new IllegalArgumentException ( "Illegal URI provided:\n" + base . toString ( ) + "\n" + target . toString ( ) ) ; } }
Enhanced version of URI.relativize, the target can now be in parent folder of base URI.

@param base Base uri, location from where to relativize.
@param target Target uri, final destination of returned URI.

@return Non-absolute URI, or target if target scheme is different than base scheme.