Skip to content

Commit c9e99a8

Browse files
authored
Merge pull request #220 from javaevolved/brunoborges-remove-python-java-detection
Replace Python Java detector with Java 8 executable JAR
2 parents 178e444 + 1a600b3 commit c9e99a8

15 files changed

Lines changed: 826 additions & 489 deletions

.github/workflows/release-agent-plugin.yml

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ jobs:
3535
with:
3636
fetch-depth: 0
3737

38+
- uses: actions/setup-java@v6
39+
with:
40+
distribution: zulu
41+
java-version: '8.0.492+9'
42+
3843
- name: Determine release version
3944
id: version
4045
env:
@@ -101,9 +106,27 @@ jobs:
101106
- name: Validate plugin
102107
working-directory: agent-plugins/modern-java-development
103108
run: |
104-
python3 -m unittest \
105-
skills/modern-java/scripts/test_detect_java_version.py \
106-
skills/modern-java/scripts/test_reference_coverage.py
109+
classes=$(mktemp -d)
110+
trap 'rm -rf "$classes"' EXIT
111+
mkdir "$classes/source" "$classes/shipped" "$classes/tests"
112+
javac -source 8 -target 8 -Xlint:-options \
113+
-d "$classes/source" \
114+
skills/modern-java/scripts/DetectJavaVersion.java
115+
(
116+
cd "$classes/shipped"
117+
jar xf "$GITHUB_WORKSPACE/agent-plugins/modern-java-development/skills/modern-java/scripts/detect-java-version.jar"
118+
)
119+
rm -rf "$classes/shipped/META-INF"
120+
diff --recursive "$classes/source" "$classes/shipped"
121+
javac -source 8 -target 8 -Xlint:-options \
122+
-cp skills/modern-java/scripts/detect-java-version.jar \
123+
-d "$classes/tests" \
124+
skills/modern-java/scripts/PluginValidationTest.java
125+
java -cp "$classes/tests:skills/modern-java/scripts/detect-java-version.jar" \
126+
PluginValidationTest ../..
127+
javap -verbose \
128+
-classpath skills/modern-java/scripts/detect-java-version.jar \
129+
DetectJavaVersion | grep --quiet 'major version: 52'
107130
jq --exit-status \
108131
--arg version "${{ steps.version.outputs.version }}" \
109132
'.version == $version' plugin.json >/dev/null

agent-plugins/modern-java-development/README.md

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ modern-java-development/
2121
│ ├── enterprise-practices.md
2222
│ └── release-practices.md
2323
└── scripts/
24-
├── detect_java_version.py
25-
├── test_reference_coverage.py
26-
└── test_detect_java_version.py
24+
├── DetectJavaVersion.java
25+
├── PluginValidationTest.java
26+
├── detect-java-version.cmd
27+
├── detect-java-version.jar
28+
└── detect-java-version.sh
2729
```
2830

2931
## Install
@@ -91,14 +93,22 @@ Agent Plugins manifest.
9193

9294
When the skill is active, the agent runs the detector from the Java project root:
9395

94-
```bash
95-
python3 skills/modern-java/scripts/detect_java_version.py .
96+
```console
97+
# macOS and Linux
98+
skills/modern-java/scripts/detect-java-version.sh .
99+
100+
# Windows
101+
skills\modern-java\scripts\detect-java-version.cmd .
96102
```
97103

98104
Pass an explicit target when build metadata is unavailable:
99105

