diff --git a/spring-core/src/main/java/org/springframework/core/io/support/EncodedResource.java b/spring-core/src/main/java/org/springframework/core/io/support/EncodedResource.java index 405a16e2a88..04a173836c1 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/EncodedResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/EncodedResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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.core.io.support; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.charset.Charset; import org.springframework.core.io.Resource; import org.springframework.util.Assert; @@ -39,7 +41,9 @@ public class EncodedResource { private final Resource resource; - private final String encoding; + private String encoding; + + private Charset charset; /** @@ -48,7 +52,8 @@ public class EncodedResource { * @param resource the Resource to hold */ public EncodedResource(Resource resource) { - this(resource, null); + Assert.notNull(resource, "Resource must not be null"); + this.resource = resource; } /** @@ -63,6 +68,18 @@ public class EncodedResource { this.encoding = encoding; } + /** + * Create a new EncodedResource for the given Resource, + * using the specified encoding. + * @param resource the Resource to hold + * @param charset the charset to use for reading from the resource + */ + public EncodedResource(Resource resource, Charset charset) { + Assert.notNull(resource, "Resource must not be null"); + this.resource = resource; + this.charset = charset; + } + /** * Return the Resource held. @@ -79,13 +96,36 @@ public class EncodedResource { return this.encoding; } + /** + * Return the charset to use for reading from the resource, + * or {@code null} if none specified. + */ + public final Charset getCharset() { + return this.charset; + } + + + /** + * Determine whether a {@link Reader} is required as opposed to an {@link InputStream}, + * i.e. whether an encoding or a charset has been specified. + * @see #getReader() + * @see #getInputStream() + */ + public boolean requiresReader() { + return (this.encoding != null || this.charset != null); + } + /** * Open a {@code java.io.Reader} for the specified resource, * using the specified encoding (if any). * @throws IOException if opening the Reader failed + * @see #requiresReader() */ public Reader getReader() throws IOException { - if (this.encoding != null) { + if (this.charset != null) { + return new InputStreamReader(this.resource.getInputStream(), this.charset); + } + else if (this.encoding != null) { return new InputStreamReader(this.resource.getInputStream(), this.encoding); } else { @@ -93,6 +133,16 @@ public class EncodedResource { } } + /** + * Open an {@code java.io.InputStream} for the specified resource, + * typically assuming that there is no specific encoding to use. + * @throws IOException if opening the InputStream failed + * @see #requiresReader() + */ + public InputStream getInputStream() throws IOException { + return this.resource.getInputStream(); + } + @Override public boolean equals(Object obj) { diff --git a/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderSupport.java b/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderSupport.java index d99e69806e6..1e68ba23d88 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderSupport.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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,6 @@ package org.springframework.core.io.support; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.util.Properties; import org.apache.commons.logging.Log; @@ -39,9 +37,6 @@ import org.springframework.util.PropertiesPersister; */ public abstract class PropertiesLoaderSupport { - public static final String XML_FILE_EXTENSION = ".xml"; - - /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); @@ -167,7 +162,7 @@ public abstract class PropertiesLoaderSupport { /** * Load properties into the given instance. * @param props the Properties instance to load into - * @throws java.io.IOException in case of I/O errors + * @throws IOException in case of I/O errors * @see #setLocations */ protected void loadProperties(Properties props) throws IOException { @@ -176,21 +171,9 @@ public abstract class PropertiesLoaderSupport { if (logger.isInfoEnabled()) { logger.info("Loading properties file from " + location); } - InputStream is = null; try { - is = location.getInputStream(); - String filename = location.getFilename(); - if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) { - this.propertiesPersister.loadFromXml(props, is); - } - else { - if (this.fileEncoding != null) { - this.propertiesPersister.load(props, new InputStreamReader(is, this.fileEncoding)); - } - else { - this.propertiesPersister.load(props, is); - } - } + PropertiesLoaderUtils.fillProperties( + props, new EncodedResource(location, this.fileEncoding), this.propertiesPersister); } catch (IOException ex) { if (this.ignoreResourceNotFound) { @@ -202,11 +185,6 @@ public abstract class PropertiesLoaderSupport { throw ex; } } - finally { - if (is != null) { - is.close(); - } - } } } } diff --git a/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderUtils.java b/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderUtils.java index 6f3308d8308..6aaa486fd37 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderUtils.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -18,6 +18,7 @@ package org.springframework.core.io.support; import java.io.IOException; import java.io.InputStream; +import java.io.Reader; import java.net.URL; import java.net.URLConnection; import java.util.Enumeration; @@ -26,6 +27,8 @@ import java.util.Properties; import org.springframework.core.io.Resource; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.DefaultPropertiesPersister; +import org.springframework.util.PropertiesPersister; import org.springframework.util.ResourceUtils; /** @@ -42,6 +45,9 @@ import org.springframework.util.ResourceUtils; */ public abstract class PropertiesLoaderUtils { + private static final String XML_FILE_EXTENSION = ".xml"; + + /** * Load properties from the given resource. * @param resource the resource to load from @@ -120,4 +126,52 @@ public abstract class PropertiesLoaderUtils { return properties; } + + /** + * Load the properties from the given encoded resource. + * @see #fillProperties + */ + static Properties loadProperties(EncodedResource resource) throws IOException { + Properties props = new Properties(); + fillProperties(props, resource, new DefaultPropertiesPersister()); + return props; + } + + /** + * Actually load properties from the given EncodedResource into the given Properties instance. + * @param props the Properties instance to load into + * @param resource the resource to load from + * @param persister the PropertiesPersister to use + * @throws IOException in case of I/O errors + */ + static void fillProperties(Properties props, EncodedResource resource, PropertiesPersister persister) + throws IOException { + + InputStream stream = null; + Reader reader = null; + try { + String filename = resource.getResource().getFilename(); + if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) { + stream = resource.getInputStream(); + persister.loadFromXml(props, stream); + } + else if (resource.requiresReader()) { + reader = resource.getReader(); + persister.load(props, reader); + } + else { + stream = resource.getInputStream(); + persister.load(props, stream); + } + } + finally { + if (stream != null) { + stream.close(); + } + if (reader != null) { + reader.close(); + } + } + } + } diff --git a/spring-core/src/main/java/org/springframework/core/io/support/ResourcePropertySource.java b/spring-core/src/main/java/org/springframework/core/io/support/ResourcePropertySource.java index 705d8d44e71..d07955456cc 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/ResourcePropertySource.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/ResourcePropertySource.java @@ -17,12 +17,11 @@ package org.springframework.core.io.support; import java.io.IOException; -import java.io.InputStream; import java.util.Properties; import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; -import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** @@ -35,16 +34,34 @@ import org.springframework.util.StringUtils; * return non-{@code null} and end in ".xml". * * @author Chris Beams + * @author Juergen Hoeller * @since 3.1 */ public class ResourcePropertySource extends PropertiesPropertySource { /** * Create a PropertySource having the given name based on Properties - * loaded from the given resource. + * loaded from the given encoded resource. + */ + public ResourcePropertySource(String name, EncodedResource resource) throws IOException { + super(name, PropertiesLoaderUtils.loadProperties(resource)); + } + + /** + * Create a PropertySource based on Properties loaded from the given resource. + * The name of the PropertySource will be generated based on the + * {@link Resource#getDescription() description} of the given resource. + */ + public ResourcePropertySource(EncodedResource resource) throws IOException { + this(getNameForResource(resource.getResource()), resource); + } + + /** + * Create a PropertySource having the given name based on Properties + * loaded from the given encoded resource. */ public ResourcePropertySource(String name, Resource resource) throws IOException { - super(name, loadPropertiesForResource(resource)); + super(name, PropertiesLoaderUtils.loadProperties(new EncodedResource(resource))); } /** @@ -62,17 +79,7 @@ public class ResourcePropertySource extends PropertiesPropertySource { * resource (assuming it is prefixed with {@code classpath:}). */ public ResourcePropertySource(String name, String location, ClassLoader classLoader) throws IOException { - this(name, getResourceForLocation(location, classLoader)); - } - - /** - * Create a PropertySource having the given name based on Properties loaded from - * the given resource location. The default thread context class loader will be - * used to load the resource (assuming the location string is prefixed with - * {@code classpath:}. - */ - public ResourcePropertySource(String name, String location) throws IOException { - this(name, location, ClassUtils.getDefaultClassLoader()); + this(name, new DefaultResourceLoader(classLoader).getResource(location)); } /** @@ -83,7 +90,17 @@ public class ResourcePropertySource extends PropertiesPropertySource { * resource. */ public ResourcePropertySource(String location, ClassLoader classLoader) throws IOException { - this(getResourceForLocation(location, classLoader)); + this(new DefaultResourceLoader(classLoader).getResource(location)); + } + + /** + * Create a PropertySource having the given name based on Properties loaded from + * the given resource location. The default thread context class loader will be + * used to load the resource (assuming the location string is prefixed with + * {@code classpath:}. + */ + public ResourcePropertySource(String name, String location) throws IOException { + this(name, new DefaultResourceLoader().getResource(location)); } /** @@ -92,34 +109,12 @@ public class ResourcePropertySource extends PropertiesPropertySource { * {@link Resource#getDescription() description} of the resource. */ public ResourcePropertySource(String location) throws IOException { - this(getResourceForLocation(location, ClassUtils.getDefaultClassLoader())); - } - - - private static Resource getResourceForLocation(String location, ClassLoader classLoader) { - return new PathMatchingResourcePatternResolver(classLoader).getResource(location); + this(new DefaultResourceLoader().getResource(location)); } - private static Properties loadPropertiesForResource(Resource resource) throws IOException { - Properties props = new Properties(); - InputStream is = resource.getInputStream(); - String filename = resource.getFilename(); - if (filename != null && filename.endsWith(".xml")) { - props.loadFromXML(is); - } - else { - props.load(is); - } - try { - is.close(); - } catch (IOException ex) { - // ignore - } - return props; - } /** - * Returns the description string for the resource, and if empty returns + * Return the description string for the resource, and if empty returns * the class name of the resource plus its identity hash code. */ private static String getNameForResource(Resource resource) {