Skip to content

Commit 9640aaa

Browse files
authored
Merge pull request #215 from javaevolved/copilot/runtime-exec-to-process-builder
Add tooling pattern: Runtime.exec(String) to ProcessBuilder arguments
2 parents 5c27101 + 55176fe commit 9640aaa

19 files changed

Lines changed: 317 additions & 2 deletions

content/language/anonymous-classes-to-lambdas.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ whyModernWins:
3333
support:
3434
state: "available"
3535
description: "Available since JDK 8 (March 2014)."
36-
prev: "tooling/junit6-with-jspecify"
36+
prev: "tooling/runtime-exec-to-process-builder"
3737
next: "language/default-interface-methods"
3838
related:
3939
- "language/default-interface-methods"

content/tooling/junit6-with-jspecify.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ support:
8888
state: "available"
8989
description: "Available since JUnit 6.0 (October 2025, requires Java 17+)"
9090
prev: "tooling/aot-class-preloading"
91-
next: "language/anonymous-classes-to-lambdas"
91+
next: "tooling/runtime-exec-to-process-builder"
9292
related:
9393
- "enterprise/spring-null-safety-jspecify"
9494
- "errors/helpful-npe"
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
id: e27cf2f6-ae52-4d75-a481-0fd04dbf2999
3+
slug: "runtime-exec-to-process-builder"
4+
title: "Runtime.exec(String) to ProcessBuilder arguments"
5+
category: "tooling"
6+
difficulty: "intermediate"
7+
jdkVersion: "5"
8+
oldLabel: "Command string"
9+
modernLabel: "ProcessBuilder"
10+
oldApproach: "Runtime.exec(String)"
11+
modernApproach: "ProcessBuilder"
12+
oldCode: |-
13+
Process process = Runtime.getRuntime()
14+
.exec("git show " + revision);
15+
modernCode: |-
16+
Process process = new ProcessBuilder(
17+
"git", "show", revision)
18+
.redirectErrorStream(true)
19+
.start();
20+
summary: "Launch processes with an explicit argument list and ProcessBuilder configuration."
21+
explanation: "Runtime.exec(String) applies Java's command-string tokenization, which\
22+
\ is easy to misunderstand when arguments contain spaces or quoting. ProcessBuilder\
23+
\ accepts program arguments as distinct values and exposes the working directory,\
24+
\ environment, input/output redirects, and error-stream policy explicitly. It does\
25+
\ not invoke a shell unless the application deliberately launches one."
26+
whyModernWins:
27+
- icon: "🎯"
28+
title: "Exact arguments"
29+
desc: "Each process argument remains a distinct value without command-string tokenization."
30+
- icon: "🎛"
31+
title: "Explicit configuration"
32+
desc: "Environment, directory, redirects, and error handling are configured together."
33+
- icon: "🛡"
34+
title: "Safer boundaries"
35+
desc: "Avoids constructing a shell-like command string from dynamic values."
36+
support:
37+
state: "available"
38+
description: "Widely available since JDK 5 (September 2004)"
39+
prev: "tooling/junit6-with-jspecify"
40+
next: "language/anonymous-classes-to-lambdas"
41+
related:
42+
- "concurrency/process-api"
43+
- "io/inputstream-transferto"
44+
- "security/security-manager-migration"
45+
tags:
46+
- tooling
47+
- security
48+
docs:
49+
- title: "ProcessBuilder"
50+
href: "https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/ProcessBuilder.html"
51+
- title: "Runtime.exec(String)"
52+
href: "https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Runtime.html#exec(java.lang.String)"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
///usr/bin/env jbang "$0" "$@" ; exit $?
2+
//JAVA 25+
3+
4+
/// Proof: runtime-exec-to-process-builder
5+
/// Source: content/tooling/runtime-exec-to-process-builder.yaml
6+
void main() throws Exception {
7+
String revision = "HEAD";
8+
9+
Process process = new ProcessBuilder(
10+
"git", "show", revision)
11+
.redirectErrorStream(true)
12+
.start();
13+
14+
try (var output = process.getInputStream()) {
15+
output.transferTo(OutputStream.nullOutputStream());
16+
}
17+
IO.println("exit code: " + process.waitFor());
18+
}

