@Nonnull
  public static String urlEncode (@Nonnull final String sValue, @Nonnull final Charset aCharset)
  {
    ValueEnforcer.notNull (sValue, "Value");
    ValueEnforcer.notNull (aCharset, "Charset");

    NonBlockingCharArrayWriter aCAW = null;
    try
    {
      final int nLen = sValue.length ();
      boolean bChanged = false;
      final StringBuilder aSB = new StringBuilder (nLen * 2);

      final char [] aSrcChars = sValue.toCharArray ();
      int nIndex = 0;
      while (nIndex < nLen)
      {
        char c = aSrcChars[nIndex];
        if (NO_URL_ENCODE.get (c))
        {
          if (c == ' ')
          {
            c = '+';
            bChanged = true;
          }
          aSB.append (c);
          nIndex++;
        }
        else
        {
          // convert to external encoding before hex conversion
          if (aCAW == null)
            aCAW = new NonBlockingCharArrayWriter ();
          else
            aCAW.reset ();

          while (true)
          {
            aCAW.write (c);
            /*
             * If this character represents the start of a Unicode surrogate
             * pair, then pass in two characters. It's not clear what should be
             * done if a bytes reserved in the surrogate pairs range occurs
             * outside of a legal surrogate pair. For now, just treat it as if
             * it were any other character.
             */
            if (Character.isHighSurrogate (c) && nIndex + 1 < nLen)
            {
              final char d = aSrcChars[nIndex + 1];
              if (Character.isLowSurrogate (d))
              {
                aCAW.write (d);
                nIndex++;
              }
            }
            nIndex++;
            if (nIndex >= nLen)
              break;

            // Try next char
            c = aSrcChars[nIndex];
            if (NO_URL_ENCODE.get (c))
              break;
          }

          final byte [] aEncodedBytes = aCAW.toByteArray (aCharset);
          for (final byte nEncByte : aEncodedBytes)
          {
            aSB.append ('%').append (URL_ENCODE_CHARS[(nEncByte >> 4) & 0xF]).append (URL_ENCODE_CHARS[nEncByte & 0xF]);
          }
          bChanged = true;
        }
      }
      return bChanged ? aSB.toString () : sValue;
    }
    finally
    {
      StreamHelper.close (aCAW);
    }
  }
@ Nonnull public static String urlEncode ( @ Nonnull final String sValue , @ Nonnull final Charset aCharset ) { ValueEnforcer . notNull ( sValue , "Value" ) ; ValueEnforcer . notNull ( aCharset , "Charset" ) ; NonBlockingCharArrayWriter aCAW = null ; try { final int nLen = sValue . length ( ) ; boolean bChanged = false ; final StringBuilder aSB = new StringBuilder ( nLen * 2 ) ; final char [ ] aSrcChars = sValue . toCharArray ( ) ; int nIndex = 0 ; while ( nIndex < nLen ) { char c = aSrcChars [ nIndex ] ; if ( NO_URL_ENCODE . get ( c ) ) { if ( c == ' ' ) { c = '+' ; bChanged = true ; } aSB . append ( c ) ; nIndex ++ ; } else { if ( aCAW == null ) aCAW = new NonBlockingCharArrayWriter ( ) ; else aCAW . reset ( ) ; while ( true ) { aCAW . write ( c ) ; if ( Character . isHighSurrogate ( c ) && nIndex + 1 < nLen ) { final char d = aSrcChars [ nIndex + 1 ] ; if ( Character . isLowSurrogate ( d ) ) { aCAW . write ( d ) ; nIndex ++ ; } } nIndex ++ ; if ( nIndex >= nLen ) break ; c = aSrcChars [ nIndex ] ; if ( NO_URL_ENCODE . get ( c ) ) break ; } final byte [ ] aEncodedBytes = aCAW . toByteArray ( aCharset ) ; for ( final byte nEncByte : aEncodedBytes ) { aSB . append ( '%' ) . append ( URL_ENCODE_CHARS [ ( nEncByte > > 4 ) & 0xF ] ) . append ( URL_ENCODE_CHARS [ nEncByte & 0xF ] ) ; } bChanged = true ; } } return bChanged ? aSB . toString ( ) : sValue ; } finally { StreamHelper . close ( aCAW ) ; } }
URL-encode the passed value automatically handling charset issues. This is
a ripped, optimized version of URLEncoder.encode but without the
UnsupportedEncodingException.

@param sValue
The value to be encoded. May not be <code>null</code>.
@param aCharset
The charset to use. May not be <code>null</code>.
@return The encoded value.