From f9783127e910e61ca96793412c198368535f799b Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Wed, 11 May 2011 13:28:05 +0000 Subject: [PATCH] Introduce ResourcePropertySource Allows convenient creation of a Properties-based PropertySource from a Spring Resource object or resource location string such as "classpath:com/myco/app.properties" or "file:/path/to/file.properties" Issue: SPR-8328 git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@4288 50f2f4bb-b051-0410-bef5-90022cba6387 --- .../core/io/ResourcePropertySource.java | 123 ++++++++++++++++++ .../core/io/ResourcePropertySourceTests.java | 91 +++++++++++++ .../core/io/example.properties | 1 + 3 files changed, 215 insertions(+) create mode 100644 org.springframework.core/src/main/java/org/springframework/core/io/ResourcePropertySource.java create mode 100644 org.springframework.core/src/test/java/org/springframework/core/io/ResourcePropertySourceTests.java create mode 100644 org.springframework.core/src/test/java/org/springframework/core/io/example.properties diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/ResourcePropertySource.java b/org.springframework.core/src/main/java/org/springframework/core/io/ResourcePropertySource.java new file mode 100644 index 00000000000..d86f53f1fda --- /dev/null +++ b/org.springframework.core/src/main/java/org/springframework/core/io/ResourcePropertySource.java @@ -0,0 +1,123 @@ +/* + * Copyright 2002-2011 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.core.io; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; + +/** + * Subclass of {@link PropertiesPropertySource} that loads a {@link Properties} + * object from a given {@link Resource} or resource location such as + * {@code "classpath:/com/myco/foo.properties"} or {@code "file:/path/to/file.properties"}. + * + * @author Chris Beams + * @since 3.1 + */ +public class ResourcePropertySource extends PropertiesPropertySource { + + /** + * Create a PropertySource having the given name based on Properties + * loaded from the given resource. + */ + public ResourcePropertySource(String name, Resource resource) throws IOException { + super(name, loadPropertiesForResource(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(Resource resource) throws IOException { + this(getNameForResource(resource), resource); + } + + /** + * Create a PropertySource having the given name based on Properties loaded from + * the given resource location and using the given class loader to load the + * 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()); + } + + /** + * Create a PropertySource based on Properties loaded from the given resource + * location and use the given class loader to load the resource, assuming it is + * prefixed with {@code classpath:}. The name of the PropertySource will be + * generated based on the {@link Resource#getDescription() description} of the + * resource. + */ + public ResourcePropertySource(String location, ClassLoader classLoader) throws IOException { + this(getResourceForLocation(location, classLoader)); + } + + /** + * Create a PropertySource based on Properties loaded from the given resource + * location. The name of the PropertySource will be generated based on the + * {@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); + } + + private static Properties loadPropertiesForResource(Resource resource) throws IOException { + Properties props = new Properties(); + InputStream is = resource.getInputStream(); + props.load(is); + try { + is.close(); + } catch (IOException ex) { + // ignore + } + return props; + } + + /** + * Returns 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) { + String name = resource.getDescription(); + if (!StringUtils.hasText(name)) { + name = resource.getClass().getSimpleName() + "@" + System.identityHashCode(resource); + } + return name; + } + +} diff --git a/org.springframework.core/src/test/java/org/springframework/core/io/ResourcePropertySourceTests.java b/org.springframework.core/src/test/java/org/springframework/core/io/ResourcePropertySourceTests.java new file mode 100644 index 00000000000..0a7f126a6a3 --- /dev/null +++ b/org.springframework.core/src/test/java/org/springframework/core/io/ResourcePropertySourceTests.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2011 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.core.io; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.easymock.internal.matchers.StartsWith; +import org.junit.Test; +import org.springframework.core.env.PropertySource; + +/** + * Unit tests for {@link ResourcePropertySource}. + * + * @author Chris Beams + * @since 3.1 + */ +public class ResourcePropertySourceTests { + + private static final String PROPERTIES_PATH = "org/springframework/core/io/example.properties"; + private static final String PROPERTIES_LOCATION = "classpath:" + PROPERTIES_PATH; + private static final String PROPERTIES_RESOURCE_DESCRIPTION = "class path resource [" + PROPERTIES_PATH + "]"; + + @Test + public void withLocationAndGeneratedName() throws IOException { + PropertySource ps = new ResourcePropertySource(PROPERTIES_LOCATION); + assertEquals(ps.getProperty("foo"), "bar"); + assertThat(ps.getName(), is(PROPERTIES_RESOURCE_DESCRIPTION)); + } + + @Test + public void withLocationAndExplicitName() throws IOException { + PropertySource ps = new ResourcePropertySource("ps1", PROPERTIES_LOCATION); + assertEquals(ps.getProperty("foo"), "bar"); + assertThat(ps.getName(), is("ps1")); + } + + @Test + public void withLocationAndExplicitNameAndExplicitClassLoader() throws IOException { + PropertySource ps = new ResourcePropertySource("ps1", PROPERTIES_LOCATION, getClass().getClassLoader()); + assertEquals(ps.getProperty("foo"), "bar"); + assertThat(ps.getName(), is("ps1")); + } + + @Test + public void withLocationAndGeneratedNameAndExplicitClassLoader() throws IOException { + PropertySource ps = new ResourcePropertySource(PROPERTIES_LOCATION, getClass().getClassLoader()); + assertEquals(ps.getProperty("foo"), "bar"); + assertThat(ps.getName(), is(PROPERTIES_RESOURCE_DESCRIPTION)); + } + + @Test + public void withResourceAndGeneratedName() throws IOException { + PropertySource ps = new ResourcePropertySource(new ClassPathResource(PROPERTIES_PATH)); + assertEquals(ps.getProperty("foo"), "bar"); + assertThat(ps.getName(), is(PROPERTIES_RESOURCE_DESCRIPTION)); + } + + @Test + public void withResourceAndExplicitName() throws IOException { + PropertySource ps = new ResourcePropertySource("ps1", new ClassPathResource(PROPERTIES_PATH)); + assertEquals(ps.getProperty("foo"), "bar"); + assertThat(ps.getName(), is("ps1")); + } + + @Test + public void withResourceHavingNoDescriptionAndGeneratedName() throws IOException { + PropertySource ps = new ResourcePropertySource(new ByteArrayResource("foo=bar".getBytes(), "")); + assertEquals(ps.getProperty("foo"), "bar"); + assertTrue(ps.getName().startsWith("ByteArrayResource@")); + } + +} diff --git a/org.springframework.core/src/test/java/org/springframework/core/io/example.properties b/org.springframework.core/src/test/java/org/springframework/core/io/example.properties new file mode 100644 index 00000000000..74d0a43fccf --- /dev/null +++ b/org.springframework.core/src/test/java/org/springframework/core/io/example.properties @@ -0,0 +1 @@ +foo=bar