From 4bf3fba8f90e901b50af7ed4e16f02d0bcdf5bcf Mon Sep 17 00:00:00 2001 From: Tobias Thierer Date: Tue, 6 Sep 2016 18:06:24 +0100 Subject: 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 --- .../harmony/tests/java/util/PropertiesTest.java | 54 ++++- 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); } /** @@ -1086,6 +1089,47 @@ public class PropertiesTest extends junit.framework.TestCase { inputStream.close(); } + /** + * 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 Properties class represents a persistent set of - * properties. The Properties 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. *

@@ -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. *

- * Because Properties inherits from Hashtable, the - * put and putAll methods can be applied to a - * Properties 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 - * Strings. The setProperty method should be used - * instead. If the store or save method is called - * on a "compromised" Properties object that contains a - * non-String key or value, the call will fail. Similarly, - * the call to the propertyNames or list method - * will fail if it is called on a "compromised" Properties - * object that contains a non-String 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. * *

* The {@link #load(java.io.Reader) load(Reader)} / @@ -78,8 +78,9 @@ import java.io.BufferedWriter; *

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">
@@ -146,15 +147,15 @@ class Properties extends Hashtable {
     }
 
     /**
-     * Calls the Hashtable method put. Provided for
+     * Calls the Hashtable method {@code put}. Provided for
      * parallelism with the getProperty method. Enforces use of
      * strings for property keys and values. The value returned is the
-     * result of the Hashtable call to put.
+     * result of the Hashtable call to {@code put}.
      *
      * @param key the key to be placed into this property list.
      * @param value the value corresponding to key.
      * @return     the previous value of the specified key in this property
-     *             list, or null 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 {
      * kinds of line, natural lines and logical lines.
      * A natural line is defined as a line of
      * characters that is terminated either by a set of line terminator
-     * characters (\n or \r or \r\n)
+     * 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
-     * \.  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 {
      * 

* A natural line that contains only white space characters is * considered blank and is ignored. A comment line has an ASCII - * '#' or '!' 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 - * (' ', '\u0020'), tab - * ('\t', '\u0009'), and form feed - * ('\f', '\u000C') to be white + * ({@code ' '}, {@code '\u005Cu0020'}), tab + * ({@code '\t'}, {@code '\u005Cu0009'}), and form feed + * ({@code '\f'}, {@code '\u005Cu000C'}) to be white * space. * *

@@ -215,32 +216,31 @@ class Properties extends Hashtable { *

* 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 '=', - * ':', 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,

* - * \:\=

+ * {@code \:\=}

* - * would be the two-character key ":=". Line - * terminator characters can be included using \r and - * \n 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 '=' or ':', 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 - * "". 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. * *

* As an example, each of the following three lines specifies the key - * "Truth" and the associated element value - * "Beauty": - *

+ * {@code "Truth"} and the associated element value + * {@code "Beauty"}: *

      * Truth = Beauty
      *  Truth:Beauty
@@ -248,29 +248,25 @@ class Properties extends Hashtable {
      * 
* As another example, the following three lines specify a single * property: - *

*

      * fruits                           apple, banana, pear, \
      *                                  cantaloupe, watermelon, \
      *                                  kiwi, mango
      * 
- * The key is "fruits" and the associated element is: - *

+ * The key is {@code "fruits"} and the associated element is: *

"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"
- * Note that a space appears before each \ so that a space - * will appear after each comma in the final result; the \, + * 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 not replaced by one or more other * characters. *

* As a third example, the line: - *

*

cheeses
      * 
- * specifies that the key is "cheeses" and the associated - * element is the empty string "".

+ * specifies that the key is {@code "cheeses"} and the associated + * element is the empty string {@code ""}. *

- * * * 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 { *

    *
  • Octal escapes are not recognized. * - *
  • The character sequence \b does not + *
  • The character sequence {@code \b} does not * represent a backspace character. * *
  • The method does not treat a backslash character, - * \, 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 "\z" 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 "\b" as equivalent to the single - * character 'b'. + * sequence {@code "\b"} as equivalent to the single + * character {@code 'b'}. * *
  • 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. * - *
  • Only a single 'u' character is allowed in a Uniocde escape + *
  • Only a single 'u' character is allowed in a Unicode escape * sequence. * *
@@ -366,7 +362,9 @@ class Properties extends Hashtable { 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 { } 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 { if (len == 0 || isCommentLine) { return -1; } + if (precedingBackslash) { + len--; + } return len; } } @@ -456,6 +458,7 @@ class Properties extends Hashtable { } } if (skipWhiteSpace) { + // Android-changed: use of Character.isWhitespace(c) b/25998006 if (Character.isWhitespace(c)) { continue; } @@ -506,6 +509,9 @@ class Properties extends Hashtable { :inStream.read(inByteBuf); inOff = 0; if (inLimit <= 0) { + if (precedingBackslash) { + len--; + } return len; } } @@ -689,20 +695,20 @@ class Properties extends Hashtable { } /** - * Calls the store(OutputStream out, String comments) 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 store(OutputStream out, - * String comments) method or the - * storeToXML(OutputStream os, String comment) 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 Properties object + * @exception ClassCastException if this {@code Properties} object * contains any keys or values that are not - * Strings. + * {@code Strings}. */ @Deprecated public void save(OutputStream out, String comments) { @@ -714,37 +720,37 @@ class Properties extends Hashtable { /** * Writes this property list (key and element pairs) in this - * Properties 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. *

- * Properties from the defaults table of this Properties + * Properties from the defaults table of this {@code Properties} * table (if any) are not written out by this method. *

- * If the comments argument is not null, then an ASCII # + * 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 comments 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 Writer - * and if the next character in comments is not character # or - * character ! then an ASCII # 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. *

* Next, a comment line is always written, consisting of an ASCII - * # character, the current date and time (as if produced - * by the toString method of Date for the - * current time), and a line separator as generated by the Writer. + * {@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}. *

- * Then every entry in this Properties 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 =, then the associated + * written, then an ASCII {@code =}, then the associated * element string. For the key, all space characters are - * written with a preceding \ 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 \ - * character. The key and element characters #, - * !, =, and : 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. *

* After the entries have been written, the output stream is flushed. @@ -755,9 +761,9 @@ class Properties extends Hashtable { * @param comments a description of the property list. * @exception IOException if writing this property list to the specified * output stream throws an IOException. - * @exception ClassCastException if this Properties object - * contains any keys or values that are not Strings. - * @exception NullPointerException if writer 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 { /** * Writes this property list (key and element pairs) in this - * Properties table to the output stream in a format suitable - * for loading into a Properties 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. *

- * Properties from the defaults table of this Properties + * Properties from the defaults table of this {@code Properties} * table (if any) are not written out by this method. *

* This method outputs the comments, properties keys and values in @@ -786,12 +792,12 @@ class Properties extends Hashtable { *

  • The stream is written using the ISO 8859-1 character encoding. * *
  • Characters not in Latin-1 in the comments are written as - * \uxxxx for their appropriate unicode + * {@code \u005Cu}xxxx for their appropriate unicode * hexadecimal value xxxx. * - *
  • Characters less than \u0020 and characters greater - * than \u007E in property keys or values are written - * as \uxxxx for the appropriate hexadecimal + *
  • Characters less than {@code \u005Cu0020} and characters greater + * than {@code \u005Cu007E} in property keys or values are written + * as {@code \u005Cu}xxxx for the appropriate hexadecimal * value xxxx. * *

    @@ -802,9 +808,9 @@ class Properties extends Hashtable { * @param comments a description of the property list. * @exception IOException if writing this property list to the specified * output stream throws an IOException. - * @exception ClassCastException if this Properties object - * contains any keys or values that are not Strings. - * @exception NullPointerException if out 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 { 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 { * Furthermore, the document must satisfy the properties DTD described * above. * + *

    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. + * *

    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 IOException. + * @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 in is null. + * @throws NullPointerException if {@code in} is null. * @see #storeToXML(OutputStream, String, String) + * @see Character + * Encoding in Entities * @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 { * props.storeToXML(os, comment, "UTF-8");. * * @param os the output stream on which to emit the XML document. - * @param comment a description of the property list, or null + * @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 IOException. - * @throws NullPointerException if os is null. - * @throws ClassCastException if this Properties object + * @throws NullPointerException if {@code os} is null. + * @throws ClassCastException if this {@code Properties} object * contains any keys or values that are not - * Strings. + * {@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 { * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> *

  • * - *

    If the specified comment is 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. - * @param comment a description of the property list, or null + * @param comment a description of the property list, or {@code null} * if no comment is desired. * @param encoding the name of a supported * @@ -921,27 +942,37 @@ class Properties extends Hashtable { * * @throws IOException if writing to the specified output stream * results in an IOException. - * @throws NullPointerException if os is null, - * or if encoding is null. - * @throws ClassCastException if this Properties 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 - * Strings. + * {@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(); - 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 - * null 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 { * @see #stringPropertyNames */ public Enumeration propertyNames() { - Hashtable h = new Hashtable(); + Hashtable h = new Hashtable<>(); enumerate(h); return h.keys(); } @@ -1026,10 +1057,10 @@ class Properties extends Hashtable { */ public void list(PrintStream out) { out.println("-- listing properties --"); - Hashtable h = new Hashtable(); + Hashtable h = new Hashtable<>(); enumerate(h); - for (Enumeration e = h.keys() ; e.hasMoreElements() ;) { - String key = (String)e.nextElement(); + for (Enumeration 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 { */ public void list(PrintWriter out) { out.println("-- listing properties --"); - Hashtable h = new Hashtable(); + Hashtable h = new Hashtable<>(); enumerate(h); - for (Enumeration e = h.keys() ; e.hasMoreElements() ;) { - String key = (String)e.nextElement(); + for (Enumeration 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 { * @throws ClassCastException if any of the property keys * is not of String type. */ - private synchronized void enumerate(Hashtable h) { + private synchronized void enumerate(Hashtable 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 { 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) { -- cgit v1.2.3