Skip to content

Commit 049169d

Browse files
committed
ResourcePropertyResource accepts EncodedResource for properties files with a specific encoding
Also added constructor with Charset argument to EncodedResource. Issue: SPR-10096
1 parent ede9d53 commit 049169d

File tree

4 files changed

+148
-71
lines changed

4 files changed

+148
-71
lines changed

spring-core/src/main/java/org/springframework/core/io/support/EncodedResource.java

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,8 +17,10 @@
1717
package org.springframework.core.io.support;
1818

1919
import java.io.IOException;
20+
import java.io.InputStream;
2021
import java.io.InputStreamReader;
2122
import java.io.Reader;
23+
import java.nio.charset.Charset;
2224

2325
import org.springframework.core.io.Resource;
2426
import org.springframework.util.Assert;
@@ -39,7 +41,9 @@ public class EncodedResource {
3941

4042
private final Resource resource;
4143

42-
private final String encoding;
44+
private String encoding;
45+
46+
private Charset charset;
4347

4448

4549
/**
@@ -48,7 +52,8 @@ public class EncodedResource {
4852
* @param resource the Resource to hold
4953
*/
5054
public EncodedResource(Resource resource) {
51-
this(resource, null);
55+
Assert.notNull(resource, "Resource must not be null");
56+
this.resource = resource;
5257
}
5358

5459
/**
@@ -63,6 +68,18 @@ public EncodedResource(Resource resource, String encoding) {
6368
this.encoding = encoding;
6469
}
6570

71+
/**
72+
* Create a new EncodedResource for the given Resource,
73+
* using the specified encoding.
74+
* @param resource the Resource to hold
75+
* @param charset the charset to use for reading from the resource
76+
*/
77+
public EncodedResource(Resource resource, Charset charset) {
78+
Assert.notNull(resource, "Resource must not be null");
79+
this.resource = resource;
80+
this.charset = charset;
81+
}
82+
6683

6784
/**
6885
* Return the Resource held.
@@ -79,20 +96,53 @@ public final String getEncoding() {
7996
return this.encoding;
8097
}
8198

99+
/**
100+
* Return the charset to use for reading from the resource,
101+
* or {@code null} if none specified.
102+
*/
103+
public final Charset getCharset() {
104+
return this.charset;
105+
}
106+
107+
108+
/**
109+
* Determine whether a {@link Reader} is required as opposed to an {@link InputStream},
110+
* i.e. whether an encoding or a charset has been specified.
111+
* @see #getReader()
112+
* @see #getInputStream()
113+
*/
114+
public boolean requiresReader() {
115+
return (this.encoding != null || this.charset != null);
116+
}
117+
82118
/**
83119
* Open a {@code java.io.Reader} for the specified resource,
84120
* using the specified encoding (if any).
85121
* @throws IOException if opening the Reader failed
122+
* @see #requiresReader()
86123
*/
87124
public Reader getReader() throws IOException {
88-
if (this.encoding != null) {
125+
if (this.charset != null) {
126+
return new InputStreamReader(this.resource.getInputStream(), this.charset);
127+
}
128+
else if (this.encoding != null) {
89129
return new InputStreamReader(this.resource.getInputStream(), this.encoding);
90130
}
91131
else {
92132
return new InputStreamReader(this.resource.getInputStream());
93133
}
94134
}
95135

136+
/**
137+
* Open an {@code java.io.InputStream} for the specified resource,
138+
* typically assuming that there is no specific encoding to use.
139+
* @throws IOException if opening the InputStream failed
140+
* @see #requiresReader()
141+
*/
142+
public InputStream getInputStream() throws IOException {
143+
return this.resource.getInputStream();
144+
}
145+
96146

97147
@Override
98148
public boolean equals(Object obj) {

spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderSupport.java

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,8 +17,6 @@
1717
package org.springframework.core.io.support;
1818

1919
import java.io.IOException;
20-
import java.io.InputStream;
21-
import java.io.InputStreamReader;
2220
import java.util.Properties;
2321

2422
import org.apache.commons.logging.Log;
@@ -39,9 +37,6 @@
3937
*/
4038
public abstract class PropertiesLoaderSupport {
4139

42-
public static final String XML_FILE_EXTENSION = ".xml";
43-
44-
4540
/** Logger available to subclasses */
4641
protected final Log logger = LogFactory.getLog(getClass());
4742

@@ -167,7 +162,7 @@ protected Properties mergeProperties() throws IOException {
167162
/**
168163
* Load properties into the given instance.
169164
* @param props the Properties instance to load into
170-
* @throws java.io.IOException in case of I/O errors
165+
* @throws IOException in case of I/O errors
171166
* @see #setLocations
172167
*/
173168
protected void loadProperties(Properties props) throws IOException {
@@ -176,21 +171,9 @@ protected void loadProperties(Properties props) throws IOException {
176171
if (logger.isInfoEnabled()) {
177172
logger.info("Loading properties file from " + location);
178173
}
179-
InputStream is = null;
180174
try {
181-
is = location.getInputStream();
182-
String filename = location.getFilename();
183-
if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) {
184-
this.propertiesPersister.loadFromXml(props, is);
185-
}
186-
else {
187-
if (this.fileEncoding != null) {
188-
this.propertiesPersister.load(props, new InputStreamReader(is, this.fileEncoding));
189-
}
190-
else {
191-
this.propertiesPersister.load(props, is);
192-
}
193-
}
175+
PropertiesLoaderUtils.fillProperties(
176+
props, new EncodedResource(location, this.fileEncoding), this.propertiesPersister);
194177
}
195178
catch (IOException ex) {
196179
if (this.ignoreResourceNotFound) {
@@ -202,11 +185,6 @@ protected void loadProperties(Properties props) throws IOException {
202185
throw ex;
203186
}
204187
}
205-
finally {
206-
if (is != null) {
207-
is.close();
208-
}
209-
}
210188
}
211189
}
212190
}

spring-core/src/main/java/org/springframework/core/io/support/PropertiesLoaderUtils.java

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import java.io.IOException;
2020
import java.io.InputStream;
21+
import java.io.Reader;
2122
import java.net.URL;
2223
import java.net.URLConnection;
2324
import java.util.Enumeration;
@@ -26,6 +27,8 @@
2627
import org.springframework.core.io.Resource;
2728
import org.springframework.util.Assert;
2829
import org.springframework.util.ClassUtils;
30+
import org.springframework.util.DefaultPropertiesPersister;
31+
import org.springframework.util.PropertiesPersister;
2932
import org.springframework.util.ResourceUtils;
3033

3134
/**
@@ -42,6 +45,9 @@
4245
*/
4346
public abstract class PropertiesLoaderUtils {
4447

48+
private static final String XML_FILE_EXTENSION = ".xml";
49+
50+
4551
/**
4652
* Load properties from the given resource.
4753
* @param resource the resource to load from
@@ -120,4 +126,52 @@ public static Properties loadAllProperties(String resourceName, ClassLoader clas
120126
return properties;
121127
}
122128

129+
130+
/**
131+
* Load the properties from the given encoded resource.
132+
* @see #fillProperties
133+
*/
134+
static Properties loadProperties(EncodedResource resource) throws IOException {
135+
Properties props = new Properties();
136+
fillProperties(props, resource, new DefaultPropertiesPersister());
137+
return props;
138+
}
139+
140+
/**
141+
* Actually load properties from the given EncodedResource into the given Properties instance.
142+
* @param props the Properties instance to load into
143+
* @param resource the resource to load from
144+
* @param persister the PropertiesPersister to use
145+
* @throws IOException in case of I/O errors
146+
*/
147+
static void fillProperties(Properties props, EncodedResource resource, PropertiesPersister persister)
148+
throws IOException {
149+
150+
InputStream stream = null;
151+
Reader reader = null;
152+
try {
153+
String filename = resource.getResource().getFilename();
154+
if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) {
155+
stream = resource.getInputStream();
156+
persister.loadFromXml(props, stream);
157+
}
158+
else if (resource.requiresReader()) {
159+
reader = resource.getReader();
160+
persister.load(props, reader);
161+
}
162+
else {
163+
stream = resource.getInputStream();
164+
persister.load(props, stream);
165+
}
166+
}
167+
finally {
168+
if (stream != null) {
169+
stream.close();
170+
}
171+
if (reader != null) {
172+
reader.close();
173+
}
174+
}
175+
}
176+
123177
}

spring-core/src/main/java/org/springframework/core/io/support/ResourcePropertySource.java

Lines changed: 35 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,11 @@
1717
package org.springframework.core.io.support;
1818

1919
import java.io.IOException;
20-
import java.io.InputStream;
2120
import java.util.Properties;
2221

2322
import org.springframework.core.env.PropertiesPropertySource;
23+
import org.springframework.core.io.DefaultResourceLoader;
2424
import org.springframework.core.io.Resource;
25-
import org.springframework.util.ClassUtils;
2625
import org.springframework.util.StringUtils;
2726

2827
/**
@@ -35,16 +34,34 @@
3534
* return non-{@code null} and end in ".xml".
3635
*
3736
* @author Chris Beams
37+
* @author Juergen Hoeller
3838
* @since 3.1
3939
*/
4040
public class ResourcePropertySource extends PropertiesPropertySource {
4141

4242
/**
4343
* Create a PropertySource having the given name based on Properties
44-
* loaded from the given resource.
44+
* loaded from the given encoded resource.
45+
*/
46+
public ResourcePropertySource(String name, EncodedResource resource) throws IOException {
47+
super(name, PropertiesLoaderUtils.loadProperties(resource));
48+
}
49+
50+
/**
51+
* Create a PropertySource based on Properties loaded from the given resource.
52+
* The name of the PropertySource will be generated based on the
53+
* {@link Resource#getDescription() description} of the given resource.
54+
*/
55+
public ResourcePropertySource(EncodedResource resource) throws IOException {
56+
this(getNameForResource(resource.getResource()), resource);
57+
}
58+
59+
/**
60+
* Create a PropertySource having the given name based on Properties
61+
* loaded from the given encoded resource.
4562
*/
4663
public ResourcePropertySource(String name, Resource resource) throws IOException {
47-
super(name, loadPropertiesForResource(resource));
64+
super(name, PropertiesLoaderUtils.loadProperties(new EncodedResource(resource)));
4865
}
4966

5067
/**
@@ -62,17 +79,7 @@ public ResourcePropertySource(Resource resource) throws IOException {
6279
* resource (assuming it is prefixed with {@code classpath:}).
6380
*/
6481
public ResourcePropertySource(String name, String location, ClassLoader classLoader) throws IOException {
65-
this(name, getResourceForLocation(location, classLoader));
66-
}
67-
68-
/**
69-
* Create a PropertySource having the given name based on Properties loaded from
70-
* the given resource location. The default thread context class loader will be
71-
* used to load the resource (assuming the location string is prefixed with
72-
* {@code classpath:}.
73-
*/
74-
public ResourcePropertySource(String name, String location) throws IOException {
75-
this(name, location, ClassUtils.getDefaultClassLoader());
82+
this(name, new DefaultResourceLoader(classLoader).getResource(location));
7683
}
7784

7885
/**
@@ -83,7 +90,17 @@ public ResourcePropertySource(String name, String location) throws IOException {
8390
* resource.
8491
*/
8592
public ResourcePropertySource(String location, ClassLoader classLoader) throws IOException {
86-
this(getResourceForLocation(location, classLoader));
93+
this(new DefaultResourceLoader(classLoader).getResource(location));
94+
}
95+
96+
/**
97+
* Create a PropertySource having the given name based on Properties loaded from
98+
* the given resource location. The default thread context class loader will be
99+
* used to load the resource (assuming the location string is prefixed with
100+
* {@code classpath:}.
101+
*/
102+
public ResourcePropertySource(String name, String location) throws IOException {
103+
this(name, new DefaultResourceLoader().getResource(location));
87104
}
88105

89106
/**
@@ -92,34 +109,12 @@ public ResourcePropertySource(String location, ClassLoader classLoader) throws I
92109
* {@link Resource#getDescription() description} of the resource.
93110
*/
94111
public ResourcePropertySource(String location) throws IOException {
95-
this(getResourceForLocation(location, ClassUtils.getDefaultClassLoader()));
96-
}
97-
98-
99-
private static Resource getResourceForLocation(String location, ClassLoader classLoader) {
100-
return new PathMatchingResourcePatternResolver(classLoader).getResource(location);
112+
this(new DefaultResourceLoader().getResource(location));
101113
}
102114

103-
private static Properties loadPropertiesForResource(Resource resource) throws IOException {
104-
Properties props = new Properties();
105-
InputStream is = resource.getInputStream();
106-
String filename = resource.getFilename();
107-
if (filename != null && filename.endsWith(".xml")) {
108-
props.loadFromXML(is);
109-
}
110-
else {
111-
props.load(is);
112-
}
113-
try {
114-
is.close();
115-
} catch (IOException ex) {
116-
// ignore
117-
}
118-
return props;
119-
}
120115

121116
/**
122-
* Returns the description string for the resource, and if empty returns
117+
* Return the description string for the resource, and if empty returns
123118
* the class name of the resource plus its identity hash code.
124119
*/
125120
private static String getNameForResource(Resource resource) {

0 commit comments

Comments
 (0)