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.

referencesframeworksLOMBOK.md

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

Lombok Conversion Guide

When This Applies

Detected when imports match lombok.*.

Core Rule

Remove ALL Lombok annotations entirely. Do not convert Lombok to Lombok — convert to idiomatic Kotlin equivalents. Lombok has no place in Kotlin code.

Annotation Conversion Table

Lombok Annotation Kotlin Equivalent
@Getter / @Setter Kotlin properties (val/var) — automatic
@Data data class with primary constructor properties
@Value (Lombok) data class with val properties (immutable)
@Builder Default parameter values, or named arguments. For complex builders, use Kotlin builder DSL
@NoArgsConstructor Secondary no-arg constructor, or default values for all params
@AllArgsConstructor Primary constructor (Kotlin default)
@RequiredArgsConstructor Primary constructor with only required (non-default) params
@ToString data class auto-generates toString, or manual override fun toString()
@EqualsAndHashCode data class auto-generates, or manual override fun equals/hashCode
@Slf4j / @Log / @Log4j2 Companion object with logger (see example below)
@Cleanup Kotlin's .use {} extension function
@SneakyThrows Kotlin has no checked exceptions — just remove it
@Synchronized Kotlin's @Synchronized annotation
@With data class .copy() method
@Accessors(chain = true) Kotlin's apply {} block

Key Rules

  1. @Slf4j — Convert to a companion object with an explicit logger:
companion object {
    private val log = LoggerFactory.getLogger(MyClass::class.java)
}
  1. @Data with JPA entities — Do NOT use data class for JPA entities. Use regular open class with properties instead. Data classes break Hibernate proxies.

  2. @Builder — Prefer default parameter values. Only create an explicit builder pattern if the Java code has complex builder logic beyond simple setters.

  3. Lombok val — Replace with Kotlin's val (they serve the same purpose).


Example 1: @Data Class with @Builder

Java Input

package com.acme.model;

import lombok.Builder;
import lombok.Data;

/**
 * Represents a customer order with shipping details.
 */
@Data
@Builder
public class Order {
    private String orderId;
    private String customerName;
    private int quantity;
    private boolean expedited;
}

Kotlin Output

package com.acme.model

/**
 * Represents a customer order with shipping details.
 */
data class Order(
    val orderId: String?,
    val customerName: String?,
    val quantity: Int = 0,
    val expedited: Boolean = false
)

What changed:

  • @Data → data class with primary constructor properties.
  • @Builder → default parameter values. Callers use named arguments: Order(orderId = "123", customerName = "Alice", quantity = 2).
  • All Lombok imports removed.
  • Fields become val properties (immutable by default; use var only if mutation is required by the original code).
  • Reference types are nullable (String?) because Java fields default to null unless proven otherwise.

Example 2: @Slf4j Annotated Service Class

Java Input

package com.acme.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * Service that processes incoming payment requests.
 */
@Slf4j
@RequiredArgsConstructor
public class PaymentService {

    private final PaymentGateway gateway;
    private final NotificationSender notifier;

    /**
     * Processes a payment for the given amount.
     *
     * @param amount the payment amount in cents
     * @return true if the payment succeeded
     */
    public boolean processPayment(long amount) {
        log.info("Processing payment of {} cents", amount);
        try {
            gateway.charge(amount);
            notifier.sendConfirmation(amount);
            log.info("Payment of {} cents succeeded", amount);
            return true;
        } catch (Exception e) {
            log.error("Payment failed for amount {}", amount, e);
            return false;
        }
    }
}

Kotlin Output

package com.acme.service

import org.slf4j.LoggerFactory

/**
 * Service that processes incoming payment requests.
 */
open class PaymentService(
    private val gateway: PaymentGateway,
    private val notifier: NotificationSender
) {

    companion object {
        private val log = LoggerFactory.getLogger(PaymentService::class.java)
    }

    /**
     * Processes a payment for the given amount.
     *
     * @param amount the payment amount in cents
     * @return true if the payment succeeded
     */
    fun processPayment(amount: Long): Boolean {
        log.info("Processing payment of {} cents", amount)
        return try {
            gateway.charge(amount)
            notifier.sendConfirmation(amount)
            log.info("Payment of {} cents succeeded", amount)
            true
        } catch (e: Exception) {
            log.error("Payment failed for amount {}", amount, e)
            false
        }
    }
}

What changed:

  • @Slf4j → companion object with LoggerFactory.getLogger(...).
  • @RequiredArgsConstructor → primary constructor with val parameters.
  • Lombok imports replaced with org.slf4j.LoggerFactory.
  • try/catch used as an expression (idiomatic Kotlin).
  • Class is open because Java classes are implicitly open.

Example 3: @Value (Lombok) Immutable Class

Java Input

package com.acme.config;

import lombok.Value;

/**
 * Immutable configuration for connecting to a database.
 */
@Value
public class DatabaseConfig {
    String host;
    int port;
    String databaseName;
    boolean useSsl;
}

Kotlin Output

package com.acme.config

/**
 * Immutable configuration for connecting to a database.
 */
data class DatabaseConfig(
    val host: String?,
    val port: Int,
    val databaseName: String?,
    val useSsl: Boolean
)

What changed:

  • @Value → data class with val properties (all immutable).
  • Lombok's @Value makes the class final, and Kotlin data class is also final by default — so the semantics match.
  • All Lombok imports removed.
  • Auto-generated equals(), hashCode(), toString(), and copy() come from data class for free.
  • Reference types are nullable (String?) since the original Java fields have no nullability annotations.

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.