All skills
kotlin avatar

/kotlin-tooling-java-to-kotlin

@8fc58af official
by kotlinkotlin/kotlin-agent-skills1.1k stars
42

Use when converting Java source files to idiomatic Kotlin, when user mentions "java to kotlin", "j2k", "convert java", "migrate java to kotlin", or when working with .java files that need to become .kt files. Handles framework-aware conversion for Spring, Lombok, Hibernate, Jackson, Micronaut, Quarkus, Dagger/Hilt, RxJava, JUnit, Guice, Retrofit, and Mockito.

Use this Skill: https://skilld.dev/gh/kotlin/kotlin-agent-skills/kotlin-tooling-java-to-kotlin

This session only. Nothing lands on disk.

referencesframeworksGUICE.md

≈1.1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Guice Conversion Guide

When This Applies

This guide applies when the Java source contains imports matching com.google.inject.*. This covers Google Guice core, Guice multibindings, and Guice servlet.

Key Rules

1. @Inject constructor syntax

Kotlin places @Inject before the constructor keyword in the primary constructor:

class Foo @Inject constructor(private val bar: Bar)

2. @Provides methods in Modules

Keep @Provides methods as regular functions. Guice modules extend AbstractModule, so override configure() as usual.

3. Module.configure() override

Override configure() in Kotlin. Use Guice's binding DSL with Kotlin class references:

bind(Foo::class.java).to(FooImpl::class.java)

4. @Named qualifier — annotation site targets

In Kotlin, @Named on constructor parameters needs a site target to reach the parameter (not the field or property). Use @param:Named for constructor injection:

class Foo @Inject constructor(
    @param:Named("primary") private val dataSource: DataSource
)

When used on function parameters (e.g., in @Provides methods), no site target is needed.

5. @Singleton scope

Preserve @Singleton exactly. It can be placed on the class declaration or in module bindings via .in(Singleton::class.java).

6. Provider<T>

Provider<T> can stay as-is for lazy or scoped injection. Where the only purpose is deferred initialization, Kotlin's lazy delegation can be used as an alternative outside of Guice-managed contexts.


Examples

Example 1: Guice Module with Bindings and an Injected Class

Java:

package com.acme.config;

import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.google.inject.name.Named;

public class AppModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(CacheService.class).to(RedisCacheService.class);
        bind(NotificationService.class).to(EmailNotificationService.class).in(Singleton.class);
    }

    @Provides
    @Singleton
    public HttpClient provideHttpClient(@Named("baseUrl") String baseUrl) {
        return new HttpClient(baseUrl);
    }
}
package com.acme.service;

import com.google.inject.Inject;
import com.google.inject.name.Named;

public class OrderService {

    private final CacheService cacheService;
    private final HttpClient httpClient;
    private final String region;

    @Inject
    public OrderService(CacheService cacheService, HttpClient httpClient, @Named("region") String region) {
        this.cacheService = cacheService;
        this.httpClient = httpClient;
        this.region = region;
    }

    public Order findById(Long id) {
        return cacheService.getOrFetch(id, () -> httpClient.get("/orders/" + id, Order.class));
    }
}

Kotlin:

package com.acme.config

import com.google.inject.AbstractModule
import com.google.inject.Provides
import com.google.inject.Singleton
import com.google.inject.name.Named

class AppModule : AbstractModule() {

    override fun configure() {
        bind(CacheService::class.java).to(RedisCacheService::class.java)
        bind(NotificationService::class.java).to(EmailNotificationService::class.java).`in`(Singleton::class.java)
    }

    @Provides
    @Singleton
    fun provideHttpClient(@Named("baseUrl") baseUrl: String): HttpClient {
        return HttpClient(baseUrl)
    }
}
package com.acme.service

import com.google.inject.Inject
import com.google.inject.name.Named

class OrderService @Inject constructor(
    private val cacheService: CacheService,
    private val httpClient: HttpClient,
    @param:Named("region") private val region: String
) {

    fun findById(id: Long): Order? {
        return cacheService.getOrFetch(id) { httpClient.get("/orders/$id", Order::class.java) }
    }
}

Key changes:

  • @Inject moves before the constructor keyword in the primary constructor.
  • Constructor parameters become private val in the primary constructor.
  • @Named("region") uses @param:Named site target so the annotation reaches the constructor parameter rather than the Kotlin property.
  • .in(Singleton.class) becomes .`in`(Singleton::class.java) — in is a reserved keyword in Kotlin and must be escaped with backticks.
  • The lambda in getOrFetch uses Kotlin's trailing lambda syntax instead of an anonymous inner class.
  • String concatenation "/orders/" + id becomes a string template "/orders/$id".

Source: SKILL.md on GitHub

No alerts16d4 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill provides a methodology for converting Java source code to Kotlin. While the logic is sound and focused on development tasks, it possesses an indirect prompt injection surface by processing untrusted source code and performing file system operations.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 8fc58af. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 3 weeks ago.

Activeupdated 7 months ago
metadata
{
  "author": "JetBrains",
  "version": "1.0.0"
}
  • kotlin
  • java
  • migration
  • spring
  • hibernate
  • jackson
  • junit
  • rxjava
  • retrofit
  • mockito
  • conversion

README badge

README badge for kotlin/kotlin-agent-skills/kotlin-tooling-java-to-kotlin

Converts Java source files to idiomatic Kotlin using a structured 4-step methodology with framework-aware handling for Spring, Lombok, Hibernate, Jackson, Micronaut, Quarkus, Dagger/Hilt, RxJava, JUnit, Guice, Retrofit, and Mockito. Preserves git history through two-phase renames and supports batch conversion with dependency ordering.

Generated from the current SKILL.md.

What frameworks does this skill handle?
Spring, Lombok, Hibernate, Jackson, Micronaut, Quarkus, Dagger/Hilt, RxJava, JUnit, Guice, Retrofit, and Mockito. The skill detects which frameworks are in use by scanning import statements and loads only the relevant framework guides.
Does this skill preserve git blame history?
Yes. It uses a two-phase approach: first rename the file with `git mv`, then replace the content in a separate commit so the rename is tracked separately from the conversion changes.
Can this skill convert multiple Java files at once?
Yes. For batch conversions, it sorts files by dependency order (leaf files first), converts one at a time through the full workflow, and updates cross-references as needed.
What happens if conversion fails the verification step?
The skill reverts to the previous conversion step and retries. It checks five invariants at each step and verifies output by compilation, tests, and annotation site targets.
Does this handle Java interop edge cases like platform types and checked exceptions?
Yes. The skill documents and handles Kotlin keyword conflicts, SAM conversion ambiguity, platform types, @JvmStatic/@JvmField/@JvmOverloads, checked exceptions, and wildcard generics in a separate known-issues reference.

Generated from the current SKILL.md. These answers refresh after source changes.