100-
```bash
101-
python3 skills/modern-java/scripts/detect_java_version.py . --java-version 21
106+
```console
107+
# macOS and Linux
108+
skills/modern-java/scripts/detect-java-version.sh . --java-version 21
109+
110+
# Windows
111+
skills\modern-java\scripts\detect-java-version.cmd . --java-version 21
102112
```
103113

104114
The detector emits JSON so an agent can distinguish the selected target from
@@ -107,9 +117,24 @@ lower-confidence runtime evidence and report conflicting build configuration.
107117
## Validate
108118

109119
```bash
110-
python3 -m unittest \
111-
skills/modern-java/scripts/test_detect_java_version.py \
112-
skills/modern-java/scripts/test_reference_coverage.py
120+
set -e
121+
classes=$(mktemp -d)
122+
trap 'rm -rf "$classes"' EXIT
123+
jarfile="$PWD/skills/modern-java/scripts/detect-java-version.jar"
124+
mkdir "$classes/source" "$classes/shipped" "$classes/tests"
125+
javac -source 8 -target 8 -Xlint:-options \
126+
-d "$classes/source" skills/modern-java/scripts/DetectJavaVersion.java
127+
(
128+
cd "$classes/shipped"
129+
jar xf "$jarfile"
130+
)
131+
rm -rf "$classes/shipped/META-INF"
132+
diff -r "$classes/source" "$classes/shipped"
133+
javac -source 8 -target 8 -Xlint:-options \
134+
-cp "$jarfile" \
135+
-d "$classes/tests" skills/modern-java/scripts/PluginValidationTest.java
136+
java -cp "$classes/tests:$jarfile" \
137+
PluginValidationTest ../..
113138
```
114139

115140
## Release

agent-plugins/modern-java-development/skills/modern-java/SKILL.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name: modern-java
33
description: Detects a project's effective Java version and provides release-appropriate guidance for writing, reviewing, refactoring, upgrading, and modernizing Java code. Use for Java implementation, architecture, code review, build configuration, migration, performance, concurrency, testing, or API design tasks.
44
license: MIT
5-
compatibility: Requires Python 3 to run the bundled detector; an agent may inspect the same project files directly when Python is unavailable.
5+
compatibility: Requires a Java 8 or newer runtime to run the bundled detector.
66
metadata:
77
author: "@brunoborges"
88
version: "1.0.0"
@@ -18,8 +18,16 @@ features or APIs the build accepts.
1818

1919
1. From the project or module root, run:
2020

21+
On macOS or Linux:
22+
2123
```bash
22-
python3 <skill-directory>/scripts/detect_java_version.py .
24+
<skill-directory>/scripts/detect-java-version.sh .
25+
```
26+
27+
On Windows:
28+
29+
```bat
30+
<skill-directory>\scripts\detect-java-version.cmd .
2331
```
2432

2533
If the user explicitly supplied Java version X, pass

agent-plugins/modern-java-development/skills/modern-java/references/core-practices.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,12 @@ syntax available at the detected compilation target.
4949
cancellation, timeout, interruption, and failure propagation behavior.
5050
- Preserve interruption (`Thread.currentThread().interrupt()`) when an
5151
`InterruptedException` cannot be propagated.
52+
- Replace unsafe forced thread termination with cooperative cancellation and
53+
explicit lifecycle ownership.
54+
<!-- covers: thread-stop-to-cooperative-cancellation -->
5255
- Use concurrent collections and high-level synchronization utilities before
5356
hand-written locking. Document invariants protected by locks.
57+
<!-- covers: wait-notify-to-blocking-queue -->
5458
- Measure before selecting executors, pool sizes, lock-free structures, or
5559
virtual-thread migration. CPU-bound and I/O-bound workloads need different
5660
strategies.

agent-plugins/modern-java-development/skills/modern-java/references/enterprise-practices.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ configuration before recommending a migration.
8888
explicit `@Configuration` over large XML bean graphs in modern Spring.
8989
Preserve XML where externalized wiring or legacy integration makes it useful;
9090
do not rely on broad component scanning that obscures ownership.
91-
<!-- covers: spring-xml-config-vs-annotations -->
91+
<!-- covers: spring-xml-config-vs-annotations spring-boot-mvc-config -->
9292
- On Spring Framework 7, use native API version conditions when they match the
9393
public versioning strategy. Keep version negotiation centralized, document
9494
deprecation and compatibility policy, and avoid merging unrelated versions

agent-plugins/modern-java-development/skills/modern-java/references/release-practices.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ on the exact runtime and module graph.
77

88
## Java 7 and older maintenance targets
99

10+
- Use generics instead of raw collections, `Deque` instead of legacy `Stack`,
11+
and unsynchronized collections unless synchronization is part of the contract.
12+
<!-- covers: raw-collections-to-generics stack-to-deque legacy-synchronized-collections -->
13+
- Use `ProcessBuilder` instead of `Runtime.exec`, construct URLs through `URI`,
14+
and specify charsets explicitly at text/byte boundaries.
15+
<!-- covers: runtime-exec-to-process-builder url-constructors-to-uri explicit-charset-file-io -->
1016
- Use multi-catch when handlers have identical behavior and neither alternative
1117
needs a more specific type. Preserve separate catches when recovery differs.
1218
<!-- covers: multi-catch -->
@@ -19,7 +25,11 @@ on the exact runtime and module graph.
1925
- Use lambdas and method references when they clarify behavior, and streams for
2026
side-effect-free transformations and reductions. Use
2127
`stream.toArray(Type[]::new)` when a typed array is the required API boundary.
22-
<!-- covers: stream-toarray-typed -->
28+
<!-- covers: anonymous-classes-to-lambdas stream-toarray-typed -->
29+
- Prefer collection bulk operations, `Map.compute`/`merge`, comparator factories,
30+
and the standard Base64 codecs over hand-written equivalents when their
31+
contracts match the required behavior.
32+
<!-- covers: collection-bulk-operations map-compute-and-merge comparator-factories standard-base64 -->
2333
- Use `java.time`, `DateTimeFormatter`, `Duration`, and `Period` instead of
2434
mutable `Date`, `Calendar`, `SimpleDateFormat`, or unitless millisecond math.
2535
<!-- covers: java-time-basics date-formatting duration-and-period -->
@@ -51,7 +61,11 @@ on the exact runtime and module graph.
5161
<!-- covers: inputstream-transferto try-with-resources-effectively-final -->
5262
- Use `ProcessBuilder` to start processes and `ProcessHandle` to inspect or
5363
manage them. Drain output, bound waits, and handle process-tree termination.
54-
<!-- covers: process-api -->
64+
<!-- covers: process-api runtime-exec-to-process-builder -->
65+
- Use `StackWalker` for controlled stack inspection, `Cleaner` or explicit
66+
resource ownership instead of finalization, and
67+
`getDeclaredConstructor().newInstance()` instead of `Class.newInstance()`.
68+
<!-- covers: stack-walker finalizers-to-resource-cleanup class-newinstance-to-constructor -->
5569
- Preserve nanosecond `Instant` precision through storage and serialization;
5670
do not silently truncate to epoch milliseconds.
5771
<!-- covers: instant-precision -->
@@ -89,7 +103,7 @@ on the exact runtime and module graph.
89103
- Prefer `java.net.http.HttpClient` for JDK-native HTTP. Reuse clients, configure
90104
connect/request timeouts, handle interruption, and validate status and body
91105
limits.
92-
<!-- covers: http-client -->
106+
<!-- covers: http-client http-websocket-client -->
93107
- Use `String.isBlank`, `strip`, `lines`, and `repeat` instead of hand-written
94108
equivalents. `strip` is Unicode-aware; `lines` recognizes multiple line
95109
terminators and does not retain them.
@@ -177,6 +191,9 @@ on the exact runtime and module graph.
177191
<!-- covers: junit6-with-jspecify -->
178192
- Treat strong encapsulation of JDK internals as a migration requirement, not
179193
something to bypass permanently with `--add-opens`.
194+
- Plan migrations away from the deprecated Security Manager around explicit
195+
process, container, module, and application security boundaries.
196+
<!-- covers: security-manager-migration -->
180197

181198
## Java 18-20
182199

@@ -189,6 +206,9 @@ on the exact runtime and module graph.
189206
- Use try-with-resources for locally owned `ExecutorService` lifetimes. Define
190207
cancellation, graceful shutdown, timeout, and forced-shutdown behavior.
191208
<!-- covers: executor-try-with-resources -->
209+
- Use `Locale.of` instead of deprecated locale constructors, while preserving
210+
language, region, variant, and BCP 47 semantics.
211+
<!-- covers: locale-of -->
192212
- Record patterns, pattern switch, and virtual threads are not final before Java
193213
21.
194214

@@ -245,6 +265,10 @@ on the exact runtime and module graph.
245265

246266
## Java 24
247267

268+
- Use the Class-File API for class-file parsing, generation, and transformation
269+
when its typed model fits; preserve unknown attributes and verify emitted
270+
bytecode when interoperability matters.
271+
<!-- covers: class-file-api -->
248272
- Use stream gatherers for reusable stateful intermediate operations when
249273
standard operations cannot express the transformation clearly. Respect
250274
integrator state, short-circuiting, parallel-combiner, and finisher semantics.

0 commit comments

Comments
 (0)