social/queue.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,4 @@ tooling/stack-walker
126126
collections/map-compute-and-merge
127127
io/http-websocket-client
128128
security/security-manager-migration
129+
tooling/runtime-exec-to-process-builder

social/tweets.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,4 +1277,14 @@ security/security-manager-migration: |-
12771277
12781278
🔗 https://javaevolved.github.io/security/security-manager-migration.html
12791279
1280+
#Java #JavaEvolved
1281+
tooling/runtime-exec-to-process-builder: |-
1282+
☕ Runtime.exec(String) to ProcessBuilder arguments
1283+
1284+
Launch processes with an explicit argument list and ProcessBuilder configuration.
1285+
1286+
Runtime.exec(String) → ProcessBuilder (JDK 5+)
1287+
1288+
🔗 https://javaevolved.github.io/tooling/runtime-exec-to-process-builder.html
1289+
12801290
#Java #JavaEvolved
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
title: "من Runtime.exec(String) إلى وسائط ProcessBuilder"
3+
oldApproach: "Runtime.exec(String)"
4+
modernApproach: "ProcessBuilder"
5+
summary: "شغّل العمليات بقائمة وسائط صريحة وبإعدادات ProcessBuilder."
6+
explanation: "تطبّق Runtime.exec(String) تقسيم سلسلة الأمر إلى رموز وفق قواعد جافا، وهو أمر يسهل إساءة فهمه عندما تحتوي الوسائط على مسافات أو علامات اقتباس. تقبل ProcessBuilder وسائط البرنامج كقيم منفصلة، وتُظهر بوضوح دليل العمل والبيئة وإعادة توجيه الإدخال والإخراج وسياسة تدفق الأخطاء. ولا تستدعي صدفة إلا إذا شغّلها التطبيق عمداً."
7+
whyModernWins:
8+
- icon: "🎯"
9+
title: "وسائط دقيقة"
10+
desc: "يبقى كل وسيط للعملية قيمة منفصلة دون تقسيم سلسلة الأمر إلى رموز."
11+
- icon: "🎛"
12+
title: "إعداد صريح"
13+
desc: "تُضبط البيئة والدليل وإعادة التوجيه ومعالجة الأخطاء معاً."
14+
- icon: "🛡"
15+
title: "حدود أكثر أماناً"
16+
desc: "يتجنّب بناء سلسلة أوامر شبيهة بالصدفة من قيم ديناميكية."
17+
support:
18+
description: "متاح على نطاق واسع منذ JDK 5 (سبتمبر 2004)"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
title: "Runtime.exec(String) থেকে ProcessBuilder আর্গুমেন্টে"
3+
oldApproach: "Runtime.exec(String)"
4+
modernApproach: "ProcessBuilder"
5+
summary: "স্পষ্ট আর্গুমেন্ট তালিকা ও ProcessBuilder কনফিগারেশন দিয়ে প্রসেস চালু করুন।"
6+
explanation: "Runtime.exec(String) জাভার কমান্ড-স্ট্রিং টোকেনাইজেশন প্রয়োগ করে, আর্গুমেন্টে স্পেস বা উদ্ধৃতি চিহ্ন থাকলে যা সহজেই ভুল বোঝা যায়। ProcessBuilder প্রোগ্রামের আর্গুমেন্টগুলোকে আলাদা মান হিসেবে নেয় এবং কার্যকরী ডিরেক্টরি, এনভায়রনমেন্ট, ইনপুট/আউটপুট রিডাইরেক্ট ও এরর-স্ট্রিম নীতি স্পষ্টভাবে প্রকাশ করে। অ্যাপ্লিকেশন ইচ্ছাকৃতভাবে শেল চালু না করলে এটি কোনো শেল ডাকে না।"
7+
whyModernWins:
8+
- icon: "🎯"
9+
title: "নির্ভুল আর্গুমেন্ট"
10+
desc: "কমান্ড-স্ট্রিং টোকেনাইজেশন ছাড়াই প্রতিটি প্রসেস আর্গুমেন্ট আলাদা মান হিসেবে থাকে।"
11+
- icon: "🎛"
12+
title: "স্পষ্ট কনফিগারেশন"
13+
desc: "এনভায়রনমেন্ট, ডিরেক্টরি, রিডাইরেক্ট ও এরর হ্যান্ডলিং একসঙ্গে কনফিগার করা যায়।"
14+
- icon: "🛡"
15+
title: "নিরাপদ সীমানা"
16+
desc: "ডায়নামিক মান দিয়ে শেল-সদৃশ কমান্ড স্ট্রিং তৈরি করা এড়ায়।"
17+
support:
18+
description: JDK 5 (সেপ্টেম্বর 2004) থেকে ব্যাপকভাবে উপলব্ধ
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
title: "Von Runtime.exec(String) zu ProcessBuilder-Argumenten"
3+
oldApproach: "Runtime.exec(String)"
4+
modernApproach: "ProcessBuilder"
5+
summary: "Starte Prozesse mit einer expliziten Argumentliste und ProcessBuilder-Konfiguration."
6+
explanation: "Runtime.exec(String) wendet die Tokenisierung von Java-Befehlszeichenketten an, die leicht missverstanden wird, wenn Argumente Leerzeichen oder Anführungszeichen enthalten. ProcessBuilder nimmt Programmargumente als eigenständige Werte entgegen und macht Arbeitsverzeichnis, Umgebung, Ein-/Ausgabeumleitungen sowie die Behandlung des Fehlerstroms explizit. Eine Shell wird nur gestartet, wenn die Anwendung dies ausdrücklich möchte."
7+
whyModernWins:
8+
- icon: "🎯"
9+
title: "Exakte Argumente"
10+
desc: "Jedes Prozessargument bleibt ein eigenständiger Wert ohne Tokenisierung der Befehlszeichenkette."
11+
- icon: "🎛"
12+
title: "Explizite Konfiguration"
13+
desc: "Umgebung, Verzeichnis, Umleitungen und Fehlerbehandlung werden gemeinsam konfiguriert."
14+
- icon: "🛡"
15+
title: "Sicherere Grenzen"
16+
desc: "Vermeidet den Aufbau einer shell-ähnlichen Befehlszeichenkette aus dynamischen Werten."
17+
support:
18+
description: "Weitgehend verfügbar seit JDK 5 (September 2004)"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
title: "De Runtime.exec(String) a argumentos de ProcessBuilder"
3+
oldApproach: "Runtime.exec(String)"
4+
modernApproach: "ProcessBuilder"
5+
summary: "Lanza procesos con una lista de argumentos explícita y la configuración de ProcessBuilder."
6+
explanation: "Runtime.exec(String) aplica la tokenización de cadenas de comando de Java, que es fácil de malinterpretar cuando los argumentos contienen espacios o comillas. ProcessBuilder acepta los argumentos del programa como valores distintos y expone de forma explícita el directorio de trabajo, el entorno, las redirecciones de entrada/salida y la política del flujo de error. No invoca un shell salvo que la aplicación lo lance deliberadamente."
7+
whyModernWins:
8+
- icon: "🎯"
9+
title: "Argumentos exactos"
10+
desc: "Cada argumento del proceso sigue siendo un valor distinto sin tokenización de la cadena de comando."
11+
- icon: "🎛"
12+
title: "Configuración explícita"
13+
desc: "El entorno, el directorio, las redirecciones y el manejo de errores se configuran en conjunto."
14+
- icon: "🛡"
15+
title: "Límites más seguros"
16+
desc: "Evita construir una cadena de comando similar a un shell a partir de valores dinámicos."
17+
support:
18+
description: "Ampliamente disponible desde JDK 5 (septiembre de 2004)"

0 commit comments

Comments
 (0)