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>
-- 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
);
Liquibase (Alternativa)¶
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)