From 9de97614a0ae24c95abc86ebeacec23a53de37c9 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 7 Mar 2017 10:33:26 +0100 Subject: [PATCH] Adapt to HtmlUnit 2.25 getCharset() return type at runtime Issue: SPR-15319 --- .../htmlunit/HtmlUnitRequestBuilder.java | 61 +++++++++++-------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilder.java index 5544875a889..f46ae7c4570 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,10 @@ package org.springframework.test.web.servlet.htmlunit; import java.io.UnsupportedEncodingException; +import java.lang.reflect.Method; import java.net.URL; import java.net.URLDecoder; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; @@ -50,7 +52,9 @@ import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilde import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.request.RequestPostProcessor; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; +import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; @@ -59,7 +63,7 @@ import org.springframework.web.util.UriComponentsBuilder; * Internal class used to transform a {@link WebRequest} into a * {@link MockHttpServletRequest} using Spring MVC Test's {@link RequestBuilder}. * - *

By default the first path segment of the URL is used as the contextPath. + *

By default the first path segment of the URL is used as the context path. * To override this default see {@link #setContextPath(String)}. * * @author Rob Winch @@ -71,6 +75,11 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { private static final Pattern LOCALE_PATTERN = Pattern.compile("^\\s*(\\w{2})(?:-(\\w{2}))?(?:;q=(\\d+\\.\\d+))?$"); + private static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1"); + + + private static final Method getCharsetMethod = ClassUtils.getMethodIfAvailable(WebRequest.class, "getCharset"); + private final Map sessions; private final WebClient webClient; @@ -98,23 +107,23 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { Assert.notNull(sessions, "Sessions Map must not be null"); Assert.notNull(webClient, "WebClient must not be null"); Assert.notNull(webRequest, "WebRequest must not be null"); - this.sessions = sessions; this.webClient = webClient; this.webRequest = webRequest; } + public MockHttpServletRequest buildRequest(ServletContext servletContext) { - String charset = getCharset(); + Charset charset = getCharset(); String httpMethod = this.webRequest.getHttpMethod().name(); UriComponents uriComponents = uriComponents(); MockHttpServletRequest request = new HtmlUnitMockHttpServletRequest( servletContext, httpMethod, uriComponents.getPath()); parent(request, this.parentBuilder); - request.setServerName(uriComponents.getHost()); // needs to be first for additional headers + request.setServerName(uriComponents.getHost()); // needs to be first for additional headers authType(request); - request.setCharacterEncoding(charset); + request.setCharacterEncoding(charset.name()); content(request, charset); contextPath(request, uriComponents); contentType(request); @@ -132,6 +141,21 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { return postProcess(request); } + private Charset getCharset() { + if (getCharsetMethod != null) { + Object value = ReflectionUtils.invokeMethod(getCharsetMethod, this.webRequest); + if (value instanceof Charset) { + // HtmlUnit 2.25: a Charset + return (Charset) value; + } + else if (value != null) { + // HtmlUnit up until 2.24: a String + return Charset.forName(value.toString()); + } + } + return DEFAULT_CHARSET; + } + private MockHttpServletRequest postProcess(MockHttpServletRequest request) { if (this.parentPostProcessor != null) { request = this.parentPostProcessor.postProcessRequest(request); @@ -220,17 +244,12 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { } } - private void content(MockHttpServletRequest request, String charset) { + private void content(MockHttpServletRequest request, Charset charset) { String requestBody = this.webRequest.getRequestBody(); if (requestBody == null) { return; } - try { - request.setContent(requestBody.getBytes(charset)); - } - catch (UnsupportedEncodingException ex) { - throw new IllegalStateException(ex); - } + request.setContent(requestBody.getBytes(charset)); } private void contentType(MockHttpServletRequest request) { @@ -256,8 +275,8 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { } else { if (!uriComponents.getPath().startsWith(this.contextPath)) { - throw new IllegalArgumentException(uriComponents.getPath() + " should start with contextPath " + - this.contextPath); + throw new IllegalArgumentException("\"" + uriComponents.getPath() + + "\" should start with context path \"" + this.contextPath + "\""); } request.setContextPath(this.contextPath); } @@ -273,7 +292,7 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { String cookieName = tokens.nextToken().trim(); if (!tokens.hasMoreTokens()) { throw new IllegalArgumentException("Expected value for cookie name '" + cookieName + - "'. Full cookie was " + cookieHeaderValue); + "': full cookie header was [" + cookieHeaderValue + "]"); } String cookieValue = tokens.nextToken().trim(); processCookie(request, cookies, new Cookie(cookieName, cookieValue)); @@ -305,14 +324,6 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { } } - private String getCharset() { - String charset = this.webRequest.getCharset(); - if (charset == null) { - return "ISO-8859-1"; - } - return charset; - } - private String header(String headerName) { return this.webRequest.getAdditionalHeaders().get(headerName); } @@ -394,7 +405,7 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable { private Locale parseLocale(String locale) { Matcher matcher = LOCALE_PATTERN.matcher(locale); if (!matcher.matches()) { - throw new IllegalArgumentException("Invalid locale " + locale); + throw new IllegalArgumentException("Invalid locale value [" + locale + "]"); } String language = matcher.group(1); String country = matcher.group(2);