Narrow String properties to a more precise type

We envision that IDE will support auto-completion for known types in the
future, for instance Charset, MimeType, Resource and Locale. Some of our
own configuration keys use a raw String type whereas they actually
represent a higher-level concept.

We now make sure to expose these with a better type, if applicable.

Closes gh-2898
This commit is contained in:
Stephane Nicoll 2015-07-10 13:38:05 +02:00
parent c4c24b1f44
commit e52c190b05
20 changed files with 182 additions and 62 deletions

View File

@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
@ -68,7 +69,7 @@ public class MessageSourceAutoConfiguration {
/**
* Message bundles encoding.
*/
private String encoding = "utf-8";
private Charset encoding = Charset.forName("UTF-8");
/**
* Loaded resource bundle files cache expiration, in seconds. When set to -1, bundles
@ -83,7 +84,7 @@ public class MessageSourceAutoConfiguration {
messageSource
.setBasenames(commaDelimitedListToStringArray(trimAllWhitespace(this.basename)));
}
messageSource.setDefaultEncoding(this.encoding);
messageSource.setDefaultEncoding(this.encoding.name());
messageSource.setCacheSeconds(this.cacheSeconds);
return messageSource;
}
@ -96,11 +97,11 @@ public class MessageSourceAutoConfiguration {
this.basename = basename;
}
public String getEncoding() {
public Charset getEncoding() {
return this.encoding;
}
public void setEncoding(String encoding) {
public void setEncoding(Charset encoding) {
this.encoding = encoding;
}

View File

@ -92,7 +92,7 @@ public class FreeMarkerAutoConfiguration {
protected void applyProperties(FreeMarkerConfigurationFactory factory) {
factory.setTemplateLoaderPaths(this.properties.getTemplateLoaderPath());
factory.setPreferFileSystemAccess(this.properties.isPreferFileSystemAccess());
factory.setDefaultEncoding(this.properties.getCharset());
factory.setDefaultEncoding(this.properties.getCharsetName());
Properties settings = new Properties();
settings.putAll(this.properties.getSettings());
factory.setFreemarkerSettings(settings);

View File

@ -146,7 +146,9 @@ class DataSourceInitializer implements ApplicationListener<DataSourceInitialized
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
populator.setContinueOnError(this.properties.isContinueOnError());
populator.setSeparator(this.properties.getSeparator());
populator.setSqlScriptEncoding(this.properties.getSqlScriptEncoding());
if (this.properties.getSqlScriptEncoding() != null) {
populator.setSqlScriptEncoding(this.properties.getSqlScriptEncoding().name());
}
for (Resource resource : resources) {
populator.addScript(resource);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2015 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.
@ -16,6 +16,7 @@
package org.springframework.boot.autoconfigure.jdbc;
import java.nio.charset.Charset;
import java.util.LinkedHashMap;
import java.util.Map;
@ -100,7 +101,7 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
/**
* SQL scripts encoding.
*/
private String sqlScriptEncoding;
private Charset sqlScriptEncoding;
private EmbeddedDatabaseConnection embeddedDatabaseConnection = EmbeddedDatabaseConnection.NONE;
@ -256,11 +257,11 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
this.separator = separator;
}
public String getSqlScriptEncoding() {
public Charset getSqlScriptEncoding() {
return this.sqlScriptEncoding;
}
public void setSqlScriptEncoding(String sqlScriptEncoding) {
public void setSqlScriptEncoding(Charset sqlScriptEncoding) {
this.sqlScriptEncoding = sqlScriptEncoding;
}

View File

@ -16,6 +16,7 @@
package org.springframework.boot.autoconfigure.mail;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
@ -32,6 +33,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "spring.mail")
public class MailProperties {
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
/**
* SMTP server host.
*/
@ -55,7 +58,7 @@ public class MailProperties {
/**
* Default MimeMessage encoding.
*/
private String defaultEncoding = "UTF-8";
private Charset defaultEncoding = DEFAULT_CHARSET;
/**
* Additional JavaMail session properties.
@ -104,11 +107,11 @@ public class MailProperties {
this.password = password;
}
public String getDefaultEncoding() {
public Charset getDefaultEncoding() {
return this.defaultEncoding;
}
public void setDefaultEncoding(String defaultEncoding) {
public void setDefaultEncoding(Charset defaultEncoding) {
this.defaultEncoding = defaultEncoding;
}

View File

@ -78,7 +78,7 @@ public class MailSenderAutoConfiguration {
}
sender.setUsername(this.properties.getUsername());
sender.setPassword(this.properties.getPassword());
sender.setDefaultEncoding(this.properties.getDefaultEncoding());
sender.setDefaultEncoding(this.properties.getDefaultEncoding().name());
if (!this.properties.getProperties().isEmpty()) {
sender.setJavaMailProperties(asProperties(this.properties.getProperties()));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013-2015 the original author or authors.
* Copyright 2012-2015 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.
@ -88,7 +88,7 @@ public class MustacheAutoConfiguration {
public MustacheResourceTemplateLoader mustacheTemplateLoader() {
MustacheResourceTemplateLoader loader = new MustacheResourceTemplateLoader(
this.mustache.getPrefix(), this.mustache.getSuffix());
loader.setCharset(this.mustache.getCharset());
loader.setCharset(this.mustache.getCharsetName());
return loader;
}
@ -107,8 +107,8 @@ public class MustacheAutoConfiguration {
resolver.setSuffix(this.mustache.getSuffix());
resolver.setCache(this.mustache.isCache());
resolver.setViewNames(this.mustache.getViewNames());
resolver.setContentType(this.mustache.getContentType());
resolver.setCharset(this.mustache.getCharset());
resolver.setContentType(this.mustache.getContentType().toString());
resolver.setCharset(this.mustache.getCharsetName());
resolver.setCompiler(mustacheCompiler);
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
return resolver;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2015 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.
@ -146,7 +146,7 @@ public abstract class AbstractTemplateViewResolverProperties extends
resolver.setPrefix(getPrefix());
resolver.setSuffix(getSuffix());
resolver.setCache(isCache());
resolver.setContentType(getContentType());
resolver.setContentType(getContentType().toString());
resolver.setViewNames(getViewNames());
resolver.setExposeRequestAttributes(isExposeRequestAttributes());
resolver.setAllowRequestOverride(isAllowRequestOverride());

View File

@ -16,7 +16,14 @@
package org.springframework.boot.autoconfigure.template;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.MimeType;
import org.springframework.web.servlet.ViewResolver;
/**
@ -29,6 +36,10 @@ import org.springframework.web.servlet.ViewResolver;
*/
public abstract class AbstractViewResolverProperties {
private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
/**
* Enable MVC view resolution for this technology.
*/
@ -42,12 +53,12 @@ public abstract class AbstractViewResolverProperties {
/**
* Content-Type value.
*/
private String contentType = "text/html";
private MimeType contentType = DEFAULT_CONTENT_TYPE;
/**
* Template encoding.
*/
private String charset = "UTF-8";
private Charset charset = DEFAULT_CHARSET;
/**
* White list of view names that can be resolved.
@ -91,22 +102,32 @@ public abstract class AbstractViewResolverProperties {
this.cache = cache;
}
public String getContentType() {
return this.contentType
+ (this.contentType.contains(";charset=") ? "" : ";charset="
+ this.charset);
public MimeType getContentType() {
return (this.contentType.getCharSet() != null ? this.contentType :
new MimeType(this.contentType, cloneParametersWithCustomCharset(this.contentType, this.charset)));
}
public void setContentType(String contentType) {
public void setContentType(MimeType contentType) {
this.contentType = contentType;
}
public String getCharset() {
public Charset getCharset() {
return this.charset;
}
public void setCharset(String charset) {
public String getCharsetName() {
return (this.charset != null ? this.charset.name() : null);
}
public void setCharset(Charset charset) {
this.charset = charset;
}
private static Map<String,String> cloneParametersWithCustomCharset(MimeType contentType, Charset charset) {
LinkedHashMap<String,String> clone = new LinkedHashMap<String, String>();
clone.put("charset", charset.name());
clone.putAll(contentType.getParameters());
return clone;
}
}

View File

@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.thymeleaf;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import javax.annotation.PostConstruct;
import javax.servlet.Servlet;
@ -39,6 +40,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.util.Assert;
import org.springframework.util.MimeType;
import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;
import org.thymeleaf.dialect.IDialect;
import org.thymeleaf.extras.conditionalcomments.dialect.ConditionalCommentsDialect;
@ -95,7 +97,7 @@ public class ThymeleafAutoConfiguration {
resolver.setPrefix(this.properties.getPrefix());
resolver.setSuffix(this.properties.getSuffix());
resolver.setTemplateMode(this.properties.getMode());
resolver.setCharacterEncoding(this.properties.getEncoding());
resolver.setCharacterEncoding(this.properties.getEncoding().name());
resolver.setCacheable(this.properties.isCache());
return resolver;
}
@ -195,7 +197,7 @@ public class ThymeleafAutoConfiguration {
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(this.templateEngine);
resolver.setCharacterEncoding(this.properties.getEncoding());
resolver.setCharacterEncoding(this.properties.getEncoding().name());
resolver.setContentType(appendCharset(this.properties.getContentType(),
resolver.getCharacterEncoding()));
resolver.setExcludedViewNames(this.properties.getExcludedViewNames());
@ -206,11 +208,14 @@ public class ThymeleafAutoConfiguration {
return resolver;
}
private String appendCharset(String type, String charset) {
if (type.contains("charset=")) {
return type;
private String appendCharset(MimeType type, String charset) {
if (type.getCharSet() != null) {
return type.toString();
}
return type + ";charset=" + charset;
LinkedHashMap<String,String> clone = new LinkedHashMap<String, String>();
clone.put("charset", charset);
clone.putAll(type.getParameters());
return new MimeType(type, clone).toString();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2015 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.
@ -16,7 +16,10 @@
package org.springframework.boot.autoconfigure.thymeleaf;
import java.nio.charset.Charset;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.MimeType;
/**
* Properties for Thymeleaf.
@ -27,6 +30,10 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8");
private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
@ -54,12 +61,12 @@ public class ThymeleafProperties {
/**
* Template encoding.
*/
private String encoding = "UTF-8";
private Charset encoding = DEFAULT_ENCODING;
/**
* Content-Type value.
*/
private String contentType = "text/html";
private MimeType contentType = DEFAULT_CONTENT_TYPE;
/**
* Enable template caching.
@ -121,19 +128,19 @@ public class ThymeleafProperties {
this.mode = mode;
}
public String getEncoding() {
public Charset getEncoding() {
return this.encoding;
}
public void setEncoding(String encoding) {
public void setEncoding(Charset encoding) {
this.encoding = encoding;
}
public String getContentType() {
public MimeType getContentType() {
return this.contentType;
}
public void setContentType(String contentType) {
public void setContentType(MimeType contentType) {
this.contentType = contentType;
}

View File

@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.web;
import java.io.File;
import java.net.InetAddress;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@ -508,7 +509,7 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
/**
* Character encoding to use to decode the URI.
*/
private String uriEncoding;
private Charset uriEncoding;
public int getMaxThreads() {
return this.maxThreads;
@ -598,11 +599,11 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
this.remoteIpHeader = remoteIpHeader;
}
public String getUriEncoding() {
public Charset getUriEncoding() {
return this.uriEncoding;
}
public void setUriEncoding(String uriEncoding) {
public void setUriEncoding(Charset uriEncoding) {
this.uriEncoding = uriEncoding;
}

View File

@ -52,7 +52,6 @@ import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.StringUtils;
import org.springframework.validation.DefaultMessageCodesResolver;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.web.accept.ContentNegotiationManager;
@ -187,8 +186,7 @@ public class WebMvcAutoConfiguration {
@ConditionalOnMissingBean(LocaleResolver.class)
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
return new FixedLocaleResolver(
StringUtils.parseLocaleString(this.mvcProperties.getLocale()));
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
@Bean

View File

@ -16,6 +16,8 @@
package org.springframework.boot.autoconfigure.web;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.DefaultMessageCodesResolver;
@ -39,7 +41,7 @@ public class WebMvcProperties {
/**
* Locale to use.
*/
private String locale;
private Locale locale;
/**
* Date format to use (e.g. dd/MM/yyyy).
@ -65,11 +67,11 @@ public class WebMvcProperties {
this.messageCodesResolverFormat = messageCodesResolverFormat;
}
public String getLocale() {
public Locale getLocale() {
return this.locale;
}
public void setLocale(String locale) {
public void setLocale(Locale locale) {
this.locale = locale;
}

View File

@ -107,14 +107,14 @@ public class MailSenderAutoConfigurationTests {
String host = "192.168.1.234";
load(EmptyConfig.class, "spring.mail.host:" + host, "spring.mail.port:42",
"spring.mail.username:john", "spring.mail.password:secret",
"spring.mail.default-encoding:ISO-9");
"spring.mail.default-encoding:US-ASCII");
JavaMailSenderImpl bean = (JavaMailSenderImpl) this.context
.getBean(JavaMailSender.class);
assertEquals(host, bean.getHost());
assertEquals(42, bean.getPort());
assertEquals("john", bean.getUsername());
assertEquals("secret", bean.getPassword());
assertEquals("ISO-9", bean.getDefaultEncoding());
assertEquals("US-ASCII", bean.getDefaultEncoding());
}
@Test

View File

@ -0,0 +1,75 @@
/*
* Copyright 2012-2015 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.template;
import java.nio.charset.Charset;
import org.junit.Test;
import org.springframework.util.MimeTypeUtils;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasToString;
/**
* Tests for {@link AbstractViewResolverProperties}.
*
* @author Stephane Nicoll
*/
public class ViewResolverPropertiesTest {
@Test
public void defaultContentType() {
assertThat(new ViewResolverProperties().getContentType(), hasToString("text/html;charset=UTF-8"));
}
@Test
public void customContentTypeDefaultCharset() {
ViewResolverProperties properties = new ViewResolverProperties();
properties.setContentType(MimeTypeUtils.parseMimeType("text/plain"));
assertThat(properties.getContentType(), hasToString("text/plain;charset=UTF-8"));
}
@Test
public void defaultContentTypeCustomCharset() {
ViewResolverProperties properties = new ViewResolverProperties();
properties.setCharset(Charset.forName("UTF-16"));
assertThat(properties.getContentType(), hasToString("text/html;charset=UTF-16"));
}
@Test
public void customContentTypeCustomCharset() {
ViewResolverProperties properties = new ViewResolverProperties();
properties.setContentType(MimeTypeUtils.parseMimeType("text/plain"));
properties.setCharset(Charset.forName("UTF-16"));
assertThat(properties.getContentType(), hasToString("text/plain;charset=UTF-16"));
}
@Test
public void customContentTypeWithPropertyAndCustomCharset() {
ViewResolverProperties properties = new ViewResolverProperties();
properties.setContentType(MimeTypeUtils.parseMimeType("text/plain;foo=bar"));
properties.setCharset(Charset.forName("UTF-16"));
assertThat(properties.getContentType(), hasToString("text/plain;charset=UTF-16;foo=bar"));
}
private static class ViewResolverProperties extends AbstractViewResolverProperties {
}
}

View File

@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure.web;
import java.net.InetAddress;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
@ -204,7 +205,7 @@ public class ServerPropertiesTests {
Map<String, String> map = new HashMap<String, String>();
map.put("server.tomcat.uriEncoding", "US-ASCII");
bindProperties(map);
assertEquals("US-ASCII", this.properties.getTomcat().getUriEncoding());
assertEquals(Charset.forName("US-ASCII"), this.properties.getTomcat().getUriEncoding());
}
@Test

View File

@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@ -89,6 +89,8 @@ import org.springframework.util.StringUtils;
public class TomcatEmbeddedServletContainerFactory extends
AbstractEmbeddedServletContainerFactory implements ResourceLoaderAware {
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private static final Set<Class<?>> NO_CLASSES = Collections.emptySet();
public static final String DEFAULT_PROTOCOL = "org.apache.coyote.http11.Http11NioProtocol";
@ -111,7 +113,7 @@ public class TomcatEmbeddedServletContainerFactory extends
private String tldSkip;
private String uriEncoding = "UTF-8";
private Charset uriEncoding = DEFAULT_CHARSET;
/**
* Create a new {@link TomcatEmbeddedServletContainerFactory} instance.
@ -237,7 +239,7 @@ public class TomcatEmbeddedServletContainerFactory extends
customizeProtocol((AbstractProtocol<?>) connector.getProtocolHandler());
}
if (getUriEncoding() != null) {
connector.setURIEncoding(getUriEncoding());
connector.setURIEncoding(getUriEncoding().name());
}
// If ApplicationContext is slow to start we want Tomcat not to bind to the socket
@ -614,7 +616,7 @@ public class TomcatEmbeddedServletContainerFactory extends
* be used.
* @param uriEncoding the uri encoding to set
*/
public void setUriEncoding(String uriEncoding) {
public void setUriEncoding(Charset uriEncoding) {
this.uriEncoding = uriEncoding;
}
@ -622,7 +624,7 @@ public class TomcatEmbeddedServletContainerFactory extends
* Returns the character encoding to use for URL decoding.
* @return the URI encoding
*/
public String getUriEncoding() {
public Charset getUriEncoding() {
return this.uriEncoding;
}

View File

@ -12,7 +12,7 @@
},
{
"name": "banner.location",
"type": "java.lang.String",
"type": "org.springframework.core.io.Resource",
"description": "Banner file location.",
"defaultValue": "classpath:banner.txt"
},

View File

@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@ -19,6 +19,7 @@ package org.springframework.boot.context.embedded.tomcat;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@ -226,7 +227,7 @@ public class TomcatEmbeddedServletContainerFactoryTests extends
@Test
public void uriEncoding() throws Exception {
TomcatEmbeddedServletContainerFactory factory = getFactory();
factory.setUriEncoding("US-ASCII");
factory.setUriEncoding(Charset.forName("US-ASCII"));
Tomcat tomcat = getTomcat(factory);
assertEquals("US-ASCII", tomcat.getConnector().getURIEncoding());
}