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:
*
*
* <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
@@ -853,23 +854,30 @@ class Properties extends Hashtable
*
- *
If the specified comment is {@code null} then no comment
+ *
If the specified comment is {@code null} then no comment
* will be stored in the document.
*
+ *
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.
+ *
*
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 @@ class Properties extends Hashtable {
*
* @throws IOException if writing to the specified output stream
* results in an IOException.
+ * @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 Character
+ * Encoding in Entities
* @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));
}
/**
diff --git a/src/share/classes/sun/util/spi/XmlPropertiesProvider.java b/src/share/classes/sun/util/spi/XmlPropertiesProvider.java
index 42194daba294edc824ca8b8c2e6783909bb67a1b..3e4acddecfa4dd5fbfb06a0adc14a2e17738b658 100644
--- a/src/share/classes/sun/util/spi/XmlPropertiesProvider.java
+++ b/src/share/classes/sun/util/spi/XmlPropertiesProvider.java
@@ -55,6 +55,9 @@ public abstract class XmlPropertiesProvider {
* @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 @@ public abstract class XmlPropertiesProvider {
* @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
diff --git a/src/share/classes/sun/util/xml/PlatformXmlPropertiesProvider.java b/src/share/classes/sun/util/xml/PlatformXmlPropertiesProvider.java
index f4e4010b28274d0b2b90d0c3bd03e27a4fb1f1c7..0878c3de9949980b30ea405727a453d6b113a9ad 100644
--- a/src/share/classes/sun/util/xml/PlatformXmlPropertiesProvider.java
+++ b/src/share/classes/sun/util/xml/PlatformXmlPropertiesProvider.java
@@ -27,6 +27,7 @@ package sun.util.xml;
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 @@ public class PlatformXmlPropertiesProvider extends XmlPropertiesProvider {
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 {
diff --git a/test/java/util/Properties/LoadAndStoreXML.java b/test/java/util/Properties/LoadAndStoreXML.java
index 8fc5e73ab44dd3ed2e3ffb28e736c9ae051e49d4..fd1d81f47e6be0cc3a946ebdc15b985149851972 100644
--- a/test/java/util/Properties/LoadAndStoreXML.java
+++ b/test/java/util/Properties/LoadAndStoreXML.java
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8000354
+ * @bug 8000354 8000685
* @summary Basic test of storeToXML and loadToXML
*/
@@ -66,13 +66,13 @@ public class LoadAndStoreXML {
* 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 @@ public class LoadAndStoreXML {
}
}
+ /**
+ * 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 = "" +
+ "" +
+ "" +
+ "bar" +
+ "";
+ 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 = "" +
+ "" +
+ "" +
+ "bar" +
+ "";
+ 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);