8000685: (props) Properties.storeToXML/loadFromXML should only require UTF-8 and UTF-16 to be supported
Reviewed-by: mchung, chegar
--- a/jdk/src/share/classes/java/util/Properties.java Tue Oct 16 15:23:17 2012 -0700
+++ b/jdk/src/share/classes/java/util/Properties.java Wed Oct 17 11:43:56 2012 +0100
@@ -81,8 +81,9 @@
* <p> The {@link #loadFromXML(InputStream)} and {@link
* #storeToXML(OutputStream, String, String)} methods load and store properties
* in a simple XML format. By default the UTF-8 character encoding is used,
- * however a specific encoding may be specified if required. An XML properties
- * document has the following DOCTYPE declaration:
+ * however a specific encoding may be specified if required. Implementations
+ * are required to support UTF-8 and UTF-16 and may support other encodings.
+ * An XML properties document has the following DOCTYPE declaration:
*
* <pre>
* <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
@@ -853,23 +854,30 @@
* Furthermore, the document must satisfy the properties DTD described
* above.
*
+ * <p> An implementation is required to read XML documents that use the
+ * "{@code UTF-8}" or "{@code UTF-16}" encoding. An implementation may
+ * support additional encodings.
+ *
* <p>The specified stream is closed after this method returns.
*
* @param in the input stream from which to read the XML document.
* @throws IOException if reading from the specified input stream
* results in an <tt>IOException</tt>.
+ * @throws java.io.UnsupportedEncodingException if the document's encoding
+ * declaration can be read and it specifies an encoding that is not
+ * supported
* @throws InvalidPropertiesFormatException Data on input stream does not
* constitute a valid XML document with the mandated document type.
* @throws NullPointerException if {@code in} is null.
* @see #storeToXML(OutputStream, String, String)
+ * @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
+ * Encoding in Entities</a>
* @since 1.5
*/
public synchronized void loadFromXML(InputStream in)
throws IOException, InvalidPropertiesFormatException
{
- if (in == null)
- throw new NullPointerException();
- XmlSupport.load(this, in);
+ XmlSupport.load(this, Objects.requireNonNull(in));
in.close();
}
@@ -896,8 +904,6 @@
public void storeToXML(OutputStream os, String comment)
throws IOException
{
- if (os == null)
- throw new NullPointerException();
storeToXML(os, comment, "UTF-8");
}
@@ -910,9 +916,13 @@
* <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
* </pre>
*
- *<p>If the specified comment is {@code null} then no comment
+ * <p>If the specified comment is {@code null} then no comment
* will be stored in the document.
*
+ * <p> An implementation is required to support writing of XML documents
+ * that use the "{@code UTF-8}" or "{@code UTF-16}" encoding. An
+ * implementation may support additional encodings.
+ *
* <p>The specified stream remains open after this method returns.
*
* @param os the output stream on which to emit the XML document.
@@ -924,20 +934,23 @@
*
* @throws IOException if writing to the specified output stream
* results in an <tt>IOException</tt>.
+ * @throws java.io.UnsupportedEncodingException if the encoding is not
+ * supported by the implementation.
* @throws NullPointerException if {@code os} is {@code null},
* or if {@code encoding} is {@code null}.
* @throws ClassCastException if this {@code Properties} object
* contains any keys or values that are not
* {@code Strings}.
* @see #loadFromXML(InputStream)
+ * @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
+ * Encoding in Entities</a>
* @since 1.5
*/
public void storeToXML(OutputStream os, String comment, String encoding)
throws IOException
{
- if (os == null)
- throw new NullPointerException();
- XmlSupport.save(this, os, comment, encoding);
+ XmlSupport.save(this, Objects.requireNonNull(os), comment,
+ Objects.requireNonNull(encoding));
}
/**
--- a/jdk/src/share/classes/sun/util/spi/XmlPropertiesProvider.java Tue Oct 16 15:23:17 2012 -0700
+++ b/jdk/src/share/classes/sun/util/spi/XmlPropertiesProvider.java Wed Oct 17 11:43:56 2012 +0100
@@ -55,6 +55,9 @@
* @param props the properties table to populate
* @param in the input stream from which to read the XML document
* @throws IOException if reading from the specified input stream fails
+ * @throws java.io.UnsupportedEncodingException if the document's encoding
+ * declaration can be read and it specifies an encoding that is not
+ * supported
* @throws InvalidPropertiesFormatException Data on input stream does not
* constitute a valid XML document with the mandated document type.
*
@@ -73,6 +76,8 @@
* @param encoding the name of a supported character encoding
*
* @throws IOException if writing to the specified output stream fails
+ * @throws java.io.UnsupportedEncodingException if the encoding is not
+ * supported by the implementation
* @throws NullPointerException if {@code out} is null.
* @throws ClassCastException if this {@code Properties} object
* contains any keys or values that are not
--- a/jdk/src/share/classes/sun/util/xml/PlatformXmlPropertiesProvider.java Tue Oct 16 15:23:17 2012 -0700
+++ b/jdk/src/share/classes/sun/util/xml/PlatformXmlPropertiesProvider.java Wed Oct 17 11:43:56 2012 +0100
@@ -27,6 +27,7 @@
import java.io.*;
import java.util.*;
+import java.nio.charset.*;
import org.xml.sax.*;
import org.w3c.dom.*;
import javax.xml.parsers.*;
@@ -127,6 +128,13 @@
String encoding)
throws IOException
{
+ // fast-fail for unsupported charsets as UnsupportedEncodingException may
+ // not be thrown later (see JDK-8000621)
+ try {
+ Charset.forName(encoding);
+ } catch (IllegalCharsetNameException | UnsupportedCharsetException x) {
+ throw new UnsupportedEncodingException(encoding);
+ }
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = null;
try {
--- a/jdk/test/java/util/Properties/LoadAndStoreXML.java Tue Oct 16 15:23:17 2012 -0700
+++ b/jdk/test/java/util/Properties/LoadAndStoreXML.java Wed Oct 17 11:43:56 2012 +0100
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8000354
+ * @bug 8000354 8000685
* @summary Basic test of storeToXML and loadToXML
*/
@@ -66,13 +66,13 @@
* Sanity test that properties saved with Properties#storeToXML can be
* read with Properties#loadFromXML.
*/
- static void test() throws IOException {
+ static void testLoadAndStore(String encoding) throws IOException {
Properties props = new Properties();
props.put("k1", "foo");
props.put("k2", "bar");
ByteArrayOutputStream out = new ByteArrayOutputStream();
- props.storeToXML(out, "no comment");
+ props.storeToXML(out, null, encoding);
Properties p = new Properties();
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
@@ -85,19 +85,74 @@
}
}
+ /**
+ * Test loadFromXML with a document that does not have an encoding declaration
+ */
+ static void testLoadWithoutEncoding() throws IOException {
+ Properties expected = new Properties();
+ expected.put("foo", "bar");
+
+ String s = "<?xml version=\"1.0\"?>" +
+ "<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">" +
+ "<properties>" +
+ "<entry key=\"foo\">bar</entry>" +
+ "</properties>";
+ ByteArrayInputStream in = new ByteArrayInputStream(s.getBytes("UTF-8"));
+ Properties props = new Properties();
+ props.loadFromXML(in);
+
+ if (!props.equals(expected)) {
+ System.err.println("loaded: " + props + ", expected: " + expected);
+ throw new RuntimeException("Test failed");
+ }
+ }
+
+ /**
+ * Test loadFromXML with unsupported encoding
+ */
+ static void testLoadWithBadEncoding() throws IOException {
+ String s = "<?xml version=\"1.0\" encoding=\"BAD\"?>" +
+ "<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">" +
+ "<properties>" +
+ "<entry key=\"foo\">bar</entry>" +
+ "</properties>";
+ ByteArrayInputStream in = new ByteArrayInputStream(s.getBytes("UTF-8"));
+ Properties props = new Properties();
+ try {
+ props.loadFromXML(in);
+ throw new RuntimeException("UnsupportedEncodingException expected");
+ } catch (UnsupportedEncodingException expected) { }
+ }
+
+ /**
+ * Test storeToXML with unsupported encoding
+ */
+ static void testStoreWithBadEncoding() throws IOException {
+ Properties props = new Properties();
+ props.put("foo", "bar");
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try {
+ props.storeToXML(out, null, "BAD");
+ throw new RuntimeException("UnsupportedEncodingException expected");
+ } catch (UnsupportedEncodingException expected) { }
+ }
+
public static void main(String[] args) throws IOException {
- // run test without security manager
- test();
+ testLoadAndStore("UTF-8");
+ testLoadAndStore("UTF-16");
+ testLoadWithoutEncoding();
+ testLoadWithBadEncoding();
+ testStoreWithBadEncoding();
- // re-run test with security manager
+ // re-run sanity test with security manager
Policy orig = Policy.getPolicy();
Policy p = new SimplePolicy(new RuntimePermission("setSecurityManager"),
new PropertyPermission("line.separator", "read"));
Policy.setPolicy(p);
System.setSecurityManager(new SecurityManager());
try {
- test();
+ testLoadAndStore("UTF-8");
} finally {
// turn off security manager and restore policy
System.setSecurityManager(null);