I'm communicating with an out of spec server which does not recognize "+" as a blank space in query strings - this was quite a problem as I am passing actual filenames which I don't control and which may have spaces in them!
The workaround I built was to copy format (and everything it calls) from URLEncodedUtils and augment to pass down the blankAsPlus value, which I then call explicitly by bypassing the built in encoder by sending in a raw encoded querystring as part of the original url string I use for my client retrieve/execution. It turns out that this function: private static String encodeFormFields (final String content, final Charset charset); needs to have a 'false' as the ultimate argument in the call to this function: private static String urlEncode( final String content, final Charset charset, final BitSet safechars, final boolean blankAsPlus); There was apparently no consideration that this might be necessary outside this private context. It's okay. I totally understand. I also understand that you may not like the idea of being compatible with obviously out of spec servers. But - it is my philosophical assertion that as a library which may be used by many divers purposes, it is better to allow the user to do whatever he wants, rather than to be quite so opinionated about it as to make it impossible to bypass the blankAsPlus while encoding My humble suggestion as thus - allow injection of blankAsPlus boolean external to the class. (I didn't chase *all* the format dependencies, but would be easy enough to do with a refactor calc or simply add a compatibility signature) (this one is in UrlEncodedFormEntity.java - conform with api change and compatibility constructor? defer to you.) - public UrlEncodedFormEntity ( - final Iterable <? extends NameValuePair> parameters, - final Charset charset) { - super(URLEncodedUtils.format(parameters, - charset != null ? charset : HTTP.DEF_CONTENT_CHARSET), - ContentType.create(URLEncodedUtils.CONTENT_TYPE, charset)); - } + public UrlEncodedFormEntity ( + final Iterable <? extends NameValuePair> parameters, + final Charset charset) { + super(URLEncodedUtils.format(parameters, + charset != null ? charset : HTTP.DEF_CONTENT_CHARSET), + ContentType.create(URLEncodedUtils.CONTENT_TYPE, charset), + false); + } + public UrlEncodedFormEntity ( + final Iterable <? extends NameValuePair> parameters, + final Charset charset, + boolean blankAsPlus) { + super(URLEncodedUtils.format(parameters, + charset != null ? charset : HTTP.DEF_CONTENT_CHARSET), + ContentType.create(URLEncodedUtils.CONTENT_TYPE, charset), + blankAsPlus); + } (this one is in URIBuilder.java - conform to api change - consider also adding mode/flag in builder to turn this on/off? (I really like this idea)) public static String encodeUrlForm(final List<NameValuePair> params) { - return format(params, Consts.UTF_8); + return format(params, Consts.UTF_8, false); } (These are all in URLEncodedUtils.java - pass the value down in and default on the public level with the old api.) - public static String format( - final Iterable<? extends NameValuePair> parameters, - final Charset charset) { - return format(parameters, '&', charset); + public static String format( + final Iterable<? extends NameValuePair> parameters, + final Charset charset) { + return format(parameters, '&', charset, false); + } + public static String format( + final Iterable<? extends NameValuePair> parameters, + final Charset charset, + boolean blankAsPlus) { + return format(parameters, '&', charset, blankAsPlus); } - public static String format( - final Iterable<? extends NameValuePair> parameters, - final char parameterSeparator, - final Charset charset) { + public static String format( + final Iterable<? extends NameValuePair> parameters, + final char parameterSeparator, + final Charset charset, + boolean blankAsPlus) { Args.notNull(parameters, "Parameters"); final StringBuilder result = new StringBuilder(); for (final NameValuePair parameter : parameters) { - final String encodedName = encodeFormFields(parameter.getName(), charset); - final String encodedValue = encodeFormFields(parameter.getValue(), charset); + final String encodedName = encodeFormFields(parameter.getName(), charset, blankAsPlus); + final String encodedValue = encodeFormFields(parameter.getValue(), charset, blankAsPlus); if (result.length() > 0) { result.append(parameterSeparator); } (And finally encodeFormFields itself.) - private static String encodeFormFields (final String content, final Charset charset) { + private static String encodeFormFields(final String content, final Charset charset, boolean blankAsPlus) { if (content == null) { return null; } - return urlEncode(content, charset != null ? charset : Consts.UTF_8, wwwFormUrlSafe(), false); + return urlEncode(content, charset != null ? charset : Consts.UTF_8, wwwFormUrlSafe(), blankAsPlus); } If you'd like me to submit a pull request on this, point me to the code repo you're using and I'll be happy to generate one. -- Dog approved this message.