Skip to content

Commit 699e6b3

Browse files
e5lclaude
andcommitted
Add Java-to-Kotlin conversion skill
Adds kotlin-tooling-java-to-kotlin skill that converts Java source files to idiomatic Kotlin using a 4-step conversion methodology with 5 invariants. Includes framework-aware guidance for 12 frameworks (Spring, Lombok, Hibernate, Jackson, Micronaut, Quarkus, Dagger/Hilt, RxJava, JUnit, Guice, Retrofit, Mockito), each in separate reference files loaded only when matching imports are detected. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 445594d commit 699e6b3

File tree

16 files changed

+3219
-0
lines changed

16 files changed

+3219
-0
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
---
2+
name: kotlin-tooling-java-to-kotlin
3+
description: >
4+
Use when converting Java source files to idiomatic Kotlin, when user mentions
5+
"java to kotlin", "j2k", "convert java", "migrate java to kotlin", or when
6+
working with .java files that need to become .kt files. Handles framework-aware
7+
conversion for Spring, Lombok, Hibernate, Jackson, Micronaut, Quarkus, Dagger/Hilt,
8+
RxJava, JUnit, Guice, Retrofit, and Mockito.
9+
license: Apache-2.0
10+
metadata:
11+
author: JetBrains
12+
version: "1.0.0"
13+
---
14+
15+
# Java to Kotlin Conversion
16+
17+
Convert Java source files to idiomatic Kotlin using a disciplined 4-step conversion
18+
methodology with 5 invariants checked at each step. Supports framework-aware conversion
19+
that handles annotation site targets, library idioms, and API preservation.
20+
21+
## Workflow
22+
23+
```dot
24+
digraph j2k_workflow {
25+
rankdir=TB;
26+
"User specifies files" -> "Step 0: Scan & Detect";
27+
"Step 0: Scan & Detect" -> "Load framework guides";
28+
"Load framework guides" -> "Step 1: Convert";
29+
"Step 1: Convert" -> "Step 2: Write .kt";
30+
"Step 2: Write .kt" -> "Step 3: Git rename";
31+
"Step 3: Git rename" -> "Step 4: Verify";
32+
"Step 4: Verify" -> "Next file?" [label="pass"];
33+
"Step 4: Verify" -> "Fix issues" [label="fail"];
34+
"Fix issues" -> "Step 1: Convert";
35+
"Next file?" -> "Step 0: Scan & Detect" [label="batch: yes"];
36+
"Next file?" -> "Done" [label="no more files"];
37+
}
38+
```
39+
40+
## Step 0: Scan & Detect Frameworks
41+
42+
Before converting, scan the Java file's import statements to detect which frameworks
43+
are in use. Load ONLY the matching framework reference files to keep context focused.
44+
45+
### Framework Detection Table
46+
47+
| Import prefix | Framework guide |
48+
|---|---|
49+
| `org.springframework.*` | [SPRING.md](references/frameworks/SPRING.md) |
50+
| `lombok.*` | [LOMBOK.md](references/frameworks/LOMBOK.md) |
51+
| `javax.persistence.*`, `jakarta.persistence.*`, `org.hibernate.*` | [HIBERNATE.md](references/frameworks/HIBERNATE.md) |
52+
| `com.fasterxml.jackson.*` | [JACKSON.md](references/frameworks/JACKSON.md) |
53+
| `io.micronaut.*` | [MICRONAUT.md](references/frameworks/MICRONAUT.md) |
54+
| `io.quarkus.*`, `javax.enterprise.*`, `jakarta.enterprise.*` | [QUARKUS.md](references/frameworks/QUARKUS.md) |
55+
| `dagger.*`, `dagger.hilt.*` | [DAGGER-HILT.md](references/frameworks/DAGGER-HILT.md) |
56+
| `io.reactivex.*`, `rx.*` | [RXJAVA.md](references/frameworks/RXJAVA.md) |
57+
| `org.junit.*`, `org.testng.*` | [JUNIT.md](references/frameworks/JUNIT.md) |
58+
| `com.google.inject.*` | [GUICE.md](references/frameworks/GUICE.md) |
59+
| `retrofit2.*`, `okhttp3.*` | [RETROFIT.md](references/frameworks/RETROFIT.md) |
60+
| `org.mockito.*` | [MOCKITO.md](references/frameworks/MOCKITO.md) |
61+
62+
If `javax.inject.*` is detected, check for Dagger/Hilt vs Guice by looking for other
63+
imports from those frameworks. If ambiguous, load both guides.
64+
65+
## Step 1: Convert
66+
67+
Apply the conversion methodology from [CONVERSION-METHODOLOGY.md](references/CONVERSION-METHODOLOGY.md).
68+
69+
This is a 4-step chain-of-thought process:
70+
1. **Faithful 1:1 translation** — exact semantics preserved
71+
2. **Nullability & mutability audit** — val/var, nullable types
72+
3. **Collection type conversion** — Java mutable → Kotlin types
73+
4. **Idiomatic transformations** — properties, string templates, lambdas
74+
75+
Five invariants are checked after each step. If any invariant is violated, revert
76+
to the previous step and redo.
77+
78+
Apply any loaded framework-specific guidance during step 4 (idiomatic transformations).
79+
80+
## Step 2: Write Output
81+
82+
Write the converted Kotlin code to a `.kt` file with the same name as the original
83+
Java file, in the same directory.
84+
85+
## Step 3: Preserve Git History
86+
87+
To preserve `git blame` history, use a two-phase approach:
88+
89+
```bash
90+
# Phase 1: Rename (creates rename tracking)
91+
git mv src/main/java/com/example/Foo.java src/main/kotlin/com/example/Foo.kt
92+
git commit -m "Rename Foo.java to Foo.kt"
93+
94+
# Phase 2: Replace content (tracked as modification, not new file)
95+
# Write the converted Kotlin content to Foo.kt
96+
git commit -m "Convert Foo from Java to Kotlin"
97+
```
98+
99+
If the project keeps Java and Kotlin in the same source root (e.g., `src/main/java/`),
100+
rename in place:
101+
102+
```bash
103+
git mv src/main/java/com/example/Foo.java src/main/java/com/example/Foo.kt
104+
```
105+
106+
If the project does not use Git, simply write the `.kt` file and delete the `.java` file.
107+
108+
## Step 4: Verify
109+
110+
After conversion, verify using [checklist.md](assets/checklist.md):
111+
- Attempt to compile the converted file
112+
- Run existing tests
113+
- Check annotation site targets
114+
- Confirm no behavioral changes
115+
116+
## Batch Conversion
117+
118+
When converting multiple files (a directory or package):
119+
120+
1. **List all `.java` files** in the target scope
121+
2. **Sort by dependency order** — convert leaf dependencies first (files that don't
122+
import other files in the conversion set), then work up to files that depend on them
123+
3. **Convert one file at a time** — apply the full workflow (steps 0-4) for each
124+
4. **Track progress** — report which files are done, which remain
125+
5. **Handle cross-references** — after converting a file, update imports in other Java
126+
files if needed (e.g., if a class moved packages)
127+
128+
For large batches, consider converting in packages (bottom-up from leaf packages).
129+
130+
## Common Pitfalls
131+
132+
See [KNOWN-ISSUES.md](references/KNOWN-ISSUES.md) for:
133+
- Kotlin keyword conflicts (`when`, `in`, `is`, `object`)
134+
- SAM conversion ambiguity
135+
- Platform types from Java interop
136+
- `@JvmStatic` / `@JvmField` / `@JvmOverloads` usage
137+
- Checked exceptions and `@Throws`
138+
- Wildcard generics → Kotlin variance
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Post-Conversion Verification Checklist
2+
3+
Use this checklist after converting each Java file to Kotlin.
4+
5+
## Compilation & Tests
6+
- [ ] The `.kt` file compiles without errors
7+
- [ ] All existing tests still pass
8+
- [ ] No new compiler warnings introduced
9+
10+
## Semantic Correctness
11+
- [ ] No new side-effects or behavioural changes
12+
- [ ] All public API signatures preserved (method names, parameter types, return types)
13+
- [ ] Exception behaviour unchanged (same exceptions thrown in same conditions)
14+
15+
## Annotations
16+
- [ ] All annotations preserved from the original Java code
17+
- [ ] Annotation site targets correct (`@field:`, `@get:`, `@set:`, `@param:`)
18+
- [ ] No annotations accidentally dropped during conversion
19+
20+
## Imports & Package
21+
- [ ] Package declaration matches original
22+
- [ ] All imports carried forward (except Java types that shadow Kotlin builtins)
23+
- [ ] No new imports added unnecessarily
24+
25+
## Documentation
26+
- [ ] All Javadoc converted to KDoc format
27+
- [ ] `{@code ...}` → backtick code in KDoc
28+
- [ ] `{@link ...}``[...]` KDoc links
29+
- [ ] `<p>` paragraph tags → blank lines
30+
- [ ] `@param`, `@return`, `@throws` tags preserved
31+
- [ ] Class-level and method-level documentation preserved
32+
33+
## Nullability & Mutability
34+
- [ ] Non-null types used only where provably non-null
35+
- [ ] Nullable types (`?`) used for all Java types that could be null
36+
- [ ] `val` used for all immutable variables/properties
37+
- [ ] `var` used only for mutable variables/properties
38+
39+
## Collections
40+
- [ ] `MutableList`/`MutableSet`/`MutableMap` for Java's mutable collections
41+
- [ ] `List`/`Set`/`Map` only where Java used immutable wrappers
42+
43+
## Kotlin Idioms
44+
- [ ] Getters/setters replaced with Kotlin properties where appropriate
45+
- [ ] String concatenation replaced with string templates where clearer
46+
- [ ] Elvis operator used where appropriate
47+
- [ ] `when` expression used instead of `switch`
48+
- [ ] Smart casts used after `is` checks (no explicit casts)
49+
50+
## Framework-Specific (check applicable items)
51+
- [ ] **Spring**: Classes that need proxying are `open`; `@Bean` methods are `open`
52+
- [ ] **Lombok**: All Lombok annotations removed; replaced with Kotlin equivalents
53+
- [ ] **Hibernate/JPA**: Entities are `open` (not data classes); no-arg constructor provided
54+
- [ ] **Jackson**: `@field:` and `@get:` annotation site targets correct
55+
- [ ] **RxJava**: Reactive types correctly mapped to Coroutines/Flow
56+
- [ ] **Mockito**: `when` keyword escaped or replaced with MockK equivalent
57+
58+
## Git History
59+
- [ ] File renamed via `git mv` (not delete + create)
60+
- [ ] Rename commit separate from content change commit

0 commit comments

Comments
 (0)