8231640: (prop) Canonical property storage

Reviewed-by: rriggs, smarks, dfuchs, ihse
This commit is contained in:
Jaikiran Pai 2021-09-28 05:17:31 +00:00
parent ddc262746a
commit af50772d39
4 changed files with 837 additions and 15 deletions

View file

@ -46,6 +46,7 @@ import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import jdk.internal.util.StaticProperty;
import sun.nio.cs.ISO_8859_1;
import sun.nio.cs.UTF_8;
@ -807,17 +808,25 @@ public class Properties extends Hashtable<Object,Object> {
* 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} 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}
* 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.
* identifying comment. Any one of a line feed ({@code \n}), a carriage
* return ({@code \r}), or a carriage return followed immediately by a line feed
* ({@code \r\n}) in comments is replaced by a
* {@link System#lineSeparator() line separator} 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 #} 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}.
* If the {@systemProperty java.properties.date} is set on the command line
* and is non-empty (as determined by {@link String#isEmpty() String.isEmpty}),
* a comment line is written as follows.
* First, a {@code #} character is written, followed by the contents
* of the property, followed by a line separator. Any line terminator characters
* in the value of the system property are treated the same way as noted above
* for the comments argument.
* If the system property is not set or is empty, a comment line is written
* as follows.
* First, a {@code #} character is written, followed by the current date and time
* formatted as if by the {@link Date#toString() Date.toString} method,
* followed by a line separator.
* <p>
* Then every entry in this {@code Properties} table is
* written out, one per line. For each entry the key string is
@ -833,6 +842,10 @@ public class Properties extends Hashtable<Object,Object> {
* After the entries have been written, the output stream is flushed.
* The output stream remains open after this method returns.
*
* @implSpec The keys and elements are written in the natural sort order
* of the keys in the {@code entrySet()} unless {@code entrySet()} is
* overridden by a subclass to return a different value than {@code super.entrySet()}.
*
* @param writer an output character stream writer.
* @param comments a description of the property list.
* @throws IOException if writing this property list to the specified
@ -903,12 +916,25 @@ public class Properties extends Hashtable<Object,Object> {
if (comments != null) {
writeComments(bw, comments);
}
bw.write("#" + new Date().toString());
bw.newLine();
writeDateComment(bw);
synchronized (this) {
for (Map.Entry<Object, Object> e : entrySet()) {
String key = (String)e.getKey();
String val = (String)e.getValue();
@SuppressWarnings("unchecked")
Collection<Map.Entry<String, String>> entries = (Set<Map.Entry<String, String>>) (Set) entrySet();
// entrySet() can be overridden by subclasses. Here we check to see if
// the returned instance type is the one returned by the Properties.entrySet()
// implementation. If yes, then we sort those entries in the natural order
// of their key. Else, we consider that the subclassed implementation may
// potentially have returned a differently ordered entries and so we just
// use the iteration order of the returned instance.
if (entries instanceof Collections.SynchronizedSet<?> ss
&& ss.c instanceof EntrySet) {
entries = new ArrayList<>(entries);
((List<Map.Entry<String, String>>) entries).sort(Map.Entry.comparingByKey());
}
for (Map.Entry<String, String> e : entries) {
String key = e.getKey();
String val = e.getValue();
key = saveConvert(key, true, escUnicode);
/* No need to escape embedded and trailing spaces for value, hence
* pass false to flag.
@ -921,6 +947,19 @@ public class Properties extends Hashtable<Object,Object> {
bw.flush();
}
private static void writeDateComment(BufferedWriter bw) throws IOException {
// value of java.properties.date system property isn't sensitive
// and so doesn't need any security manager checks to make the value accessible
// to the callers
String sysPropVal = StaticProperty.javaPropertiesDate();
if (sysPropVal != null && !sysPropVal.isEmpty()) {
writeComments(bw, sysPropVal);
} else {
bw.write("#" + new Date());
bw.newLine();
}
}
/**
* Loads all of the properties represented by the XML document on the
* specified input stream into this properties table.