UriEncoding { @SuppressWarnings("squid:S3776") private static String decodeRFC3986(final String source) { final int length = source.length(); final ByteArrayOutputStream out = new ByteArrayOutputStream(length); boolean changed = false; int i = 0; while (i < length) { final int c = source.charAt(i); if (c == '%') { if ((i + 2) < length) { final char hex1 = source.charAt(i + 1); final char hex2 = source.charAt(i + 2); final int digit1 = Character.digit(hex1, 16); final int digit2 = Character.digit(hex2, 16); if (digit1 < 0 || digit2 < 0) { throw new IllegalArgumentException( "Illegal hex characters in escape pattern - negative value: \"" + source.substring(i) + "\"!"); } out.write((char) ((digit1 << 4) + digit2)); i += 2; changed = true; } else { throw new IllegalArgumentException( "Incomplete trailing escape pattern: \"" + source.substring(i) + "\"!"); } } else { out.write(c); } i++; } if (changed) { try { return new String(out.toByteArray(), ENCODING); } catch (final UnsupportedEncodingException e) { throw new IllegalStateException(e); } } else { return source; } }  static String encodePath(final String path); static String encodePathSegment(final String pathSegment); static String encodeQuery(final String query, final EncodingType encType); static String encodeQueryParam(final String queryParam, final EncodingType encType); static String decode(final String source, final EncodingType encType);  }
@Test public void decodeRfc3986() { assertEquals("", UriEncoding.decode("", RFC3986)); assertEquals("foo", UriEncoding.decode("foo", RFC3986)); assertEquals("with space", UriEncoding.decode("with%20space", RFC3986)); assertEquals("with+PlusEncoded", UriEncoding.decode("with%2bPlusEncoded", RFC3986)); assertEquals("with+PlusNotEncoded", UriEncoding.decode("with+PlusNotEncoded", RFC3986)); assertEquals(MANY_DIFFERENT_CHARS, UriEncoding.decode(MANY_DIFFERENT_CHARS_QUERY_PARAM_ENCODED_RFC3986, RFC3986)); }