Based on all your remarks here is my proposal that worked for me :
private final class CustomHttpServletRequest extends HttpServletRequestWrapper {
private final Map<String, String[]> queryParameterMap;
private final Charset requestEncoding;
public CustomHttpServletRequest(HttpServletRequest request) {
super(request);
queryParameterMap = getCommonQueryParamFromLegacy(request.getParameterMap());
String encoding = request.getCharacterEncoding();
requestEncoding = (encoding != null ? Charset.forName(encoding) : StandardCharsets.UTF_8);
}
private final Map<String, String[]> getCommonQueryParamFromLegacy(Map<String, String[]> paramMap) {
Objects.requireNonNull(paramMap);
Map<String, String[]> commonQueryParamMap = new LinkedHashMap<>(paramMap);
commonQueryParamMap.put(CommonQueryParams.PATIENT_ID, new String[] { paramMap.get(LEGACY_PARAM_PATIENT_ID)[0] });
commonQueryParamMap.put(CommonQueryParams.PATIENT_BIRTHDATE, new String[] { paramMap.get(LEGACY_PARAM_PATIENT_BIRTHDATE)[0] });
commonQueryParamMap.put(CommonQueryParams.KEYWORDS, new String[] { paramMap.get(LEGACY_PARAM_STUDYTYPE)[0] });
String lowerDateTime = null;
String upperDateTime = null;
try {
String studyDateTime = new SimpleDateFormat("yyyy-MM-dd").format(new SimpleDateFormat("dd-MM-yyyy").parse(paramMap.get(LEGACY_PARAM_STUDY_DATE_TIME)[0]));
lowerDateTime = studyDateTime + "T23:59:59";
upperDateTime = studyDateTime + "T00:00:00";
} catch (ParseException e) {
LOGGER.error("Can't parse StudyDate from query parameters : {}", e.getLocalizedMessage());
}
commonQueryParamMap.put(CommonQueryParams.LOWER_DATETIME, new String[] { lowerDateTime });
commonQueryParamMap.put(CommonQueryParams.UPPER_DATETIME, new String[] { upperDateTime });
legacyQueryParams.forEach(commonQueryParamMap::remove);
return Collections.unmodifiableMap(commonQueryParamMap);
}
@Override
public String getParameter(String name) {
String[] params = queryParameterMap.get(name);
return params != null ? params[0] : null;
}
@Override
public String[] getParameterValues(String name) {
return queryParameterMap.get(name);
}
@Override
public Map<String, String[]> getParameterMap() {
return queryParameterMap; // unmodifiable to uphold the interface contract.
}
@Override
public Enumeration<String> getParameterNames() {
return Collections.enumeration(queryParameterMap.keySet());
}
@Override
public String getQueryString() {
// @see : https://stackoverflow.com/a/35831692/9869013
// return queryParameterMap.entrySet().stream().flatMap(entry -> Stream.of(entry.getValue()).map(value -> entry.getKey() + "=" + value)).collect(Collectors.joining("&")); // without encoding !!
return queryParameterMap.entrySet().stream().flatMap(entry -> encodeMultiParameter(entry.getKey(), entry.getValue(), requestEncoding)).collect(Collectors.joining("&"));
}
private Stream<String> encodeMultiParameter(String key, String[] values, Charset encoding) {
return Stream.of(values).map(value -> encodeSingleParameter(key, value, encoding));
}
private String encodeSingleParameter(String key, String value, Charset encoding) {
return urlEncode(key, encoding) + "=" + urlEncode(value, encoding);
}
private String urlEncode(String value, Charset encoding) {
try {
return URLEncoder.encode(value, encoding.name());
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("Cannot url encode " + value, e);
}
}
@Override
public ServletInputStream getInputStream() throws IOException {
throw new UnsupportedOperationException("getInputStream() is not implemented in this " + CustomHttpServletRequest.class.getSimpleName() + " wrapper");
}
}
note : queryString() requires to process ALL the values for each KEY and don't forget to encodeUrl() when adding your own param values, if required
As a limitation, if you call request.getParameterMap() or any method that would call request.getReader() and begin reading, you will prevent any further calls to request.setCharacterEncoding(...)