diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 2882b7079cb..9f64cb05b50 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; import org.springframework.boot.context.properties.NestedConfigurationProperty; import org.springframework.boot.convert.DurationUnit; +import org.springframework.boot.system.JavaVersion; import org.springframework.boot.web.server.Compression; import org.springframework.boot.web.server.Cookie; import org.springframework.boot.web.server.Http2; @@ -513,6 +514,12 @@ public class ServerProperties { */ private DataSize maxHttpResponseHeaderSize = DataSize.ofKilobytes(8); + /** + * Whether to use APR. If running on Java below 24, the default value is + * 'WHEN_AVAILABLE'. On Java 24 or later, the default value is 'NEVER'. + */ + private UseApr useApr; + public DataSize getMaxHttpFormPostSize() { return this.maxHttpFormPostSize; } @@ -669,6 +676,18 @@ public class ServerProperties { this.maxHttpResponseHeaderSize = maxHttpResponseHeaderSize; } + public UseApr getUseApr() { + if (this.useApr == null) { + return JavaVersion.getJavaVersion().isEqualOrNewerThan(JavaVersion.TWENTY_FOUR) ? UseApr.NEVER + : UseApr.WHEN_AVAILABLE; + } + return this.useApr; + } + + public void setUseApr(UseApr useApr) { + this.useApr = useApr; + } + /** * Tomcat access log properties. */ @@ -1918,4 +1937,26 @@ public class ServerProperties { } + /** + * When to use APR. + */ + public enum UseApr { + + /** + * Always use APR and fail if it's not available. + */ + ALWAYS, + + /** + * Use APR if it is available. + */ + WHEN_AVAILABLE, + + /** + * Never user APR. + */ + NEVER + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/TomcatReactiveWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/TomcatReactiveWebServerFactoryCustomizer.java index 5e5ca0c8546..4291e5c075c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/TomcatReactiveWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/TomcatReactiveWebServerFactoryCustomizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,14 @@ package org.springframework.boot.autoconfigure.web.reactive; +import org.apache.catalina.core.AprLifecycleListener; + import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat; +import org.springframework.boot.autoconfigure.web.ServerProperties.UseApr; import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.util.Assert; /** * {@link WebServerFactoryCustomizer} to apply {@link ServerProperties} to Tomcat reactive @@ -38,7 +43,27 @@ public class TomcatReactiveWebServerFactoryCustomizer @Override public void customize(TomcatReactiveWebServerFactory factory) { - factory.setDisableMBeanRegistry(!this.serverProperties.getTomcat().getMbeanregistry().isEnabled()); + Tomcat tomcatProperties = this.serverProperties.getTomcat(); + factory.setDisableMBeanRegistry(!tomcatProperties.getMbeanregistry().isEnabled()); + factory.setUseApr(getUseApr(tomcatProperties.getUseApr())); + } + + private boolean getUseApr(UseApr useApr) { + return switch (useApr) { + case ALWAYS -> { + Assert.state(isAprAvailable(), "APR has been configured to 'ALWAYS', but it's not available"); + yield true; + } + case WHEN_AVAILABLE -> isAprAvailable(); + case NEVER -> false; + }; + } + + private boolean isAprAvailable() { + // At least one instance of AprLifecycleListener has to be created for + // isAprAvailable() to work + new AprLifecycleListener(); + return AprLifecycleListener.isAprAvailable(); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/TomcatServletWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/TomcatServletWebServerFactoryCustomizer.java index f1dcfb7e265..ec40912ec2d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/TomcatServletWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/TomcatServletWebServerFactoryCustomizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,15 @@ package org.springframework.boot.autoconfigure.web.servlet; +import org.apache.catalina.core.AprLifecycleListener; + import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.autoconfigure.web.ServerProperties.UseApr; import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.core.Ordered; +import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; /** @@ -56,6 +60,7 @@ public class TomcatServletWebServerFactoryCustomizer } customizeUseRelativeRedirects(factory, tomcatProperties.isUseRelativeRedirects()); factory.setDisableMBeanRegistry(!tomcatProperties.getMbeanregistry().isEnabled()); + factory.setUseApr(getUseApr(tomcatProperties.getUseApr())); } private void customizeRedirectContextRoot(ConfigurableTomcatWebServerFactory factory, boolean redirectContextRoot) { @@ -67,4 +72,22 @@ public class TomcatServletWebServerFactoryCustomizer factory.addContextCustomizers((context) -> context.setUseRelativeRedirects(useRelativeRedirects)); } + private boolean getUseApr(UseApr useApr) { + return switch (useApr) { + case ALWAYS -> { + Assert.state(isAprAvailable(), "APR has been configured to 'ALWAYS', but it's not available"); + yield true; + } + case WHEN_AVAILABLE -> isAprAvailable(); + case NEVER -> false; + }; + } + + private boolean isAprAvailable() { + // At least one instance of AprLifecycleListener has to be created for + // isAprAvailable() to work + new AprLifecycleListener(); + return AprLifecycleListener.isAprAvailable(); + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java index 231df5b4c92..97704daebf1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,9 +35,12 @@ import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; import reactor.netty.http.HttpDecoderSpec; import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Accesslog; +import org.springframework.boot.autoconfigure.web.ServerProperties.UseApr; import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.source.ConfigurationPropertySource; @@ -69,6 +72,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Chris Bono * @author Parviz Rozikov * @author Lasse Wulff + * @author Moritz Halbritter */ @DirtiesUrlFactories class ServerPropertiesTests { @@ -494,6 +498,18 @@ class ServerPropertiesTests { .isEqualTo(HttpDecoderSpec.DEFAULT_INITIAL_BUFFER_SIZE); } + @Test + @EnabledForJreRange(max = JRE.JAVA_23) + void shouldDefaultAprToWhenAvailableUntilJava23() { + assertThat(this.properties.getTomcat().getUseApr()).isEqualTo(UseApr.WHEN_AVAILABLE); + } + + @Test + @EnabledForJreRange(min = JRE.JAVA_24) + void shouldDefaultAprToNeverOnJava24AndLater() { + assertThat(this.properties.getTomcat().getUseApr()).isEqualTo(UseApr.NEVER); + } + private Connector getDefaultConnector() { return new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactory.java index f50f1d4ebf3..5b449e69a1c 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ import org.apache.catalina.connector.Connector; import org.apache.catalina.core.AprLifecycleListener; import org.apache.catalina.loader.WebappLoader; import org.apache.catalina.startup.Tomcat; +import org.apache.catalina.startup.Tomcat.FixContextListener; import org.apache.catalina.webresources.StandardRoot; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -83,8 +84,6 @@ public class TomcatReactiveWebServerFactory extends AbstractReactiveWebServerFac private List contextLifecycleListeners = new ArrayList<>(); - private final List serverLifecycleListeners = getDefaultServerLifecycleListeners(); - private Set tomcatContextCustomizers = new LinkedHashSet<>(); private Set tomcatConnectorCustomizers = new LinkedHashSet<>(); @@ -101,6 +100,8 @@ public class TomcatReactiveWebServerFactory extends AbstractReactiveWebServerFac private boolean disableMBeanRegistry = true; + private boolean useApr; + /** * Create a new {@link TomcatReactiveWebServerFactory} instance. */ @@ -116,10 +117,12 @@ public class TomcatReactiveWebServerFactory extends AbstractReactiveWebServerFac super(port); } - private static List getDefaultServerLifecycleListeners() { - AprLifecycleListener aprLifecycleListener = new AprLifecycleListener(); - return AprLifecycleListener.isAprAvailable() ? new ArrayList<>(Arrays.asList(aprLifecycleListener)) - : new ArrayList<>(); + private List getDefaultServerLifecycleListeners() { + ArrayList lifecycleListeners = new ArrayList<>(); + if (this.useApr) { + lifecycleListeners.add(new AprLifecycleListener()); + } + return lifecycleListeners; } @Override @@ -130,7 +133,7 @@ public class TomcatReactiveWebServerFactory extends AbstractReactiveWebServerFac Tomcat tomcat = new Tomcat(); File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat"); tomcat.setBaseDir(baseDir.getAbsolutePath()); - for (LifecycleListener listener : this.serverLifecycleListeners) { + for (LifecycleListener listener : getDefaultServerLifecycleListeners()) { tomcat.getServer().addLifecycleListener(listener); } Connector connector = new Connector(this.protocol); @@ -171,7 +174,7 @@ public class TomcatReactiveWebServerFactory extends AbstractReactiveWebServerFac context.setResources(resourcesRoot); context.setPath(""); context.setDocBase(docBase.getAbsolutePath()); - context.addLifecycleListener(new Tomcat.FixContextListener()); + context.addLifecycleListener(new FixContextListener()); ClassLoader parentClassLoader = ClassUtils.getDefaultClassLoader(); context.setParentClassLoader(parentClassLoader); skipAllTldScanning(context); @@ -476,4 +479,13 @@ public class TomcatReactiveWebServerFactory extends AbstractReactiveWebServerFac this.disableMBeanRegistry = disableMBeanRegistry; } + /** + * Whether to use APR. + * @param useApr whether to use APR + * @since 3.4.4 + */ + public void setUseApr(boolean useApr) { + this.useApr = useApr; + } + } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java index cf897544f9e..3920748cf3c 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -135,8 +135,6 @@ public class TomcatServletWebServerFactory extends AbstractServletWebServerFacto private List contextLifecycleListeners = new ArrayList<>(); - private final List serverLifecycleListeners = getDefaultServerLifecycleListeners(); - private Set tomcatContextCustomizers = new LinkedHashSet<>(); private Set tomcatConnectorCustomizers = new LinkedHashSet<>(); @@ -159,6 +157,8 @@ public class TomcatServletWebServerFactory extends AbstractServletWebServerFacto private boolean disableMBeanRegistry = true; + private boolean useApr; + /** * Create a new {@link TomcatServletWebServerFactory} instance. */ @@ -184,13 +184,10 @@ public class TomcatServletWebServerFactory extends AbstractServletWebServerFacto super(contextPath, port); } - private static List getDefaultServerLifecycleListeners() { + private List getDefaultServerLifecycleListeners() { ArrayList lifecycleListeners = new ArrayList<>(); - if (!NativeDetector.inNativeImage()) { - AprLifecycleListener aprLifecycleListener = new AprLifecycleListener(); - if (AprLifecycleListener.isAprAvailable()) { - lifecycleListeners.add(aprLifecycleListener); - } + if (!NativeDetector.inNativeImage() && this.useApr) { + lifecycleListeners.add(new AprLifecycleListener()); } return lifecycleListeners; } @@ -203,7 +200,7 @@ public class TomcatServletWebServerFactory extends AbstractServletWebServerFacto Tomcat tomcat = new Tomcat(); File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat"); tomcat.setBaseDir(baseDir.getAbsolutePath()); - for (LifecycleListener listener : this.serverLifecycleListeners) { + for (LifecycleListener listener : getDefaultServerLifecycleListeners()) { tomcat.getServer().addLifecycleListener(listener); } Connector connector = new Connector(this.protocol); @@ -784,6 +781,15 @@ public class TomcatServletWebServerFactory extends AbstractServletWebServerFacto this.disableMBeanRegistry = disableMBeanRegistry; } + /** + * Whether to use APR. + * @param useApr whether to use APR + * @since 3.4.4 + */ + public void setUseApr(boolean useApr) { + this.useApr = useApr; + } + /** * {@link LifecycleListener} to disable persistence in the {@link StandardManager}. A * {@link LifecycleListener} is used so not to interfere with Tomcat's default manager diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java index aaa1170c62f..cdd83d00876 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -95,12 +95,20 @@ class TomcatReactiveWebServerFactoryTests extends AbstractReactiveWebServerFacto @Test void defaultTomcatListeners() { TomcatReactiveWebServerFactory factory = getFactory(); - if (AprLifecycleListener.isAprAvailable()) { - assertThat(factory.getContextLifecycleListeners()).singleElement().isInstanceOf(AprLifecycleListener.class); - } - else { - assertThat(factory.getContextLifecycleListeners()).isEmpty(); - } + assertThat(factory.getContextLifecycleListeners()).isEmpty(); + TomcatWebServer tomcatWebServer = (TomcatWebServer) factory.getWebServer(mock(HttpHandler.class)); + this.webServer = tomcatWebServer; + assertThat(tomcatWebServer.getTomcat().getServer().findLifecycleListeners()).isEmpty(); + } + + @Test + void aprShouldBeOptIn() { + TomcatReactiveWebServerFactory factory = getFactory(); + factory.setUseApr(true); + TomcatWebServer tomcatWebServer = (TomcatWebServer) factory.getWebServer(mock(HttpHandler.class)); + this.webServer = tomcatWebServer; + assertThat(tomcatWebServer.getTomcat().getServer().findLifecycleListeners()).singleElement() + .isInstanceOf(AprLifecycleListener.class); } @Test diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java index 08246478d12..39812cee4e4 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java @@ -150,12 +150,20 @@ class TomcatServletWebServerFactoryTests extends AbstractServletWebServerFactory @Test void defaultTomcatListeners() { TomcatServletWebServerFactory factory = getFactory(); - if (AprLifecycleListener.isAprAvailable()) { - assertThat(factory.getContextLifecycleListeners()).singleElement().isInstanceOf(AprLifecycleListener.class); - } - else { - assertThat(factory.getContextLifecycleListeners()).isEmpty(); - } + assertThat(factory.getContextLifecycleListeners()).isEmpty(); + TomcatWebServer tomcatWebServer = (TomcatWebServer) factory.getWebServer(); + this.webServer = tomcatWebServer; + assertThat(tomcatWebServer.getTomcat().getServer().findLifecycleListeners()).isEmpty(); + } + + @Test + void aprShouldBeOptIn() { + TomcatServletWebServerFactory factory = getFactory(); + factory.setUseApr(true); + TomcatWebServer tomcatWebServer = (TomcatWebServer) factory.getWebServer(); + this.webServer = tomcatWebServer; + assertThat(tomcatWebServer.getTomcat().getServer().findLifecycleListeners()).singleElement() + .isInstanceOf(AprLifecycleListener.class); } @Test diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-classic-tests/src/dockerTest/java/org/springframework/boot/loader/LoaderIntegrationTests.java b/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-classic-tests/src/dockerTest/java/org/springframework/boot/loader/LoaderIntegrationTests.java index 99683fa4dd0..a77127dbb41 100644 --- a/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-classic-tests/src/dockerTest/java/org/springframework/boot/loader/LoaderIntegrationTests.java +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-classic-tests/src/dockerTest/java/org/springframework/boot/loader/LoaderIntegrationTests.java @@ -67,15 +67,12 @@ class LoaderIntegrationTests { .withLogConsumer(this.output) .withCopyFileToContainer(MountableFile.forHostPath(findApplication().toPath()), "/app.jar") .withStartupCheckStrategy(new OneShotStartupCheckStrategy().withTimeout(Duration.ofMinutes(5))) - .withCommand(command(javaRuntime)); + .withCommand(command()); } - private String[] command(JavaRuntime javaRuntime) { + private String[] command() { List command = new ArrayList<>(); command.add("java"); - if (javaRuntime.version == JavaVersion.TWENTY_FOUR) { - command.add("--enable-native-access=ALL-UNNAMED"); - } command.add("-jar"); command.add("app.jar"); return command.toArray(new String[0]); diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/src/dockerTest/java/org/springframework/boot/loader/LoaderIntegrationTests.java b/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/src/dockerTest/java/org/springframework/boot/loader/LoaderIntegrationTests.java index de3876bb69e..f71d1579f8d 100644 --- a/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/src/dockerTest/java/org/springframework/boot/loader/LoaderIntegrationTests.java +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/src/dockerTest/java/org/springframework/boot/loader/LoaderIntegrationTests.java @@ -90,15 +90,12 @@ class LoaderIntegrationTests { .withLogConsumer(this.output) .withCopyFileToContainer(findApplication(name, classifier), "/app.jar") .withStartupCheckStrategy(new OneShotStartupCheckStrategy().withTimeout(Duration.ofMinutes(5))) - .withCommand(command(javaRuntime)); + .withCommand(command()); } - private String[] command(JavaRuntime javaRuntime) { + private String[] command() { List command = new ArrayList<>(); command.add("java"); - if (javaRuntime.version == JavaVersion.TWENTY_FOUR) { - command.add("--enable-native-access=ALL-UNNAMED"); - } command.add("-jar"); command.add("app.jar"); return command.toArray(new String[0]);