Summary
java.util.Properties::store(Writer writer, String comments)
and
java.util.Properties::store(OutputStream out, String comments)
must write the properties in a deterministic order and must allow
for the default added date comment to be user controlled.
Problem
Applications, such as build tools, use the Properties::store
methods
to write out the application specific properties. In certain environments,
like for generating reproducible builds (https://reproducible-builds.org/)
these build tools expect the stored output to be exactly the same when
the same set of property keys and values are provided as inputs to
the store
methods.
The implementation of the Properties::store
methods, currently writes
out the properties in the iteration order of an internal hash based
map. This order is not deterministic, and it may vary from run to run.
Additionally, the Properties::store
method implementations always
write out a default comment which is the formatted string representation
of the current date and time. Naturally, this also varies from run to run.
Because of these two implementation semantics, applications cannot rely
on Properties::store
methods to produce reproducible output.
Solution
Change the implementation of Properties::store
methods to write out
the properties in the natural order of the property keys and also
introduce a system property that can be set to control the default
comment that gets written out by these methods.
Multiple different options were discussed in the PR as well as a proposal thread before coming to this solution. The links to those threads are as follows:
https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-August/080758.html
https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-September/081113.html
https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-September/081115.html
Specification
diff --git a/src/java.base/share/classes/java/util/Properties.java b/src/java.base/share/classes/java/util/Properties.java
index 333b75f45b00..2955f65c20e8 100644
--- a/src/java.base/share/classes/java/util/Properties.java
+++ b/src/java.base/share/classes/java/util/Properties.java
@@ -46,6 +46,7 @@
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 void save(OutputStream out, String comments) {
* 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 void save(OutputStream out, String comments) {
* 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
- csr of
-
JDK-8231640 (prop) Canonical property storage
-
- Resolved
-