This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 9a56dc951a Route production system-property access through Settings
abstraction (TODO-234)
9a56dc951a is described below
commit 9a56dc951a881cfb6b81ce087f1554648177fec0
Author: James Bognar <[email protected]>
AuthorDate: Tue Jul 14 09:24:11 2026 -0400
Route production system-property access through Settings abstraction
(TODO-234)
Migrate production System.getProperty reads onto the Settings lookup chain
so
they are test-overridable via Settings.setLocal/setGlobal, and document the
raw-access sites that must intentionally stay unabstracted (SVL $S{...}
which
reads System.getProperty directly, jetty/tomcat bound-port publication
consumed
by jetty.xml, and external logging adapters).
Co-authored-by: Cursor <[email protected]>
---
.../src/main/java/org/apache/juneau/config/Config.java | 6 +++++-
.../juneau/marshall/parquet/ParquetParserSession.java | 15 ++++++++++-----
.../juneau/microservice/jetty/JettyServerComponent.java | 9 +++++++++
.../juneau/microservice/tomcat/TomcatServerComponent.java | 9 +++++++++
.../java/org/apache/juneau/microservice/Microservice.java | 8 ++++++++
.../org/apache/juneau/rest/mock/classic/MockLogger.java | 6 ++++++
6 files changed, 47 insertions(+), 6 deletions(-)
diff --git
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
index b28e155717..9a7f917635 100644
---
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
+++
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
@@ -513,7 +513,7 @@ public class Config extends Context implements
ConfigEventListener {
return l;
}
- var cmd = System.getProperty("sun.java.command",
"not_found").split("\\s+")[0];
+ var cmd = env("sun.java.command", "not_found").split("\\s+")[0];
if (cmd.endsWith(".jar") && ! co(cmd, "surefirebooter")) { //
HTT - not a .jar during tests
cmd = cmd.replaceAll(".*?([^\\\\\\/]+)\\.jar$", "$1");
l.add(cmd + ".cfg");
@@ -1157,6 +1157,10 @@ public class Config extends Context implements
ConfigEventListener {
for (var section : getSectionNames()) {
for (var key : getKeys(section)) {
var k = (section.isEmpty() ? key : section +
'/' + key);
+ // Intentional real-JVM-property export: this
method's documented contract is to publish config
+ // entries as process-global system properties
so external/third-party code (which reads raw
+ // System.getProperty) can observe them.
Routing through Settings would break that contract, so
+ // the mutation is kept deliberately.
System.setProperty(k, getRaw(k));
}
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetParserSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetParserSession.java
index ace665fec3..b7a95faee9 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetParserSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/parquet/ParquetParserSession.java
@@ -18,6 +18,7 @@ package org.apache.juneau.marshall.parquet;
import static org.apache.juneau.commons.utils.AssertionUtils.*;
import static org.apache.juneau.commons.utils.Shorts.*;
+import static org.apache.juneau.commons.utils.SystemUtils.*;
import static org.apache.juneau.marshall.parquet.ParquetSchemaElement.*;
import java.io.*;
@@ -47,8 +48,12 @@ public class ParquetParserSession extends
InputStreamParserSession implements Re
private static final byte[] MAGIC =
"PAR1".getBytes(StandardCharsets.UTF_8);
private static final String ARG_ctx = "ctx";
- /** Enable via {@link #setDebugEnabled} or -Djuneau.parquet.debug=true.
*/
- private static boolean parquetDebug =
"true".equals(System.getProperty("juneau.parquet.debug"));
+ /**
+ * Explicit override set via {@link #setDebugEnabled}. When {@code
null}, the debug state is read
+ * from the {@code juneau.parquet.debug} setting through the settings
lookup chain (via {@code env(...)}),
+ * making it test-overridable via {@code Settings.setLocal}/{@code
setGlobal}.
+ */
+ private static Boolean parquetDebugOverride;
/**
* Enable debug output for schema/column tracing.
@@ -56,16 +61,16 @@ public class ParquetParserSession extends
InputStreamParserSession implements Re
* @param enabled <jk>true</jk> to enable debug logging to temp file.
*/
public static void setDebugEnabled(boolean enabled) {
- parquetDebug = enabled;
+ parquetDebugOverride = enabled;
}
private static boolean parquetDebug() {
- return parquetDebug;
+ return parquetDebugOverride != null ? parquetDebugOverride :
env("juneau.parquet.debug", false);
}
private static void parquetDebugLog(String msg) {
try {
- var f =
java.nio.file.Paths.get(System.getProperty("java.io.tmpdir", "/tmp"),
"juneau-parquet-debug.log");
+ var f = java.nio.file.Paths.get(env("java.io.tmpdir",
"/tmp"), "juneau-parquet-debug.log");
java.nio.file.Files.writeString(f, "[Parquet DEBUG] " +
msg + "\n",
java.nio.file.StandardOpenOption.CREATE,
java.nio.file.StandardOpenOption.APPEND);
} catch (@SuppressWarnings("unused") IOException ignored) {
diff --git
a/juneau-microservice/juneau-microservice-jetty/src/main/java/org/apache/juneau/microservice/jetty/JettyServerComponent.java
b/juneau-microservice/juneau-microservice-jetty/src/main/java/org/apache/juneau/microservice/jetty/JettyServerComponent.java
index 14bcb34ebf..c64139344f 100644
---
a/juneau-microservice/juneau-microservice-jetty/src/main/java/org/apache/juneau/microservice/jetty/JettyServerComponent.java
+++
b/juneau-microservice/juneau-microservice-jetty/src/main/java/org/apache/juneau/microservice/jetty/JettyServerComponent.java
@@ -212,6 +212,11 @@ public class JettyServerComponent implements
MicroserviceListener {
var availablePort = findOpenPort(ports);
if (availablePortEnv.isEmpty())
+ // Intentional real-JVM-property publish: the
bundled jetty.xml binds its connector to
+ // $S{availablePort,10000}, and the $S{...} SVL
var resolves via raw System.getProperty (bypassing
+ // the Settings override chain). A
Settings-based write would be invisible to jetty.xml, so the
+ // bound port MUST be published as a real
system property here. The @Value-injected availablePortEnv
+ // read side is already Settings-abstracted;
only this publish must stay raw.
System.setProperty("availablePort",
String.valueOf(availablePort));
// Prefer a @Bean-supplied Server, else build one from
jetty.xml.
@@ -312,6 +317,10 @@ public class JettyServerComponent implements
MicroserviceListener {
}
if (serverPortEnv.isEmpty())
+ // Intentional real-JVM-property publish:
juneau.serverPort is a documented cross-component/external
+ // publication of the bound port, consumed via
raw System.getProperty (and $S{...} SVL). A
+ // Settings-based write would not be visible to
those raw readers, so this is kept. The
+ // @Value-injected serverPortEnv read side is
already Settings-abstracted.
System.setProperty("juneau.serverPort",
String.valueOf(availablePort));
server.get().start();
diff --git
a/juneau-microservice/juneau-microservice-tomcat/src/main/java/org/apache/juneau/microservice/tomcat/TomcatServerComponent.java
b/juneau-microservice/juneau-microservice-tomcat/src/main/java/org/apache/juneau/microservice/tomcat/TomcatServerComponent.java
index 89fbd38ee9..5f91a3f7a2 100644
---
a/juneau-microservice/juneau-microservice-tomcat/src/main/java/org/apache/juneau/microservice/tomcat/TomcatServerComponent.java
+++
b/juneau-microservice/juneau-microservice-tomcat/src/main/java/org/apache/juneau/microservice/tomcat/TomcatServerComponent.java
@@ -215,6 +215,11 @@ public class TomcatServerComponent implements
MicroserviceListener {
var availablePort = findOpenPort(ports);
if (availablePortEnv.isEmpty())
+ // Intentional real-JVM-property publish: the
bound port is exposed as a process-global system
+ // property so external config/templates (e.g.
the bundled jetty.xml's $S{availablePort}) can read
+ // it. The $S{...} SVL var resolves via raw
System.getProperty (bypassing the Settings override
+ // chain), so a Settings-based write would be
invisible to those consumers. The @Value-injected
+ // availablePortEnv read side is already
Settings-abstracted; only this publish must stay raw.
System.setProperty("availablePort",
String.valueOf(availablePort));
// Prefer a @Bean-supplied Tomcat, else build one
programmatically via the factory.
@@ -269,6 +274,10 @@ public class TomcatServerComponent implements
MicroserviceListener {
}
if (serverPortEnv.isEmpty())
+ // Intentional real-JVM-property publish:
juneau.serverPort is a documented cross-component/external
+ // publication of the bound port, consumed via
raw System.getProperty (and $S{...} SVL). A
+ // Settings-based write would not be visible to
those raw readers, so this is kept. The
+ // @Value-injected serverPortEnv read side is
already Settings-abstracted.
System.setProperty("juneau.serverPort",
String.valueOf(availablePort));
tomcat.get().start();
diff --git
a/juneau-microservice/juneau-microservice/src/main/java/org/apache/juneau/microservice/Microservice.java
b/juneau-microservice/juneau-microservice/src/main/java/org/apache/juneau/microservice/Microservice.java
index 7789423a1e..e3f1fcec6c 100755
---
a/juneau-microservice/juneau-microservice/src/main/java/org/apache/juneau/microservice/Microservice.java
+++
b/juneau-microservice/juneau-microservice/src/main/java/org/apache/juneau/microservice/Microservice.java
@@ -1166,6 +1166,10 @@ public class Microservice implements ConfigEventListener
{
var spKeys = config.getKeys("SystemProperties");
if (nn(spKeys))
for (var key : spKeys)
+ // Intentional real-JVM-property export: the
[SystemProperties] config section is a documented
+ // feature whose whole purpose is to push
config entries into process-global system properties so
+ // third-party libraries (e.g. SLF4J/logging
adapters) that read raw System.getProperty pick them
+ // up. A Settings-based write would be
invisible to those external consumers, so this is kept.
System.setProperty(key,
config.get("SystemProperties/" + key).orElse(null));
//
--------------------------------------------------------------------------------
@@ -1183,6 +1187,10 @@ public class Microservice implements ConfigEventListener
{
var logDirFile = resolveFile(logDir);
mkdirs(logDirFile, false);
logDir = logDirFile.getAbsolutePath();
+ // Intentional real-JVM-property publish: the
resolved log directory is exposed as a process-global
+ // system property so external config/templates
can reference it via the raw-reading $S{juneau.logDir}
+ // SVL var (SystemPropertiesVar reads
System.getProperty directly, bypassing the Settings override
+ // chain). A Settings-based write would not be
visible to $S{...}, so this is kept.
System.setProperty("juneau.logDir", logDir);
var append = coalesce(logConfig.append,
config.get("Logging/append").asBoolean().orElse(false));
diff --git
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/classic/MockLogger.java
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/classic/MockLogger.java
index 841370974a..880e854fba 100644
---
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/classic/MockLogger.java
+++
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/classic/MockLogger.java
@@ -225,6 +225,12 @@ public class MockLogger extends Logger {
synchronized (this) {
f = formatter.get();
if (f == null) { // HTT - double-checked
locking; false branch requires concurrent thread
+ // Intentional, contained
global-property mutation: the JDK's SimpleFormatter reads its layout
+ // exclusively from the raw
java.util.logging.SimpleFormatter.format system property at
+ // construction time. There is no
constructor/API to inject the format, and the Settings
+ // abstraction cannot intercept a
JDK-internal raw read, so we must set the property, construct
+ // the formatter, then restore the
prior value. The mutation is fully guarded by this lock and
+ // paired save/restore.
String oldFormat =
System.getProperty(FORMAT_PROPERTY);
System.setProperty(FORMAT_PROPERTY,
format.get());
f = new SimpleFormatter();