diff options
author | Tobias Thierer <tobiast@google.com> | 2016-09-06 18:06:24 +0100 |
---|---|---|
committer | Tobias Thierer <tobiast@google.com> | 2016-09-22 15:55:11 +0100 |
commit | 4bf3fba8f90e901b50af7ed4e16f02d0bcdf5bcf (patch) | |
tree | b4337016fa86aff67577d608bcdeafcd26cf1c73 | |
parent | e1bee3b4eb43e4401d88b5c7395258424569239e (diff) |
Update Properties to OpenJDK8u60
- This contains a deliberate behavior change in the case of
a single backslash (possibly followed by newline characters)
at the end of input. Such a trailing backslash is now skipped
whereas previously it was parsed as \u0000.
The new behavior makes more sense and there is nothing in
the documentation asserting either behavior. Further, the
new behavior matches upstream.
The tests that were asserting the old behavior were
added as harmony SVN revision 617124 with commit message
"Fix for HARMONY-5414 (java.util.Properties.load() decodes
invalid unicode sequences)". This references the harmony bug:
https://issues.apache.org/jira/browse/HARMONY-5414
While the test code attached to the bug does cover the
case of a lone \, it is not mentioned in the bug description.
The bug otherwise focuses on unicode sequences with numbers
of digits other than 4, e.g. \u123 which is asserted to yield
IllegalArgumentException.
This CL changes the test to assert the new behavior which is
that the backslash is ignored/trimmed.
This CL also adds more comprehensive test coverage for
properties read from a Reader and with trailing backslashes
at end of line followed by end of input, newline characters,
or additional lines.
- Android-changed: The implementation for loading/storing
properties from/to XML stil uses OpenJDK7u40's java.util.XMLUtils.
The upstream replacement XmlSupport adds considerable dependencies
and complexity that would have no apparent behavioral benefit on
Android.
Test: PropertiesTest
Test: Verified that testTrailingBackslash() fails if
the first fix is commented out.
Test: Verified that testTrailingBackslashAndNewline()
fails if the second fix is commented out.
Bug: 29935305
Change-Id: I93a4b879c10909d31585320af9b0d5c1fe7e46b8
-rw-r--r-- | harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PropertiesTest.java | 54 | ||||
-rw-r--r-- | ojluni/src/main/java/java/util/Properties.java | 265 |
2 files changed, 197 insertions, 122 deletions
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PropertiesTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PropertiesTest.java index 27cae4e365..038cc7bf9a 100644 --- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PropertiesTest.java +++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PropertiesTest.java @@ -20,15 +20,18 @@ package org.apache.harmony.tests.java.util; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.CharArrayReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintStream; import java.io.PrintWriter; +import java.io.Reader; import java.io.Writer; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.InvalidPropertiesFormatException; @@ -389,21 +392,21 @@ public class PropertiesTest extends junit.framework.TestCase { prop = new Properties(); Properties expected = new Properties(); - expected.put("a", "\u0000"); + expected.put("a", ""); prop.load(new ByteArrayInputStream("a=\\".getBytes())); - assertEquals("Failed to read trailing slash value", expected, prop); + assertEquals("Failed to trim trailing slash value", expected, prop); prop = new Properties(); expected = new Properties(); - expected.put("a", "\u1234\u0000"); + expected.put("a", "\u1234"); prop.load(new ByteArrayInputStream("a=\\u1234\\".getBytes())); - assertEquals("Failed to read trailing slash value #2", expected, prop); + assertEquals("Failed to trim trailing slash value #2", expected, prop); prop = new Properties(); expected = new Properties(); expected.put("a", "q"); prop.load(new ByteArrayInputStream("a=\\q".getBytes())); - assertEquals("Failed to read slash value #3", expected, prop); + assertEquals("Failed to skip slash value #3", expected, prop); } /** @@ -1087,6 +1090,47 @@ public class PropertiesTest extends junit.framework.TestCase { } /** + * Checks the example given in the documentation of a single property split over + * multiple lines separated by a backslash and newline character. + */ + public void testSingleProperty_multipleLinesJoinedByBackslash() throws Exception { + String propertyString = "fruits apple, banana, pear, \\\n" + + " cantaloupe, watermelon, \\\n" + + " kiwi, mango"; + checkSingleProperty("fruits", "apple, banana, pear, cantaloupe, watermelon, kiwi, mango", + propertyString); + } + + /** + * Checks that a trailing backslash at the end of the single line of input is ignored. + * This is similar to a check in {@link #test_loadLjava_io_Reader()} that uses an + * InputStream and {@link Properties#equals(Object)} . + */ + public void testSingleProperty_oneLineWithTrailingBackslash() throws Exception { + checkSingleProperty("key", "value", "key=value\\"); + } + + /** + * Checks that a trailing backslash at the end of the single line of input is ignored, + * even when that line has a newline. + */ + public void testSingleProperty_oneLineWithTrailingBackslash_newline() throws Exception { + checkSingleProperty("key", "value", "key=value\\\r"); + checkSingleProperty("key", "value", "key=value\\\n"); + checkSingleProperty("key", "value", "key=value\\\r\n"); + } + + private static void checkSingleProperty(String key, String value, String serialized) + throws IOException { + Properties properties = new Properties(); + try (Reader reader = new CharArrayReader(serialized.toCharArray())) { + properties.load(reader); + assertEquals(Collections.singleton(key), properties.keySet()); + assertEquals(value, properties.getProperty(key)); + } + } + + /** * Sets up the fixture, for example, open a network connection. This method * is called before a test is executed. */ diff --git a/ojluni/src/main/java/java/util/Properties.java b/ojluni/src/main/java/java/util/Properties.java index 7c3f0bba97..fe61f987c0 100644 --- a/ojluni/src/main/java/java/util/Properties.java +++ b/ojluni/src/main/java/java/util/Properties.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,8 +37,8 @@ import java.io.OutputStreamWriter; import java.io.BufferedWriter; /** - * The <code>Properties</code> class represents a persistent set of - * properties. The <code>Properties</code> can be saved to a stream + * The {@code Properties} class represents a persistent set of + * properties. The {@code Properties} can be saved to a stream * or loaded from a stream. Each key and its corresponding value in * the property list is a string. * <p> @@ -46,17 +46,17 @@ import java.io.BufferedWriter; * "defaults"; this second property list is searched if * the property key is not found in the original property list. * <p> - * Because <code>Properties</code> inherits from <code>Hashtable</code>, the - * <code>put</code> and <code>putAll</code> methods can be applied to a - * <code>Properties</code> object. Their use is strongly discouraged as they + * Because {@code Properties} inherits from {@code Hashtable}, the + * {@code put} and {@code putAll} methods can be applied to a + * {@code Properties} object. Their use is strongly discouraged as they * allow the caller to insert entries whose keys or values are not - * <code>Strings</code>. The <code>setProperty</code> method should be used - * instead. If the <code>store</code> or <code>save</code> method is called - * on a "compromised" <code>Properties</code> object that contains a - * non-<code>String</code> key or value, the call will fail. Similarly, - * the call to the <code>propertyNames</code> or <code>list</code> method - * will fail if it is called on a "compromised" <code>Properties</code> - * object that contains a non-<code>String</code> key. + * {@code Strings}. The {@code setProperty} method should be used + * instead. If the {@code store} or {@code save} method is called + * on a "compromised" {@code Properties} object that contains a + * non-{@code String} key or value, the call will fail. Similarly, + * the call to the {@code propertyNames} or {@code list} method + * will fail if it is called on a "compromised" {@code Properties} + * object that contains a non-{@code String} key. * * <p> * The {@link #load(java.io.Reader) load(Reader)} <tt>/</tt> @@ -78,8 +78,9 @@ import java.io.BufferedWriter; * <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"> @@ -146,15 +147,15 @@ class Properties extends Hashtable<Object,Object> { } /** - * Calls the <tt>Hashtable</tt> method <code>put</code>. Provided for + * Calls the <tt>Hashtable</tt> method {@code put}. Provided for * parallelism with the <tt>getProperty</tt> method. Enforces use of * strings for property keys and values. The value returned is the - * result of the <tt>Hashtable</tt> call to <code>put</code>. + * result of the <tt>Hashtable</tt> call to {@code put}. * * @param key the key to be placed into this property list. * @param value the value corresponding to <tt>key</tt>. * @return the previous value of the specified key in this property - * list, or <code>null</code> if it did not have one. + * list, or {@code null} if it did not have one. * @see #getProperty * @since 1.2 */ @@ -171,13 +172,13 @@ class Properties extends Hashtable<Object,Object> { * kinds of line, <i>natural lines</i> and <i>logical lines</i>. * A natural line is defined as a line of * characters that is terminated either by a set of line terminator - * characters (<code>\n</code> or <code>\r</code> or <code>\r\n</code>) + * characters ({@code \n} or {@code \r} or {@code \r\n}) * or by the end of the stream. A natural line may be either a blank line, * a comment line, or hold all or some of a key-element pair. A logical * line holds all the data of a key-element pair, which may be spread * out across several adjacent natural lines by escaping * the line terminator sequence with a backslash character - * <code>\</code>. Note that a comment line cannot be extended + * {@code \}. Note that a comment line cannot be extended * in this manner; every natural line that is a comment must have * its own comment indicator, as described below. Lines are read from * input until the end of the stream is reached. @@ -185,13 +186,13 @@ class Properties extends Hashtable<Object,Object> { * <p> * A natural line that contains only white space characters is * considered blank and is ignored. A comment line has an ASCII - * <code>'#'</code> or <code>'!'</code> as its first non-white + * {@code '#'} or {@code '!'} as its first non-white * space character; comment lines are also ignored and do not * encode key-element information. In addition to line * terminators, this format considers the characters space - * (<code>' '</code>, <code>'\u0020'</code>), tab - * (<code>'\t'</code>, <code>'\u0009'</code>), and form feed - * (<code>'\f'</code>, <code>'\u000C'</code>) to be white + * ({@code ' '}, {@code '\u005Cu0020'}), tab + * ({@code '\t'}, {@code '\u005Cu0009'}), and form feed + * ({@code '\f'}, {@code '\u005Cu000C'}) to be white * space. * * <p> @@ -215,32 +216,31 @@ class Properties extends Hashtable<Object,Object> { * <p> * The key contains all of the characters in the line starting * with the first non-white space character and up to, but not - * including, the first unescaped <code>'='</code>, - * <code>':'</code>, or white space character other than a line + * including, the first unescaped {@code '='}, + * {@code ':'}, or white space character other than a line * terminator. All of these key termination characters may be * included in the key by escaping them with a preceding backslash * character; for example,<p> * - * <code>\:\=</code><p> + * {@code \:\=}<p> * - * would be the two-character key <code>":="</code>. Line - * terminator characters can be included using <code>\r</code> and - * <code>\n</code> escape sequences. Any white space after the + * would be the two-character key {@code ":="}. Line + * terminator characters can be included using {@code \r} and + * {@code \n} escape sequences. Any white space after the * key is skipped; if the first non-white space character after - * the key is <code>'='</code> or <code>':'</code>, then it is + * the key is {@code '='} or {@code ':'}, then it is * ignored and any white space characters after it are also * skipped. All remaining characters on the line become part of * the associated element string; if there are no remaining * characters, the element is the empty string - * <code>""</code>. Once the raw character sequences + * {@code ""}. Once the raw character sequences * constituting the key and element are identified, escape * processing is performed as described above. * * <p> * As an example, each of the following three lines specifies the key - * <code>"Truth"</code> and the associated element value - * <code>"Beauty"</code>: - * <p> + * {@code "Truth"} and the associated element value + * {@code "Beauty"}: * <pre> * Truth = Beauty * Truth:Beauty @@ -248,29 +248,25 @@ class Properties extends Hashtable<Object,Object> { * </pre> * As another example, the following three lines specify a single * property: - * <p> * <pre> * fruits apple, banana, pear, \ * cantaloupe, watermelon, \ * kiwi, mango * </pre> - * The key is <code>"fruits"</code> and the associated element is: - * <p> + * The key is {@code "fruits"} and the associated element is: * <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre> - * Note that a space appears before each <code>\</code> so that a space - * will appear after each comma in the final result; the <code>\</code>, + * Note that a space appears before each {@code \} so that a space + * will appear after each comma in the final result; the {@code \}, * line terminator, and leading white space on the continuation line are * merely discarded and are <i>not</i> replaced by one or more other * characters. * <p> * As a third example, the line: - * <p> * <pre>cheeses * </pre> - * specifies that the key is <code>"cheeses"</code> and the associated - * element is the empty string <code>""</code>.<p> + * specifies that the key is {@code "cheeses"} and the associated + * element is the empty string {@code ""}. * <p> - * * <a name="unicodeescapes"></a> * Characters in keys and elements can be represented in escape * sequences similar to those used for character and string literals @@ -283,24 +279,24 @@ class Properties extends Hashtable<Object,Object> { * <ul> * <li> Octal escapes are not recognized. * - * <li> The character sequence <code>\b</code> does <i>not</i> + * <li> The character sequence {@code \b} does <i>not</i> * represent a backspace character. * * <li> The method does not treat a backslash character, - * <code>\</code>, before a non-valid escape character as an + * {@code \}, before a non-valid escape character as an * error; the backslash is silently dropped. For example, in a - * Java string the sequence <code>"\z"</code> would cause a + * Java string the sequence {@code "\z"} would cause a * compile time error. In contrast, this method silently drops * the backslash. Therefore, this method treats the two character - * sequence <code>"\b"</code> as equivalent to the single - * character <code>'b'</code>. + * sequence {@code "\b"} as equivalent to the single + * character {@code 'b'}. * * <li> Escapes are not necessary for single and double quotes; * however, by the rule above, single and double quote characters * preceded by a backslash still yield single and double quote * characters, respectively. * - * <li> Only a single 'u' character is allowed in a Uniocde escape + * <li> Only a single 'u' character is allowed in a Unicode escape * sequence. * * </ul> @@ -366,7 +362,9 @@ class Properties extends Hashtable<Object,Object> { valueStart = keyLen + 1; hasSep = true; break; - } else if (Character.isWhitespace(c) && !precedingBackslash) { + } + // Android-changed: use of Character.isWhitespace(c) b/25998006 + else if (Character.isWhitespace(c) && !precedingBackslash) { valueStart = keyLen + 1; break; } @@ -379,6 +377,7 @@ class Properties extends Hashtable<Object,Object> { } while (valueStart < limit) { c = lr.lineBuf[valueStart]; + // Android-changed: use of Character.isWhitespace(c) b/25998006 if (!Character.isWhitespace(c)) { if (!hasSep && (c == '=' || c == ':')) { hasSep = true; @@ -439,6 +438,9 @@ class Properties extends Hashtable<Object,Object> { if (len == 0 || isCommentLine) { return -1; } + if (precedingBackslash) { + len--; + } return len; } } @@ -456,6 +458,7 @@ class Properties extends Hashtable<Object,Object> { } } if (skipWhiteSpace) { + // Android-changed: use of Character.isWhitespace(c) b/25998006 if (Character.isWhitespace(c)) { continue; } @@ -506,6 +509,9 @@ class Properties extends Hashtable<Object,Object> { :inStream.read(inByteBuf); inOff = 0; if (inLimit <= 0) { + if (precedingBackslash) { + len--; + } return len; } } @@ -689,20 +695,20 @@ class Properties extends Hashtable<Object,Object> { } /** - * Calls the <code>store(OutputStream out, String comments)</code> method + * Calls the {@code store(OutputStream out, String comments)} method * and suppresses IOExceptions that were thrown. * * @deprecated This method does not throw an IOException if an I/O error * occurs while saving the property list. The preferred way to save a - * properties list is via the <code>store(OutputStream out, - * String comments)</code> method or the - * <code>storeToXML(OutputStream os, String comment)</code> method. + * properties list is via the {@code store(OutputStream out, + * String comments)} method or the + * {@code storeToXML(OutputStream os, String comment)} method. * * @param out an output stream. * @param comments a description of the property list. - * @exception ClassCastException if this <code>Properties</code> object + * @exception ClassCastException if this {@code Properties} object * contains any keys or values that are not - * <code>Strings</code>. + * {@code Strings}. */ @Deprecated public void save(OutputStream out, String comments) { @@ -714,37 +720,37 @@ class Properties extends Hashtable<Object,Object> { /** * Writes this property list (key and element pairs) in this - * <code>Properties</code> table to the output character stream in a + * {@code Properties} table to the output character stream in a * format suitable for using the {@link #load(java.io.Reader) load(Reader)} * method. * <p> - * Properties from the defaults table of this <code>Properties</code> + * Properties from the defaults table of this {@code Properties} * table (if any) are <i>not</i> written out by this method. * <p> - * If the comments argument is not null, then an ASCII <code>#</code> + * If the comments argument is not null, then an ASCII {@code #} * character, the comments string, and a line separator are first written - * to the output stream. Thus, the <code>comments</code> can serve as an + * to the output stream. Thus, the {@code comments} can serve as an * identifying comment. Any one of a line feed ('\n'), a carriage * return ('\r'), or a carriage return followed immediately by a line feed - * in comments is replaced by a line separator generated by the <code>Writer</code> - * and if the next character in comments is not character <code>#</code> or - * character <code>!</code> then an ASCII <code>#</code> is written out + * in comments is replaced by a line separator generated by the {@code Writer} + * and if the next character in comments is not character {@code #} or + * character {@code !} then an ASCII {@code #} is written out * after that line separator. * <p> * Next, a comment line is always written, consisting of an ASCII - * <code>#</code> character, the current date and time (as if produced - * by the <code>toString</code> method of <code>Date</code> for the - * current time), and a line separator as generated by the <code>Writer</code>. + * {@code #} character, the current date and time (as if produced + * by the {@code toString} method of {@code Date} for the + * current time), and a line separator as generated by the {@code Writer}. * <p> - * Then every entry in this <code>Properties</code> table is + * Then every entry in this {@code Properties} table is * written out, one per line. For each entry the key string is - * written, then an ASCII <code>=</code>, then the associated + * written, then an ASCII {@code =}, then the associated * element string. For the key, all space characters are - * written with a preceding <code>\</code> character. For the + * written with a preceding {@code \} character. For the * element, leading space characters, but not embedded or trailing - * space characters, are written with a preceding <code>\</code> - * character. The key and element characters <code>#</code>, - * <code>!</code>, <code>=</code>, and <code>:</code> are written + * space characters, are written with a preceding {@code \} + * character. The key and element characters {@code #}, + * {@code !}, {@code =}, and {@code :} are written * with a preceding backslash to ensure that they are properly loaded. * <p> * After the entries have been written, the output stream is flushed. @@ -755,9 +761,9 @@ class Properties extends Hashtable<Object,Object> { * @param comments a description of the property list. * @exception IOException if writing this property list to the specified * output stream throws an <tt>IOException</tt>. - * @exception ClassCastException if this <code>Properties</code> object - * contains any keys or values that are not <code>Strings</code>. - * @exception NullPointerException if <code>writer</code> is null. + * @exception ClassCastException if this {@code Properties} object + * contains any keys or values that are not {@code Strings}. + * @exception NullPointerException if {@code writer} is null. * @since 1.6 */ public void store(Writer writer, String comments) @@ -771,11 +777,11 @@ class Properties extends Hashtable<Object,Object> { /** * Writes this property list (key and element pairs) in this - * <code>Properties</code> table to the output stream in a format suitable - * for loading into a <code>Properties</code> table using the + * {@code Properties} table to the output stream in a format suitable + * for loading into a {@code Properties} table using the * {@link #load(InputStream) load(InputStream)} method. * <p> - * Properties from the defaults table of this <code>Properties</code> + * Properties from the defaults table of this {@code Properties} * table (if any) are <i>not</i> written out by this method. * <p> * This method outputs the comments, properties keys and values in @@ -786,12 +792,12 @@ class Properties extends Hashtable<Object,Object> { * <li>The stream is written using the ISO 8859-1 character encoding. * * <li>Characters not in Latin-1 in the comments are written as - * <code>\u</code><i>xxxx</i> for their appropriate unicode + * {@code \u005Cu}<i>xxxx</i> for their appropriate unicode * hexadecimal value <i>xxxx</i>. * - * <li>Characters less than <code>\u0020</code> and characters greater - * than <code>\u007E</code> in property keys or values are written - * as <code>\u</code><i>xxxx</i> for the appropriate hexadecimal + * <li>Characters less than {@code \u005Cu0020} and characters greater + * than {@code \u005Cu007E} in property keys or values are written + * as {@code \u005Cu}<i>xxxx</i> for the appropriate hexadecimal * value <i>xxxx</i>. * </ul> * <p> @@ -802,9 +808,9 @@ class Properties extends Hashtable<Object,Object> { * @param comments a description of the property list. * @exception IOException if writing this property list to the specified * output stream throws an <tt>IOException</tt>. - * @exception ClassCastException if this <code>Properties</code> object - * contains any keys or values that are not <code>Strings</code>. - * @exception NullPointerException if <code>out</code> is null. + * @exception ClassCastException if this {@code Properties} object + * contains any keys or values that are not {@code Strings}. + * @exception NullPointerException if {@code out} is null. * @since 1.2 */ public void store(OutputStream out, String comments) @@ -824,7 +830,7 @@ class Properties extends Hashtable<Object,Object> { bw.write("#" + new Date().toString()); bw.newLine(); synchronized (this) { - for (Enumeration e = keys(); e.hasMoreElements();) { + for (Enumeration<?> e = keys(); e.hasMoreElements();) { String key = (String)e.nextElement(); String val = (String)get(key); key = saveConvert(key, true, escUnicode); @@ -850,23 +856,36 @@ class Properties extends Hashtable<Object,Object> { * 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</code> is null. + * @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(); - XMLUtils.load(this, in); + // Android-changed: Keep OpenJDK7u40's XmlUtils. + // XmlSupport's system property based XmlPropertiesProvider + // selection does not make sense on Android and has too many + // dependencies on classes that are not available on Android. + // + // XmlSupport.load(this, Objects.requireNonNull(in)); + XMLUtils.load(this, Objects.requireNonNull(in)); in.close(); } @@ -879,22 +898,20 @@ class Properties extends Hashtable<Object,Object> { * <tt>props.storeToXML(os, comment, "UTF-8");</tt>. * * @param os the output stream on which to emit the XML document. - * @param comment a description of the property list, or <code>null</code> + * @param comment a description of the property list, or {@code null} * if no comment is desired. * @throws IOException if writing to the specified output stream * results in an <tt>IOException</tt>. - * @throws NullPointerException if <code>os</code> is null. - * @throws ClassCastException if this <code>Properties</code> object + * @throws NullPointerException if {@code os} is null. + * @throws ClassCastException if this {@code Properties} object * contains any keys or values that are not - * <code>Strings</code>. + * {@code Strings}. * @see #loadFromXML(InputStream) * @since 1.5 */ public void storeToXML(OutputStream os, String comment) throws IOException { - if (os == null) - throw new NullPointerException(); storeToXML(os, comment, "UTF-8"); } @@ -907,13 +924,17 @@ class Properties extends Hashtable<Object,Object> { * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> * </pre> * - *<p>If the specified comment is <code>null</code> 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. - * @param comment a description of the property list, or <code>null</code> + * @param comment a description of the property list, or {@code null} * if no comment is desired. * @param encoding the name of a supported * <a href="../lang/package-summary.html#charenc"> @@ -921,27 +942,37 @@ class Properties extends Hashtable<Object,Object> { * * @throws IOException if writing to the specified output stream * results in an <tt>IOException</tt>. - * @throws NullPointerException if <code>os</code> is <code>null</code>, - * or if <code>encoding</code> is <code>null</code>. - * @throws ClassCastException if this <code>Properties</code> object + * @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</code>. + * {@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(); - XMLUtils.save(this, os, comment, encoding); + // Android-changed: Keep OpenJDK7u40's XmlUtils. + // XmlSupport's system property based XmlPropertiesProvider + // selection does not make sense on Android and has too many + // dependencies on classes that are not available on Android. + // + // XmlSupport.save(this, Objects.requireNonNull(os), comment, + // Objects.requireNonNull(encoding)); + XMLUtils.save(this, Objects.requireNonNull(os), comment, + Objects.requireNonNull(encoding)); } /** * Searches for the property with the specified key in this property list. * If the key is not found in this property list, the default property list, * and its defaults, recursively, are then checked. The method returns - * <code>null</code> if the property is not found. + * {@code null} if the property is not found. * * @param key the property key. * @return the value in this property list with the specified key value. @@ -987,7 +1018,7 @@ class Properties extends Hashtable<Object,Object> { * @see #stringPropertyNames */ public Enumeration<?> propertyNames() { - Hashtable h = new Hashtable(); + Hashtable<String,Object> h = new Hashtable<>(); enumerate(h); return h.keys(); } @@ -1026,10 +1057,10 @@ class Properties extends Hashtable<Object,Object> { */ public void list(PrintStream out) { out.println("-- listing properties --"); - Hashtable h = new Hashtable(); + Hashtable<String,Object> h = new Hashtable<>(); enumerate(h); - for (Enumeration e = h.keys() ; e.hasMoreElements() ;) { - String key = (String)e.nextElement(); + for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) { + String key = e.nextElement(); String val = (String)h.get(key); if (val.length() > 40) { val = val.substring(0, 37) + "..."; @@ -1054,10 +1085,10 @@ class Properties extends Hashtable<Object,Object> { */ public void list(PrintWriter out) { out.println("-- listing properties --"); - Hashtable h = new Hashtable(); + Hashtable<String,Object> h = new Hashtable<>(); enumerate(h); - for (Enumeration e = h.keys() ; e.hasMoreElements() ;) { - String key = (String)e.nextElement(); + for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) { + String key = e.nextElement(); String val = (String)h.get(key); if (val.length() > 40) { val = val.substring(0, 37) + "..."; @@ -1072,11 +1103,11 @@ class Properties extends Hashtable<Object,Object> { * @throws ClassCastException if any of the property keys * is not of String type. */ - private synchronized void enumerate(Hashtable h) { + private synchronized void enumerate(Hashtable<String,Object> h) { if (defaults != null) { defaults.enumerate(h); } - for (Enumeration e = keys() ; e.hasMoreElements() ;) { + for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) { String key = (String)e.nextElement(); h.put(key, get(key)); } @@ -1091,7 +1122,7 @@ class Properties extends Hashtable<Object,Object> { if (defaults != null) { defaults.enumerateStringProperties(h); } - for (Enumeration e = keys() ; e.hasMoreElements() ;) { + for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) { Object k = e.nextElement(); Object v = get(k); if (k instanceof String && v instanceof String) { |