Saltar a contenido

Java / Kotlin - Entorno de Desarrollo

Guía completa para configurar un entorno de desarrollo Java/Kotlin para backend que permita a Claude Code trabajar eficazmente.

Requisitos del Sistema

Componente Versión Mínima Recomendada
JDK 17 LTS 21 LTS
Maven 3.8 3.9+
Gradle 8.0 8.5+
Kotlin 1.9 2.0+
IntelliJ IDEA 2023.2+ Latest

Instalación del JDK

SDKMAN (Recomendado - Multiplataforma)

# Instalar SDKMAN
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"

# Verificar
sdk version

# Listar versiones disponibles
sdk list java

# Instalar Java 21 (Temurin/Eclipse Adoptium)
sdk install java 21.0.2-tem

# Instalar Java 17
sdk install java 17.0.10-tem

# Cambiar versión
sdk use java 21.0.2-tem
sdk default java 21.0.2-tem

# Instalar Kotlin
sdk install kotlin

# Instalar Gradle
sdk install gradle

# Instalar Maven
sdk install maven

Windows (Sin SDKMAN)

# Winget - Eclipse Temurin (recomendado)
winget install EclipseAdoptium.Temurin.21.JDK

# O Azul Zulu
winget install Azul.Zulu.21.JDK

# O Amazon Corretto
winget install Amazon.Corretto.21.JDK

# Verificar
java -version
javac -version

# Configurar JAVA_HOME (si es necesario)
$env:JAVA_HOME = "C:\Program Files\Eclipse Adoptium\jdk-21.0.2.13-hotspot"
[Environment]::SetEnvironmentVariable("JAVA_HOME", $env:JAVA_HOME, "User")

macOS

# Homebrew
brew install openjdk@21

# Crear symlink
sudo ln -sfn /opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-21.jdk

# Añadir a ~/.zshrc
export JAVA_HOME=$(/usr/libexec/java_home -v 21)
export PATH="$JAVA_HOME/bin:$PATH"

# Verificar
java -version

Linux

# Ubuntu/Debian
sudo apt install openjdk-21-jdk

# Fedora
sudo dnf install java-21-openjdk-devel

# Configurar alternativas
sudo update-alternatives --config java

# Verificar
java -version
echo $JAVA_HOME

Build Tools

Maven

# Instalar con SDKMAN
sdk install maven

# O Windows
winget install Apache.Maven

# O macOS
brew install maven

# Verificar
mvn -version

# Comandos comunes
mvn clean install              # Build completo
mvn compile                    # Solo compilar
mvn test                       # Ejecutar tests
mvn package                    # Crear JAR/WAR
mvn spring-boot:run           # Ejecutar Spring Boot
mvn dependency:tree           # Ver árbol de dependencias
mvn versions:display-dependency-updates  # Ver actualizaciones

Gradle

# Instalar con SDKMAN
sdk install gradle

# O Windows
winget install Gradle.Gradle

# O macOS
brew install gradle

# Verificar
gradle -version

# Comandos comunes
./gradlew build                # Build completo
./gradlew test                 # Tests
./gradlew bootRun             # Spring Boot
./gradlew dependencies        # Dependencias
./gradlew clean               # Limpiar
./gradlew tasks               # Listar tareas

# Wrapper (recomendado)
gradle wrapper                 # Genera gradlew
./gradlew wrapper --gradle-version 8.5

IDE

IntelliJ IDEA (Recomendado)

# Windows
winget install JetBrains.IntelliJIDEA.Ultimate
# O Community Edition
winget install JetBrains.IntelliJIDEA.Community

# macOS
brew install --cask intellij-idea
# O Community
brew install --cask intellij-idea-ce

# Plugins recomendados (desde Settings > Plugins):
# - Lombok
# - Spring Boot
# - Database Tools
# - Docker
# - Kubernetes
# - SonarLint
# - MapStruct Support

Visual Studio Code

# Extensiones
code --install-extension vscjava.vscode-java-pack
code --install-extension vmware.vscode-spring-boot
code --install-extension pivotal.vscode-spring-boot
code --install-extension gabrielbb.vscode-lombok
code --install-extension fwcd.kotlin
code --install-extension vscjava.vscode-gradle
code --install-extension ms-azuretools.vscode-docker

Frameworks Backend

Spring Boot (Recomendado)

# Spring Initializr CLI
sdk install springboot

# Crear proyecto
spring init --dependencies=web,data-jpa,postgresql,lombok,validation \
  --java-version=21 --type=maven-project myapp

# O usar start.spring.io
# https://start.spring.io/

# Estructura típica
myapp/
├── src/
   ├── main/
      ├── java/com/example/myapp/
         ├── MyappApplication.java
         ├── controller/
         ├── service/
         ├── repository/
         ├── model/
         ├── dto/
         └── config/
      └── resources/
          ├── application.yml
          └── db/migration/  # Flyway
   └── test/
├── pom.xml
└── mvnw

pom.xml esencial:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.2</version>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>myapp</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>21</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Quarkus (Cloud Native)

# CLI
sdk install quarkus

# Crear proyecto
quarkus create app com.example:myapp \
  --extension='resteasy-reactive,hibernate-orm-panache,jdbc-postgresql'

# Ejecutar en modo dev (hot reload)
quarkus dev

# Build nativo
quarkus build --native

Micronaut

# CLI
sdk install micronaut

# Crear proyecto
mn create-app com.example.myapp \
  --features=data-jdbc,postgres,lombok

Bases de Datos

