diff --git a/build.gradle b/build.gradle index 836637b912..fba776e778 100644 --- a/build.gradle +++ b/build.gradle @@ -123,8 +123,6 @@ configure(allprojects) { project -> } } - compileJava.options.encoding = 'UTF-8' - compileJava.options*.compilerArgs = [ "-Xlint:serial", "-Xlint:varargs", "-Xlint:cast", "-Xlint:classfile", "-Xlint:dep-ann", "-Xlint:divzero", "-Xlint:empty", "-Xlint:finally", @@ -143,11 +141,13 @@ configure(allprojects) { project -> compileJava { sourceCompatibility = 1.8 targetCompatibility = 1.8 + options.encoding = 'UTF-8' } compileTestJava { sourceCompatibility = 1.8 targetCompatibility = 1.8 + options.encoding = 'UTF-8' options.compilerArgs += "-parameters" } diff --git a/spring-core/src/main/java/org/springframework/util/StringUtils.java b/spring-core/src/main/java/org/springframework/util/StringUtils.java index 72e81e4a79..2f14858af2 100644 --- a/spring-core/src/main/java/org/springframework/util/StringUtils.java +++ b/spring-core/src/main/java/org/springframework/util/StringUtils.java @@ -16,8 +16,6 @@ package org.springframework.util; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -1196,44 +1194,4 @@ public abstract class StringUtils { return arrayToDelimitedString(arr, ","); } - /** - * Encode the given header field param as describe in the rfc5987. - * @param input the header field param - * @param charset the charset of the header field param string - * @return the encoded header field param - * @see rfc5987 - * @since 5.0 - */ - public static String encodeHttpHeaderFieldParam(String input, Charset charset) { - Assert.notNull(charset, "charset should not be null"); - if(StandardCharsets.US_ASCII.equals(charset)) { - return input; - } - Assert.isTrue(StandardCharsets.UTF_8.equals(charset) || StandardCharsets.ISO_8859_1.equals(charset), - "charset should be UTF-8 or ISO-8859-1"); - final byte[] source = input.getBytes(charset); - final int len = source.length; - final StringBuilder sb = new StringBuilder(len << 1); - sb.append(charset.name()); - sb.append("''"); - for (byte b : source) { - if (isRFC5987AttrChar(b)) { - sb.append((char) b); - } - else { - sb.append('%'); - char hex1 = Character.toUpperCase(Character.forDigit((b >> 4) & 0xF, 16)); - char hex2 = Character.toUpperCase(Character.forDigit(b & 0xF, 16)); - sb.append(hex1); - sb.append(hex2); - } - } - return sb.toString(); - } - - private static boolean isRFC5987AttrChar(byte c) { - return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') - || c == '!' || c == '#' || c == '$' || c == '&' || c == '+' || c == '-' - || c == '.' || c == '^' || c == '_' || c == '`' || c == '|' || c == '~'; - } } diff --git a/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java b/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java index 2b574aaca5..b0a79776d8 100644 --- a/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java @@ -628,8 +628,7 @@ public class StringUtilsTests { assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); } - // SPR-3671 - @Test + @Test // SPR-3671 public void testParseLocaleWithMultiValuedVariant() throws Exception { final String variant = "proper_northern"; final String localeString = "en_GB_" + variant; @@ -637,8 +636,7 @@ public class StringUtilsTests { assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); } - // SPR-3671 - @Test + @Test // SPR-3671 public void testParseLocaleWithMultiValuedVariantUsingSpacesAsSeparators() throws Exception { final String variant = "proper northern"; final String localeString = "en GB " + variant; @@ -646,8 +644,7 @@ public class StringUtilsTests { assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); } - // SPR-3671 - @Test + @Test // SPR-3671 public void testParseLocaleWithMultiValuedVariantUsingMixtureOfUnderscoresAndSpacesAsSeparators() throws Exception { final String variant = "proper northern"; final String localeString = "en_GB_" + variant; @@ -655,8 +652,7 @@ public class StringUtilsTests { assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); } - // SPR-3671 - @Test + @Test // SPR-3671 public void testParseLocaleWithMultiValuedVariantUsingSpacesAsSeparatorsWithLotsOfLeadingWhitespace() throws Exception { final String variant = "proper northern"; final String localeString = "en GB " + variant; // lots of whitespace @@ -664,8 +660,7 @@ public class StringUtilsTests { assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); } - // SPR-3671 - @Test + @Test // SPR-3671 public void testParseLocaleWithMultiValuedVariantUsingUnderscoresAsSeparatorsWithLotsOfLeadingWhitespace() throws Exception { final String variant = "proper_northern"; final String localeString = "en_GB_____" + variant; // lots of underscores @@ -673,8 +668,7 @@ public class StringUtilsTests { assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); } - // SPR-7779 - @Test + @Test // SPR-7779 public void testParseLocaleWithInvalidCharacters() { try { StringUtils.parseLocaleString("%0D%0AContent-length:30%0D%0A%0D%0A%3Cscript%3Ealert%28123%29%3C/script%3E"); @@ -685,15 +679,13 @@ public class StringUtilsTests { } } - // SPR-9420 - @Test + @Test // SPR-9420 public void testParseLocaleWithSameLowercaseTokenForLanguageAndCountry() { assertEquals("tr_TR", StringUtils.parseLocaleString("tr_tr").toString()); assertEquals("bg_BG_vnt", StringUtils.parseLocaleString("bg_bg_vnt").toString()); } - // SPR-11806 - @Test + @Test // SPR-11806 public void testParseLocaleWithVariantContainingCountryCode() { String variant = "GBtest"; String localeString = "en_GB_" + variant; @@ -701,19 +693,4 @@ public class StringUtilsTests { assertEquals("Variant containing country code not extracted correctly", variant, locale.getVariant()); } - // SPR-14547 - @Test - public void encodeHttpHeaderFieldParam() { - String result = StringUtils.encodeHttpHeaderFieldParam("test.txt", StandardCharsets.US_ASCII); - assertEquals("test.txt", result); - - result = StringUtils.encodeHttpHeaderFieldParam("中文.txt", StandardCharsets.UTF_8); - assertEquals("UTF-8''%E4%B8%AD%E6%96%87.txt", result); - } - - @Test(expected = IllegalArgumentException.class) - public void encodeHttpHeaderFieldParamInvalidCharset() { - StringUtils.encodeHttpHeaderFieldParam("test", StandardCharsets.UTF_16); - } - } diff --git a/spring-web/src/main/java/org/springframework/http/HttpHeaders.java b/spring-web/src/main/java/org/springframework/http/HttpHeaders.java index b4f4b2047b..61c365f963 100644 --- a/spring-web/src/main/java/org/springframework/http/HttpHeaders.java +++ b/spring-web/src/main/java/org/springframework/http/HttpHeaders.java @@ -679,13 +679,14 @@ public class HttpHeaders implements MultiValueMap, Serializable /** * Set the (new) value of the {@code Content-Disposition} header - * for {@code form-data}, optionally encoding the filename using the rfc5987. + * for {@code form-data}, optionally encoding the filename using the RFC 5987. *

Only the US-ASCII, UTF-8 and ISO-8859-1 charsets are supported. * @param name the control name * @param filename the filename (may be {@code null}) * @param charset the charset used for the filename (may be {@code null}) - * @see rfc7230 Section 3.2.4 - * @since 5.0 + * @since 4.3.3 + * @see #setContentDispositionFormData(String, String) + * @see RFC 7230 Section 3.2.4 */ public void setContentDispositionFormData(String name, String filename, Charset charset) { Assert.notNull(name, "'name' must not be null"); @@ -698,7 +699,7 @@ public class HttpHeaders implements MultiValueMap, Serializable } else { builder.append("; filename*="); - builder.append(StringUtils.encodeHttpHeaderFieldParam(filename, charset)); + builder.append(encodeHeaderFieldParam(filename, charset)); } } set(CONTENT_DISPOSITION, builder.toString()); @@ -1345,4 +1346,45 @@ public class HttpHeaders implements MultiValueMap, Serializable return new HttpHeaders(headers, true); } + /** + * Encode the given header field param as describe in RFC 5987. + * @param input the header field param + * @param charset the charset of the header field param string + * @return the encoded header field param + * @see RFC 5987 + */ + static String encodeHeaderFieldParam(String input, Charset charset) { + Assert.notNull(input, "Input String should not be null"); + Assert.notNull(charset, "Charset should not be null"); + if (StandardCharsets.US_ASCII.equals(charset)) { + return input; + } + Assert.isTrue(StandardCharsets.UTF_8.equals(charset) || StandardCharsets.ISO_8859_1.equals(charset), + "Charset should be UTF-8 or ISO-8859-1"); + byte[] source = input.getBytes(charset); + int len = source.length; + StringBuilder sb = new StringBuilder(len << 1); + sb.append(charset.name()); + sb.append("''"); + for (byte b : source) { + if (isRFC5987AttrChar(b)) { + sb.append((char) b); + } + else { + sb.append('%'); + char hex1 = Character.toUpperCase(Character.forDigit((b >> 4) & 0xF, 16)); + char hex2 = Character.toUpperCase(Character.forDigit(b & 0xF, 16)); + sb.append(hex1); + sb.append(hex2); + } + } + return sb.toString(); + } + + private static boolean isRFC5987AttrChar(byte c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + c == '!' || c == '#' || c == '$' || c == '&' || c == '+' || c == '-' || + c == '.' || c == '^' || c == '_' || c == '`' || c == '|' || c == '~'; + } + } diff --git a/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java b/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java index c6464553a6..b28f4d8bc9 100644 --- a/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java +++ b/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java @@ -150,7 +150,6 @@ public class HttpHeadersTests { headers.setHost(host); assertEquals("Invalid Host header", host, headers.getHost()); assertEquals("Invalid Host header", "localhost:8080", headers.getFirst("Host")); - } @Test @@ -159,7 +158,6 @@ public class HttpHeadersTests { headers.setHost(host); assertEquals("Invalid Host header", host, headers.getHost()); assertEquals("Invalid Host header", "localhost", headers.getFirst("Host")); - } @Test(expected = IllegalArgumentException.class) @@ -429,4 +427,18 @@ public class HttpHeadersTests { assertEquals(HttpMethod.POST, headers.getAccessControlRequestMethod()); } + @Test // SPR-14547 + public void encodeHeaderFieldParam() { + String result = HttpHeaders.encodeHeaderFieldParam("test.txt", StandardCharsets.US_ASCII); + assertEquals("test.txt", result); + + result = HttpHeaders.encodeHeaderFieldParam("中文.txt", StandardCharsets.UTF_8); + assertEquals("UTF-8''%E4%B8%AD%E6%96%87.txt", result); + } + + @Test(expected = IllegalArgumentException.class) + public void encodeHeaderFieldParamInvalidCharset() { + HttpHeaders.encodeHeaderFieldParam("test", StandardCharsets.UTF_16); + } + } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupView.java index 38eda9811f..e3007c34a8 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupView.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -45,7 +45,7 @@ import org.springframework.web.util.NestedServletException; * @see GroovyMarkupViewResolver * @see GroovyMarkupConfigurer * @see - * Groovy Markup Template engine documentation + * Groovy Markup Template engine documentation */ public class GroovyMarkupView extends AbstractTemplateView { @@ -63,17 +63,6 @@ public class GroovyMarkupView extends AbstractTemplateView { this.engine = engine; } - @Override - public boolean checkResource(Locale locale) throws Exception { - try { - this.engine.resolveTemplate(getUrl()); - } - catch (IOException exception) { - return false; - } - return true; - } - /** * Invoked at startup. * If no {@link #setTemplateEngine(MarkupTemplateEngine) templateEngine} has @@ -107,6 +96,17 @@ public class GroovyMarkupView extends AbstractTemplateView { } + @Override + public boolean checkResource(Locale locale) throws Exception { + try { + this.engine.resolveTemplate(getUrl()); + } + catch (IOException ex) { + return false; + } + return true; + } + @Override protected void renderMergedTemplateModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { @@ -125,8 +125,9 @@ public class GroovyMarkupView extends AbstractTemplateView { } catch (ClassNotFoundException ex) { Throwable cause = (ex.getCause() != null ? ex.getCause() : ex); - throw new NestedServletException("Could not find class while rendering Groovy Markup view with name '" + - getUrl() + "': " + ex.getMessage() + "'", cause); + throw new NestedServletException( + "Could not find class while rendering Groovy Markup view with name '" + + getUrl() + "': " + ex.getMessage() + "'", cause); } } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/groovy/GroovyMarkupViewTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/groovy/GroovyMarkupViewTests.java index d276be0313..63f2bb0257 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/groovy/GroovyMarkupViewTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/groovy/GroovyMarkupViewTests.java @@ -15,9 +15,7 @@ */ package org.springframework.web.servlet.view.groovy; -import java.io.IOException; import java.io.Reader; -import java.util.Arrays; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -27,7 +25,6 @@ import groovy.text.Template; import groovy.text.TemplateEngine; import groovy.text.markup.MarkupTemplateEngine; import groovy.text.markup.TemplateConfiguration; -import org.codehaus.groovy.control.CompilationFailedException; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; @@ -57,6 +54,7 @@ public class GroovyMarkupViewTests { private ServletContext servletContext; + @Before public void setup() { this.webAppContext = mock(WebApplicationContext.class); @@ -82,7 +80,6 @@ public class GroovyMarkupViewTests { @Test public void customTemplateEngine() throws Exception { - GroovyMarkupView view = new GroovyMarkupView(); view.setTemplateEngine(new TestTemplateEngine()); view.setApplicationContext(this.webAppContext); @@ -95,9 +92,7 @@ public class GroovyMarkupViewTests { @Test public void detectTemplateEngine() throws Exception { - GroovyMarkupView view = new GroovyMarkupView(); - view.setTemplateEngine(new TestTemplateEngine()); view.setApplicationContext(this.webAppContext); @@ -109,35 +104,30 @@ public class GroovyMarkupViewTests { @Test public void checkResource() throws Exception { - GroovyMarkupView view = createViewWithUrl("test.tpl"); assertTrue(view.checkResource(Locale.US)); } @Test public void checkMissingResource() throws Exception { - GroovyMarkupView view = createViewWithUrl("missing.tpl"); assertFalse(view.checkResource(Locale.US)); } @Test public void checkI18nResource() throws Exception { - GroovyMarkupView view = createViewWithUrl("i18n.tpl"); assertTrue(view.checkResource(Locale.FRENCH)); } @Test public void checkI18nResourceMissingLocale() throws Exception { - GroovyMarkupView view = createViewWithUrl("i18n.tpl"); assertTrue(view.checkResource(Locale.CHINESE)); } @Test public void renderMarkupTemplate() throws Exception { - Map model = new HashMap<>(); model.put("name", "Spring"); MockHttpServletResponse response = renderViewWithModel("test.tpl", model, Locale.US); @@ -155,7 +145,7 @@ public class GroovyMarkupViewTests { assertEquals("

Include German

Hallo Spring

", response.getContentAsString()); response = renderViewWithModel("i18n.tpl", model, new Locale("es")); - assertEquals("

Include Default

¡hola Spring

", response.getContentAsString()); + assertEquals("

Include Default

Hola Spring

", response.getContentAsString()); } @Test @@ -166,30 +156,30 @@ public class GroovyMarkupViewTests { response.getContentAsString()); } - private MockHttpServletResponse renderViewWithModel(String viewUrl, Map model, Locale locale) throws Exception { + private MockHttpServletResponse renderViewWithModel(String viewUrl, Map model, Locale locale) throws Exception { GroovyMarkupView view = createViewWithUrl(viewUrl); MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletRequest request = new MockHttpServletRequest(); - request.setPreferredLocales(Arrays.asList(locale)); + request.addPreferredLocale(locale); LocaleContextHolder.setLocale(locale); view.renderMergedTemplateModel(model, request, response); return response; } private GroovyMarkupView createViewWithUrl(String viewUrl) throws Exception { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(GroovyMarkupConfiguration.class); ctx.refresh(); GroovyMarkupView view = new GroovyMarkupView(); - view.setApplicationContext(ctx); view.setUrl(viewUrl); + view.setApplicationContext(ctx); view.afterPropertiesSet(); return view; } + public class TestTemplateEngine extends MarkupTemplateEngine { public TestTemplateEngine() { @@ -197,11 +187,12 @@ public class GroovyMarkupViewTests { } @Override - public Template createTemplate(Reader reader) throws CompilationFailedException, ClassNotFoundException, IOException { + public Template createTemplate(Reader reader) { return null; } } + @Configuration static class GroovyMarkupConfiguration { @@ -212,4 +203,5 @@ public class GroovyMarkupViewTests { return configurer; } } + } diff --git a/spring-webmvc/src/test/resources/org/springframework/web/servlet/view/groovy/i18n_es.tpl b/spring-webmvc/src/test/resources/org/springframework/web/servlet/view/groovy/i18n_es.tpl index 2d52884bde..169951e0d6 100644 --- a/spring-webmvc/src/test/resources/org/springframework/web/servlet/view/groovy/i18n_es.tpl +++ b/spring-webmvc/src/test/resources/org/springframework/web/servlet/view/groovy/i18n_es.tpl @@ -1,2 +1,2 @@ include template: 'includes/include.tpl' -p('¡hola Spring') \ No newline at end of file +p('Hola Spring') \ No newline at end of file