提交 b1e83e1a 编写于 作者: A alanb

8000685: (props) Properties.storeToXML/loadFromXML should only require UTF-8...

8000685: (props) Properties.storeToXML/loadFromXML should only require UTF-8 and UTF-16 to be supported
Reviewed-by: mchung, chegar
上级 67fec827
...@@ -81,8 +81,9 @@ import sun.util.spi.XmlPropertiesProvider; ...@@ -81,8 +81,9 @@ import sun.util.spi.XmlPropertiesProvider;
* <p> The {@link #loadFromXML(InputStream)} and {@link * <p> The {@link #loadFromXML(InputStream)} and {@link
* #storeToXML(OutputStream, String, String)} methods load and store properties * #storeToXML(OutputStream, String, String)} methods load and store properties
* in a simple XML format. By default the UTF-8 character encoding is used, * 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 * however a specific encoding may be specified if required. Implementations
* document has the following DOCTYPE declaration: * are required to support UTF-8 and UTF-16 and may support other encodings.
* An XML properties document has the following DOCTYPE declaration:
* *
* <pre> * <pre>
* &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt; * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
...@@ -853,23 +854,30 @@ class Properties extends Hashtable<Object,Object> { ...@@ -853,23 +854,30 @@ class Properties extends Hashtable<Object,Object> {
* Furthermore, the document must satisfy the properties DTD described * Furthermore, the document must satisfy the properties DTD described
* above. * 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. * <p>The specified stream is closed after this method returns.
* *
* @param in the input stream from which to read the XML document. * @param in the input stream from which to read the XML document.
* @throws IOException if reading from the specified input stream * @throws IOException if reading from the specified input stream
* results in an <tt>IOException</tt>. * 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 * @throws InvalidPropertiesFormatException Data on input stream does not
* constitute a valid XML document with the mandated document type. * constitute a valid XML document with the mandated document type.
* @throws NullPointerException if {@code in} is null. * @throws NullPointerException if {@code in} is null.
* @see #storeToXML(OutputStream, String, String) * @see #storeToXML(OutputStream, String, String)
* @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
* Encoding in Entities</a>
* @since 1.5 * @since 1.5
*/ */
public synchronized void loadFromXML(InputStream in) public synchronized void loadFromXML(InputStream in)
throws IOException, InvalidPropertiesFormatException throws IOException, InvalidPropertiesFormatException
{ {
if (in == null) XmlSupport.load(this, Objects.requireNonNull(in));
throw new NullPointerException();
XmlSupport.load(this, in);
in.close(); in.close();
} }
...@@ -896,8 +904,6 @@ class Properties extends Hashtable<Object,Object> { ...@@ -896,8 +904,6 @@ class Properties extends Hashtable<Object,Object> {
public void storeToXML(OutputStream os, String comment) public void storeToXML(OutputStream os, String comment)
throws IOException throws IOException
{ {
if (os == null)
throw new NullPointerException();
storeToXML(os, comment, "UTF-8"); storeToXML(os, comment, "UTF-8");
} }
...@@ -910,9 +916,13 @@ class Properties extends Hashtable<Object,Object> { ...@@ -910,9 +916,13 @@ class Properties extends Hashtable<Object,Object> {
* &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt; * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
* </pre> * </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. * 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. * <p>The specified stream remains open after this method returns.
* *
* @param os the output stream on which to emit the XML document. * @param os the output stream on which to emit the XML document.
...@@ -924,20 +934,23 @@ class Properties extends Hashtable<Object,Object> { ...@@ -924,20 +934,23 @@ class Properties extends Hashtable<Object,Object> {
* *
* @throws IOException if writing to the specified output stream * @throws IOException if writing to the specified output stream
* results in an <tt>IOException</tt>. * 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}, * @throws NullPointerException if {@code os} is {@code null},
* or if {@code encoding} is {@code null}. * or if {@code encoding} is {@code null}.
* @throws ClassCastException if this {@code Properties} object * @throws ClassCastException if this {@code Properties} object
* contains any keys or values that are not * contains any keys or values that are not
* {@code Strings}. * {@code Strings}.
* @see #loadFromXML(InputStream) * @see #loadFromXML(InputStream)
* @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
* Encoding in Entities</a>
* @since 1.5 * @since 1.5
*/ */
public void storeToXML(OutputStream os, String comment, String encoding) public void storeToXML(OutputStream os, String comment, String encoding)
throws IOException throws IOException
{ {
if (os == null) XmlSupport.save(this, Objects.requireNonNull(os), comment,
throw new NullPointerException(); Objects.requireNonNull(encoding));
XmlSupport.save(this, os, comment, encoding);
} }
/** /**
......
...@@ -55,6 +55,9 @@ public abstract class XmlPropertiesProvider { ...@@ -55,6 +55,9 @@ public abstract class XmlPropertiesProvider {
* @param props the properties table to populate * @param props the properties table to populate
* @param in the input stream from which to read the XML document * @param in the input stream from which to read the XML document
* @throws IOException if reading from the specified input stream fails * @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 * @throws InvalidPropertiesFormatException Data on input stream does not
* constitute a valid XML document with the mandated document type. * constitute a valid XML document with the mandated document type.
* *
...@@ -73,6 +76,8 @@ public abstract class XmlPropertiesProvider { ...@@ -73,6 +76,8 @@ public abstract class XmlPropertiesProvider {
* @param encoding the name of a supported character encoding * @param encoding the name of a supported character encoding
* *
* @throws IOException if writing to the specified output stream fails * @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 NullPointerException if {@code out} is null.
* @throws ClassCastException if this {@code Properties} object * @throws ClassCastException if this {@code Properties} object
* contains any keys or values that are not * contains any keys or values that are not
......
...@@ -27,6 +27,7 @@ package sun.util.xml; ...@@ -27,6 +27,7 @@ package sun.util.xml;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import java.nio.charset.*;
import org.xml.sax.*; import org.xml.sax.*;
import org.w3c.dom.*; import org.w3c.dom.*;
import javax.xml.parsers.*; import javax.xml.parsers.*;
...@@ -127,6 +128,13 @@ public class PlatformXmlPropertiesProvider extends XmlPropertiesProvider { ...@@ -127,6 +128,13 @@ public class PlatformXmlPropertiesProvider extends XmlPropertiesProvider {
String encoding) String encoding)
throws IOException 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(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = null; DocumentBuilder db = null;
try { try {
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
/* /*
* @test * @test
* @bug 8000354 * @bug 8000354 8000685
* @summary Basic test of storeToXML and loadToXML * @summary Basic test of storeToXML and loadToXML
*/ */
...@@ -66,13 +66,13 @@ public class LoadAndStoreXML { ...@@ -66,13 +66,13 @@ public class LoadAndStoreXML {
* Sanity test that properties saved with Properties#storeToXML can be * Sanity test that properties saved with Properties#storeToXML can be
* read with Properties#loadFromXML. * read with Properties#loadFromXML.
*/ */
static void test() throws IOException { static void testLoadAndStore(String encoding) throws IOException {
Properties props = new Properties(); Properties props = new Properties();
props.put("k1", "foo"); props.put("k1", "foo");
props.put("k2", "bar"); props.put("k2", "bar");
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
props.storeToXML(out, "no comment"); props.storeToXML(out, null, encoding);
Properties p = new Properties(); Properties p = new Properties();
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
...@@ -85,19 +85,74 @@ public class LoadAndStoreXML { ...@@ -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 = "<?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 { public static void main(String[] args) throws IOException {
// run test without security manager testLoadAndStore("UTF-8");
test(); testLoadAndStore("UTF-16");
testLoadWithoutEncoding();
testLoadWithBadEncoding();
testStoreWithBadEncoding();
// re-run test with security manager // re-run sanity test with security manager
Policy orig = Policy.getPolicy(); Policy orig = Policy.getPolicy();
Policy p = new SimplePolicy(new RuntimePermission("setSecurityManager"), Policy p = new SimplePolicy(new RuntimePermission("setSecurityManager"),
new PropertyPermission("line.separator", "read")); new PropertyPermission("line.separator", "read"));
Policy.setPolicy(p); Policy.setPolicy(p);
System.setSecurityManager(new SecurityManager()); System.setSecurityManager(new SecurityManager());
try { try {
test(); testLoadAndStore("UTF-8");
} finally { } finally {
// turn off security manager and restore policy // turn off security manager and restore policy
System.setSecurityManager(null); System.setSecurityManager(null);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册