Spring Data JPA + PostgreSQL

application.yml:

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/myapp
    username: postgres
    password: postgres
    driver-class-name: org.postgresql.Driver
  jpa:
    hibernate:
      ddl-auto: validate
    show-sql: true
    properties:
      hibernate:
        format_sql: true
        dialect: org.hibernate.dialect.PostgreSQLDialect

Flyway (Migraciones)

<!-- pom.xml -->
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
</dependency>
# application.yml
spring:
  flyway:
    enabled: true
    locations: classpath:db/migration
-- src/main/resources/db/migration/V1__create_users_table.sql
CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL UNIQUE,
    name VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
# Comandos Maven
mvn flyway:migrate
mvn flyway:info
mvn flyway:repair

Liquibase (Alternativa)

<dependency>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-core</artifactId>
</dependency>

Testing

JUnit 5 + Mockito

<!-- Incluido en spring-boot-starter-test -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
@SpringBootTest
class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void shouldCreateUser() {
        // Given
        User user = new User("test@email.com", "Test User");
        when(userRepository.save(any(User.class))).thenReturn(user);

        // When
        User result = userService.createUser(user);

        // Then
        assertThat(result.getEmail()).isEqualTo("test@email.com");
        verify(userRepository).save(any(User.class));
    }
}

Testcontainers (Tests de integración)

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>postgresql</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>junit-jupiter</artifactId>
    <scope>test</scope>
</dependency>
@SpringBootTest
@Testcontainers
class UserRepositoryIT {

    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16");

    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
        registry.add("spring.datasource.password", postgres::getPassword);
    }

    @Autowired
    private UserRepository userRepository;

    @Test
    void shouldSaveAndFindUser() {
        User user = userRepository.save(new User("test@email.com", "Test"));
        assertThat(userRepository.findById(user.getId())).isPresent();
    }
}

Kotlin

Configuración para Spring Boot

<!-- pom.xml -->
<properties>
    <kotlin.version>2.0.0</kotlin.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.jetbrains.kotlin</groupId>
        <artifactId>kotlin-stdlib</artifactId>
    </dependency>
    <dependency>
        <groupId>org.jetbrains.kotlin</groupId>
        <artifactId>kotlin-reflect</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.module</groupId>
        <artifactId>jackson-module-kotlin</artifactId>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-maven-plugin</artifactId>
            <configuration>
                <args>
                    <arg>-Xjsr305=strict</arg>
                </args>
                <compilerPlugins>
                    <plugin>spring</plugin>
                    <plugin>jpa</plugin>
                </compilerPlugins>
            </configuration>
        </plugin>
    </plugins>
</build>

Gradle con Kotlin DSL

// build.gradle.kts
plugins {
    id("org.springframework.boot") version "3.2.2"
    id("io.spring.dependency-management") version "1.1.4"
    kotlin("jvm") version "2.0.0"
    kotlin("plugin.spring") version "2.0.0"
    kotlin("plugin.jpa") version "2.0.0"
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    runtimeOnly("org.postgresql:postgresql")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}

Docker para Java

Dockerfile Multi-stage

# Build stage
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
COPY .mvn/ .mvn/
COPY mvnw pom.xml ./
RUN ./mvnw dependency:go-offline
COPY src ./src
RUN ./mvnw package -DskipTests

# Runtime stage
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app

# Crear usuario no-root
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring

COPY --from=builder /app/target/*.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

Docker Compose

version: '3.8'

services:
  api:
    build: .
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=docker
      - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/myapp
      - SPRING_DATASOURCE_USERNAME=postgres
      - SPRING_DATASOURCE_PASSWORD=postgres
    depends_on:
      - db

  db:
    image: postgres:16
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

Comandos que Claude Code Ejecutará

# Maven
mvn clean install
mvn compile
mvn test
mvn package
mvn spring-boot:run
mvn dependency:tree
mvn versions:display-dependency-updates

# Gradle
./gradlew build
./gradlew test
./gradlew bootRun
./gradlew dependencies
./gradlew clean

# Flyway
mvn flyway:migrate
mvn flyway:info
mvn flyway:clean

# Spring Boot
./mvnw spring-boot:run -Dspring-boot.run.profiles=dev
java -jar target/myapp.jar

# Quarkus
quarkus dev
quarkus build

# Docker
docker build -t myapp .
docker compose up -d

Verificación del Entorno

#!/bin/bash
# verify-java-env.sh

echo "=== Verificación Entorno Java ==="

echo -e "\n--- Java ---"
java -version
echo "JAVA_HOME: $JAVA_HOME"

echo -e "\n--- Maven ---"
mvn -version 2>/dev/null || echo "Maven no encontrado"

echo -e "\n--- Gradle ---"
gradle -version 2>/dev/null || echo "Gradle no encontrado"

echo -e "\n--- Kotlin ---"
kotlin -version 2>/dev/null || echo "Kotlin no encontrado"

echo -e "\n--- SDKMAN ---"
sdk version 2>/dev/null || echo "SDKMAN no instalado"

echo -e "\n--- Docker ---"
docker --version

echo -e "\n=== Verificación Completa ==="

Troubleshooting

JAVA_HOME no configurado

# Linux/macOS
export JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java))))

# macOS específico
export JAVA_HOME=$(/usr/libexec/java_home -v 21)

Maven out of memory

export MAVEN_OPTS="-Xmx2048m -XX:MaxPermSize=512m"

Gradle daemon issues

./gradlew --stop
./gradlew clean build --no-daemon

Recursos