Discussion: Interpretation of system property flags

Roger Riggs roger.riggs at oracle.com
Wed Dec 4 15:03:13 UTC 2024


Hi Eirik,

Yes, its a long standing and inconsistent area of deferred maintenance.
Most of the individual cases are not used enough to warrant making the 
(in many cases) incompatible change and breaking some 
application/library somewhere.

Interesting, you did not mention Boolean.getBoolean(String name) whose 
behavior isn't the most useful.
In particular, it returns true only if the value is "true" (case 
insensitive).

 From a usability point of view, it should be true if the Property is 
present and either "true" or empty.
It should be possible to enable using just '-Dname'.


A related problem is the naming and semantics of the property, there a 
number of places where to enable a function you have to set a 
"disableXXX" property to false.  That makes comprehension harder.

Common utility methods might be a small code cleanup but aligning all 
uses might have a very small payback for the possible incompatibilties.

Regards, Roger


On 12/4/24 9:47 AM, Eirik Bjørsnøs wrote:
> Hi,
>
> The OpenJDK includes many boolean flags in the form of system 
> properties. These toggle different behavior such as debug logging, 
> verification, caching, compatibility and conditional features.
>
> A common interpretation is to evaluate a property as true if it is set 
> and either blank or equal to "true" (ignoring case). This is a useful 
> interpretation when a feature should usually be disabled, but you want 
> users to enable it by setting a flag:
>
> Let's call this the "ifEnabled" interpretation:
>
> -Dflag=true  => true
> -Dflag=TRUE  => true
> -Dflag       => true
> -Dflag=false => false
> -Dflag=FALSE => false
> -Dflag=abc   => false
> -Dother      => false
>
> MacOSXFileSystem:
>
>     final String name = PROPERTY_NORMALIZE_FILE_PATHS;
>     String value = System.getProperty(name);
>     NORMALIZE_FILE_PATHS = (value != null)
>         && ("".equals(value) || Boolean.parseBoolean(value));
>
>
> The same logic is implemented in a number of different ways, see for 
> example:
>
> IPAddressUtil:
>
>     var value = System.getProperty(DELAY_URL_PARSING_SP, "false");
>     DELAY_URL_PARSING_SP_VALUE = value.isEmpty()
>             || Boolean.parseBoolean(value);
>
>
> It can also be used to conditionally disable a feature:
>
> ZipFile:
>
>     boolean result;
>     String value =
>     System.getProperty("jdk.util.zip.disableZip64ExtraFieldValidation");
>     if (value == null) {
>         result = false;
>     } else {
>         result = value.isEmpty() || value.equalsIgnoreCase("true");
>     }
>     return result;
>
>
> However, sometimes the logic is inverted (what we really want below is 
> USE_FAST_PATH = !flagSet):
>
> SystemModuleFinders:
>
>     String value =
>     System.getProperty("jdk.system.module.finder.disableFastPath");
>     if (value == null) {
>         USE_FAST_PATH = true;
>     } else {
>         USE_FAST_PATH = !value.isEmpty() && !Boolean.parseBoolean(value);
>     } 
>
>
> Another variant of interpretation flips the meaning of null and empty 
> values. Under this interpretation, a flag evaluates to true when the 
> flag is not set (value is null) and to false when the flag is set but 
> empty. Presumably, this is useful when you want a feature to be 
> enabled by default, but you need a way to disable it by setting the 
> flag to "false"
>
> Let's call this the "unlessDisabled" interpretation:
>
> -Dflag=true  => true
> -Dflag=TRUE  => true
> -Dflag       => false
> -Dflag=false => false
> -Dflag=FALSE => false
> -Dflag=abc   => false
> -DnotFlag    => true
>
> Switching the meaning of null seems useful, as it allows defining a 
> different default value when the flag is not set.
>
> Switching the meaning of empty seems more questionable. Why should the 
> following evaluate to false?
>
> -Djdk.preserveScopedValueCache
>
> Likewise, why should the following evaluate to false given that the 
> default if not set is true?
>
> -Djdk.preserveScopedValueCache=abc
>
> I'm wondering if such use cases would have been better served by a 
> "not set to false" interpretation:
>
> -Dflag=true  => true
> -Dflag=TRUE => true
> -Dflag       => true
> -Dflag=false => false
> -Dflag=FALSE => false
> -Dflag=abc   => true
> -DnotFlag => true
>
> Some examples of this logic:
>
> Continuation.java:
>
>     String value = System.getProperty("jdk.preserveScopedValueCache");
>     PRESERVE_SCOPED_VALUE_CACHE = (value == null) ||
>     Boolean.parseBoolean(value);
>
>
> HttpClient.java:
>
>     String keepAlive = props.getProperty("http.keepAlive");
>     if (keepAlive != null) {
>         keepAliveProp = Boolean.parseBoolean(keepAlive);
>     } else {
>         keepAliveProp = true;
>     }
>
>
> Complicating the above is the fact that not all  "true" or "false" 
> comparisons ignores case:
>
> InetAddress.java:
>
>     PREFER_IPV4_STACK_VALUE =
>     System.getProperty("java.net.preferIPv4Stack");
>
> ..
>
>     if ("true".equals(PREFER_IPV4_STACK_VALUE) && ipv4Available) {
>         return LookupPolicy.of(IPV4);
>     }
>
>
> The sum of all this "interpretation-of-flags" logic was a bit messy 
> and inconsistent before the JEP-486 cleanups. After the 
> SecurityManager cleanups, it's becoming increasingly evident that 
> there is a good amount of accidental complexity in this area.
>
> The analysis required just to prepare this email felt surprisingly 
> difficult. One would think programmers can reason about simple boolean 
> arithmetic, but after looking at this aspect of the code base for a 
> while, I quickly felt the need for a banana break :-)
>
> I guess there is also an underlying usability question here: Would 
> users prefer using the "ifEnabled" interpretation to configure a 
> "featureDisabled" flag, or would it be better to use an 
> "unlessDisabled" interpretation on a "featureEnabled" flag. Looking at 
> the OpenJDK code base, it's obvious that developers are not in 
> agreement about this question, leading to inconsistent treatment of 
> flags. (Personally, I much prefer "enabled=false" over "disabled=true")
>
> Perhaps we should introduce some "Flags" utility with functions for a 
> small set of standard interpretations? Then new code could mostly use 
> that, and existing code could gradually move over to match standard 
> interpretations after carefully reviewing behavioral impact?
>
> Any ideas, feedback, questions?
>
> Thanks,
> Eirik.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20241204/a4bfd666/attachment-0001.htm>


More information about the core-libs-dev mailing list