Skip to content

[GR-68047] Split up and rename future defaults. #11790

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions docs/reference-manual/native-image/JCASecurityServices.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,17 @@ The report will detail all registered service classes, the API methods that trig

## Provider Initialization

Currently security providers are initialized at build time.
To move their initialization to run time, use the option `--future-defaults=all` or `--future-defaults=run-time-initialized-jdk`.
Provider verification will still occur at build time.
Currently, security providers are initialized at build time.
To move their initialization to run time, use the option `--future-defaults=run-time-initialize-security-providers`, `--future-defaults=all`, or `--future-defaults=run-time-initialize-jdk`.
Provider verification will still occur at build time.
Run-time initialization of security providers helps reduce image heap size.
To move their initialization to run time, you can use the flag `--future-defaults=all` or `--future-defaults=run-time-initialized-jdk`.

## Provider Registration

The `native-image` builder captures the list of providers and their preference order from the underlying JVM.
The provider order is specified in the `java.security` file under `<java-home>/conf/security/java.security`.
New security providers cannot be registered at run time by default (see the section above); all providers must be statically configured at executable build time.
If the user specifies `--future-defaults=all` or `--future-defaults=run-time-initialized-jdk` to move providers initialization to run time, then a specific properties file can be used via the command line option `-Djava.security.properties=<path>`.
If the user specifies `--future-defaults=run-time-initialize-security-providers`, `--future-defaults=all`, or `--future-defaults=run-time-initialize-jdk` to move providers initialization to run time, then a specific properties file can be used via the command line option `-Djava.security.properties=<path>`.

## Providers Reordering at Run Time

