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.

referencesframeworksJACKSON.md

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

Jackson Conversion Guide

When This Applies

Detected when imports match com.fasterxml.jackson.*.

Key Rules

  1. Annotation site targets:

    • @JsonProperty on a Java field → @field:JsonProperty in Kotlin.
    • @JsonProperty on a Java getter → @get:JsonProperty in Kotlin.
    • When converting to Kotlin properties, apply BOTH @field: and @get: targets to match Java's dual annotation on field + getter.
  2. @JsonCreator: Java's @JsonCreator static factory or constructor → Kotlin primary constructor. The @JsonCreator annotation is often unnecessary on Kotlin's primary constructor if using the Jackson Kotlin module, but preserve it for safety.

  3. @JsonIgnore: Preserve exactly. Use @get:JsonIgnore or @field:JsonIgnore depending on original target.

  4. @JsonDeserialize / @JsonSerialize: Preserve exactly with correct site targets.

  5. @JsonInclude: Preserve on class or property level.

  6. @JsonFormat: Preserve with @field:JsonFormat site target.

  7. Jackson Kotlin Module: Note that projects using Jackson with Kotlin should add jackson-module-kotlin for proper Kotlin support (data classes, default values, nullable types). This is NOT something to add during conversion — just note it if missing.

  8. Builder pattern with @JsonPOJOBuilder: Replace with primary constructor + @JsonCreator if converting to data class. Otherwise preserve.


Example 1: DTO with Various Jackson Annotations

Java Input

package com.acme.dto;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonFormat;

/**
 * Data transfer object for an order summary.
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public class OrderSummaryDto {

    @JsonProperty("order_id")
    private final String orderId;

    @JsonProperty("total_amount")
    private final double totalAmount;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    private final String createdDate;

    @JsonIgnore
    private String internalNote;

    public OrderSummaryDto(String orderId, double totalAmount, String createdDate) {
        this.orderId = orderId;
        this.totalAmount = totalAmount;
        this.createdDate = createdDate;
    }

    @JsonProperty("order_id")
    public String getOrderId() {
        return orderId;
    }

    @JsonProperty("total_amount")
    public double getTotalAmount() {
        return totalAmount;
    }

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    public String getCreatedDate() {
        return createdDate;
    }

    @JsonIgnore
    public String getInternalNote() {
        return internalNote;
    }

    public void setInternalNote(String internalNote) {
        this.internalNote = internalNote;
    }
}

Kotlin Output

package com.acme.dto

import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonFormat

/**
 * Data transfer object for an order summary.
 *
 * @property orderId unique identifier for the order, serialized as `"order_id"`
 * @property totalAmount total monetary amount, serialized as `"total_amount"`
 * @property createdDate date the order was created, formatted as `yyyy-MM-dd`
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
open class OrderSummaryDto(
    @field:JsonProperty("order_id")
    @get:JsonProperty("order_id")
    val orderId: String?,

    @field:JsonProperty("total_amount")
    @get:JsonProperty("total_amount")
    val totalAmount: Double,

    @field:JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    @get:JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    val createdDate: String?
) {
    @field:JsonIgnore
    @get:JsonIgnore
    var internalNote: String? = null
}

Key points:

  • @JsonInclude stays at class level — no site target needed.
  • @JsonProperty gets both @field: and @get: to match the Java field + getter annotations.
  • @JsonFormat also gets both @field: and @get: since Java had it on both.
  • @JsonIgnore gets both @field: and @get: to suppress serialization fully.

Example 2: Class with @JsonCreator Factory Method

Java Input

package com.acme.model;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
 * Immutable configuration entry deserialized from JSON.
 */
public class ConfigEntry {

    private final String key;
    private final String value;
    private final boolean enabled;

    @JsonCreator
    public static ConfigEntry create(
            @JsonProperty("key") String key,
            @JsonProperty("value") String value,
            @JsonProperty("enabled") boolean enabled) {
        return new ConfigEntry(key, value, enabled);
    }

    private ConfigEntry(String key, String value, boolean enabled) {
        this.key = key;
        this.value = value;
        this.enabled = enabled;
    }

    @JsonProperty("key")
    public String getKey() {
        return key;
    }

    @JsonProperty("value")
    public String getValue() {
        return value;
    }

    @JsonProperty("enabled")
    public boolean isEnabled() {
        return enabled;
    }
}

Kotlin Output

package com.acme.model

import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty

/**
 * Immutable configuration entry deserialized from JSON.
 *
 * @property key the configuration key
 * @property value the configuration value
 * @property enabled whether this entry is active
 */
data class ConfigEntry @JsonCreator constructor(
    @field:JsonProperty("key")
    @get:JsonProperty("key")
    val key: String?,

    @field:JsonProperty("value")
    @get:JsonProperty("value")
    val value: String?,

    @field:JsonProperty("enabled")
    @get:JsonProperty("enabled")
    val enabled: Boolean
) {
    companion object {
        /**
         * Factory method preserved for documentation; the primary constructor
         * with [JsonCreator] handles deserialization directly.
         */
        @JsonCreator
        @JvmStatic
        fun create(
            @JsonProperty("key") key: String?,
            @JsonProperty("value") value: String?,
            @JsonProperty("enabled") enabled: Boolean
        ): ConfigEntry = ConfigEntry(key, value, enabled)
    }
}

Key points:

  • The Java @JsonCreator static factory is converted to a Kotlin primary constructor with @JsonCreator. The companion object factory is preserved for backward compatibility but the primary constructor handles deserialization.
  • The class becomes a data class since it is immutable and value-oriented.
  • @JsonCreator is kept on the primary constructor for safety, ensuring Jackson can deserialize even without the Jackson Kotlin module.
  • String parameters remain nullable (String?) since Java strings are nullable by default and there is no @NonNull or Objects.requireNonNull evidence.

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.