Expand All @@ -61,7 +60,7 @@ Security.removeProvider("BC");
Security.insertProviderAt(bcProvider, 1);
```

If `--future-defaults=all` or `--future-defaults=run-time-initialized-jdk` is enabled, the list of providers is constructed at run time.
If `--future-defaults=all` or `--future-defaults=run-time-initialize-jdk` is enabled, the list of providers is constructed at run time.
The same approach to manipulating providers can then be used.

## SecureRandom
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

Expand Down Expand Up @@ -54,26 +55,36 @@
* rolled back. The changes must be aligning native image with the Java spec and must be thoroughly
* reviewed.
* </p>
* Note 2: future defaults can not be simply removed as user code can depend on the system property
* Note 2: future defaults can depend on each other. For example, if some functionality depends on
* <code>run-time-security-providers</code> it can enable it similarly to <code>all</code> that
* enables all future defaults.
* </p>
* Note 3: future defaults can not be simply removed as user code can depend on the system property
* values that are set by the option. When removing a future-default option, one has to leave the
* system property both a build time and at run time set to <code>true</code>.
*/
public class FutureDefaultsOptions {
private static final String OPTION_NAME = "future-defaults";

private static final String DEFAULT_NAME = "<default-value>";
private static final String ALL_NAME = "all";
private static final String RUN_TIME_INITIALIZE_JDK = "run-time-initialize-jdk";
private static final String NONE_NAME = "none";
private static final String RUN_TIME_INITIALIZE_JDK_NAME = "run-time-initialized-jdk";
private static final String TREAT_NAME_AS_TYPE_NAME = "treat-name-as-type";

public static final String RUN_TIME_INITIALIZE_JDK_REASON = "Initialize JDK classes at run time (--" + OPTION_NAME + " includes " + RUN_TIME_INITIALIZE_JDK_NAME + ")";

/**
* Macro commands: They enable or disable other defaults, but they are not future defaults
* themselves.
*/
private static final Set<String> ALL_COMMANDS = Set.of(ALL_NAME, RUN_TIME_INITIALIZE_JDK, NONE_NAME);

private static final String RUN_TIME_INITIALIZE_SECURITY_PROVIDERS = "run-time-initialize-security-providers";
private static final String RUN_TIME_INITIALIZE_FILE_SYSTEM_PROVIDERS = "run-time-initialize-file-system-providers";
private static final String COMPLETE_REFLECTION_TYPES = "complete-reflection-types";
private static final Set<String> ALL_FUTURE_DEFAULTS = Set.of(RUN_TIME_INITIALIZE_FILE_SYSTEM_PROVIDERS, RUN_TIME_INITIALIZE_SECURITY_PROVIDERS, COMPLETE_REFLECTION_TYPES);

public static final String RUN_TIME_INITIALIZE_FILE_SYSTEM_PROVIDERS_REASON = "Initialize JDK classes at run time (--" + OPTION_NAME + " includes " + RUN_TIME_INITIALIZE_SECURITY_PROVIDERS + ")";
public static final String RUN_TIME_INITIALIZE_SECURITY_PROVIDERS_REASON = "Initialize JDK classes at run time (--" + OPTION_NAME + " includes " + RUN_TIME_INITIALIZE_FILE_SYSTEM_PROVIDERS + ")";
private static final String DEFAULT_NAME = "<default-value>";
public static final String SYSTEM_PROPERTY_PREFIX = ImageInfo.PROPERTY_NATIVE_IMAGE_PREFIX + OPTION_NAME + ".";

private static final Set<String> ALL_FUTURE_DEFAULTS = Set.of(RUN_TIME_INITIALIZE_JDK_NAME, TREAT_NAME_AS_TYPE_NAME);
private static final Set<String> ALL_COMMANDS = Set.of(ALL_NAME, NONE_NAME);

private static String futureDefaultsAllValues() {
return StringUtil.joinSingleQuoted(getAllValues());
}
Expand Down Expand Up @@ -128,6 +139,8 @@ public static void parseAndVerifyOptions() {

if (value.equals(ALL_NAME)) {
futureDefaults.addAll(ALL_FUTURE_DEFAULTS);
} else if (value.equals(RUN_TIME_INITIALIZE_JDK)) {
futureDefaults.addAll(List.of(RUN_TIME_INITIALIZE_SECURITY_PROVIDERS, RUN_TIME_INITIALIZE_FILE_SYSTEM_PROVIDERS));
} else {
futureDefaults.add(value);
}
Expand All @@ -143,15 +156,31 @@ public static Set<String> getFutureDefaults() {
return Collections.unmodifiableSet(Objects.requireNonNull(futureDefaults, "must be initialized before usage"));
}

/**
* @see FutureDefaultsOptions#FutureDefaults
*/
public static boolean allFutureDefaults() {
return getFutureDefaults().containsAll(ALL_FUTURE_DEFAULTS);
}

public static boolean isJDKInitializedAtRunTime() {
return getFutureDefaults().contains(RUN_TIME_INITIALIZE_JDK_NAME);
/**
* @see FutureDefaultsOptions#FutureDefaults
*/
public static boolean completeReflectionTypes() {
return getFutureDefaults().contains(COMPLETE_REFLECTION_TYPES);
}

/**
* @see FutureDefaultsOptions#FutureDefaults
*/
public static boolean securityProvidersInitializedAtRunTime() {
return getFutureDefaults().contains(RUN_TIME_INITIALIZE_SECURITY_PROVIDERS);
}

public static boolean treatNameAsType() {
return getFutureDefaults().contains(TREAT_NAME_AS_TYPE_NAME);
/**
* @see FutureDefaultsOptions#FutureDefaults
*/
public static boolean fileSystemProvidersInitializedAtRunTime() {
return getFutureDefaults().contains(RUN_TIME_INITIALIZE_FILE_SYSTEM_PROVIDERS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public static EnumSet<ConfigurationParserOption> getConfigurationParserOptions()
if (TreatAllTypeReachableConditionsAsTypeReached.getValue()) {
result.add(ConfigurationParserOption.TREAT_ALL_TYPE_REACHABLE_CONDITIONS_AS_TYPE_REACHED);
}
if (TreatAllNameEntriesAsType.getValue() || FutureDefaultsOptions.treatNameAsType()) {
if (TreatAllNameEntriesAsType.getValue() || FutureDefaultsOptions.completeReflectionTypes()) {
result.add(ConfigurationParserOption.TREAT_ALL_NAME_ENTRIES_AS_TYPE);
}
return result;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Enable options that are planned to become defaults in future releases. Comma-separated list can contain 'all', 'run-time-initialized-jdk', 'none'.
Enable options that are planned to become defaults in future releases. Comma-separated list can contain 'all', 'treat-name-as-type', 'run-time-initialize-security-providers', 'run-time-initialize-file-system-providers', and 'none'.

The preferred way to use this option is '--future-defaults=all'. The meaning of each possible option is as follows:
1. 'all' is the preferred option, and it enables all other behaviors.
2. 'run-time-initialized-jdk' shifts away from build-time initialization of the JDK, instead initializing most of it at run time. This transition is gradual, with individual components of the JDK becoming run-time initialized in each release. This process should complete with JDK 29 when this option should not be needed anymore. Unless you store classes from the JDK in the image heap, this option should not affect you. In case this option breaks your build, follow the suggestions in the error messages.
3. 'none' forcefully disables all enabled options. This can be used only on the command line to override choices taken by inaccessible parts of the build process.
2. 'complete-reflection-types' reflective registration of a type, via metadata files or the Feature API, always includes all type metadata. Now, all registered types behave the same as types defined in 'reachability-metadata.json'.
3. 'run-time-initialize-security-providers' shifts away from build-time initialization for 'java.security.Provider'. Unless you store 'java.security.Provider'-related classes in the image heap, this option should not affect you. In case this option breaks your build, follow the suggestions in the error messages.
4. 'run-time-initialize-file-system-providers' shifts away from build-time initialization for 'java.nio.file.spi.FileSystemProvider'. Unless you store 'FileSystemProvider'-related classes in the image heap, this option should not affect you. In case this option breaks your build, follow the suggestions in the error messages.
5. 'none' forcefully disables all enabled options. This can be used only on the command line to override choices taken by inaccessible parts of the build process.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public final class FileSystemProviderSupport {

@Platforms(Platform.HOSTED_ONLY.class)
public static void register(FileSystemProvider provider) {
VMError.guarantee(!FutureDefaultsOptions.isJDKInitializedAtRunTime(), "No need to register FileSystemProvider if the JDK is initialized at run time.");
VMError.guarantee(!FutureDefaultsOptions.fileSystemProvidersInitializedAtRunTime(), "No need to register FileSystemProvider if the JDK is initialized at run time.");
FileSystemProviderBuildTimeInitSupport.register(provider);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2025, 2025, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.core.jdk;

import java.util.function.BooleanSupplier;

import com.oracle.svm.core.FutureDefaultsOptions;

public class FileSystemProvidersInitializedAtBuildTime implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return !FutureDefaultsOptions.fileSystemProvidersInitializedAtRunTime();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2025, 2025, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.core.jdk;

import java.util.function.BooleanSupplier;

import com.oracle.svm.core.FutureDefaultsOptions;

public class FileSystemProvidersInitializedAtRunTime implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return FutureDefaultsOptions.fileSystemProvidersInitializedAtRunTime();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@

import com.oracle.svm.core.FutureDefaultsOptions;

public class JDKInitializedAtRunTime implements BooleanSupplier {
public class SecurityProvidersInitializedAtBuildTime implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return FutureDefaultsOptions.isJDKInitializedAtRunTime();
return !FutureDefaultsOptions.securityProvidersInitializedAtRunTime();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@

import com.oracle.svm.core.FutureDefaultsOptions;

public class JDKInitializedAtBuildTime implements BooleanSupplier {
public class SecurityProvidersInitializedAtRunTime implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return !FutureDefaultsOptions.isJDKInitializedAtRunTime();
return FutureDefaultsOptions.securityProvidersInitializedAtRunTime();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ private static void setJavaHome(String newJavaHome) {
* properly signed and can be used by JCE. It does that via jar verification which we cannot
* support.
*/
@TargetClass(className = "javax.crypto.JceSecurity", onlyWith = JDKInitializedAtBuildTime.class)
@TargetClass(className = "javax.crypto.JceSecurity", onlyWith = SecurityProvidersInitializedAtBuildTime.class)
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+27/src/java.base/share/classes/javax/crypto/JceSecurity.java.template")
@SuppressWarnings({"unused"})
final class Target_javax_crypto_JceSecurity {
Expand Down Expand Up @@ -303,7 +303,7 @@ static Exception getVerificationResult(Provider p) {
}
}

@TargetClass(className = "javax.crypto.JceSecurity", innerClass = "WeakIdentityWrapper", onlyWith = JDKInitializedAtBuildTime.class)
@TargetClass(className = "javax.crypto.JceSecurity", innerClass = "WeakIdentityWrapper", onlyWith = SecurityProvidersInitializedAtBuildTime.class)
@SuppressWarnings({"unused"})
final class Target_javax_crypto_JceSecurity_WeakIdentityWrapper {

Expand Down Expand Up @@ -377,7 +377,7 @@ public boolean implies(ProtectionDomain domain, Permission permission) {
}
}

@TargetClass(className = "sun.security.jca.ProviderConfig", onlyWith = JDKInitializedAtBuildTime.class)
@TargetClass(className = "sun.security.jca.ProviderConfig", onlyWith = SecurityProvidersInitializedAtBuildTime.class)
@SuppressWarnings({"unused", "static-method"})
final class Target_sun_security_jca_ProviderConfig {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public void afterRegistration(AfterRegistrationAccess access) {
*/
RuntimeClassInitializationSupport rci = ImageSingletons.lookup(RuntimeClassInitializationSupport.class);
rci.initializeAtBuildTime("sun.security.util.UntrustedCertificates", "Required for TrustStoreManager");
if (!FutureDefaultsOptions.isJDKInitializedAtRunTime()) {
if (!FutureDefaultsOptions.securityProvidersInitializedAtRunTime()) {
/*
* All security providers must be registered (and initialized) at buildtime (see
* SecuritySubstitutions.java). XMLDSigRI is used for validating XML Signatures from
Expand Down
Loading
Loading