Agent skill
Java
Execute these commands after EVERY implementation (see AGENT_AUTOMATION module for full workflow).
Install this agent skill to your Project
npx add-skill https://github.com/hivellm/rulebook/tree/main/templates/skills/languages/java
SKILL.md
Java Project Rules
Agent Automation Commands
CRITICAL: Execute these commands after EVERY implementation (see AGENT_AUTOMATION module for full workflow).
# Maven projects:
mvn spotless:check # Format check
mvn checkstyle:check # Linting
mvn test # All tests (100% pass)
mvn package -DskipTests # Build
mvn jacoco:check # Coverage (95%+ required)
# Security audit:
mvn dependency:analyze # Dependency check
mvn versions:display-dependency-updates # Outdated deps
# Gradle projects:
./gradlew spotlessCheck # Format check
./gradlew checkstyleMain # Linting
./gradlew test # All tests
./gradlew build -x test # Build
./gradlew jacocoTestCoverageVerification # Coverage
Java Version
CRITICAL: Use Java 17 LTS or Java 21 LTS for modern features and long-term support.
- Minimum Version: Java 17 LTS
- Recommended: Java 21 LTS
- Build Tool: Maven or Gradle
Formatting
- Use Spotless or Google Java Format
- Consistent formatting across entire project
- Format before committing
Maven configuration (pom.xml):
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>2.40.0</version>
<configuration>
<java>
<googleJavaFormat>
<version>1.17.0</version>
<style>GOOGLE</style>
</googleJavaFormat>
</java>
</configuration>
</plugin>
Gradle configuration (build.gradle):
plugins {
id 'com.diffplug.spotless' version '6.23.0'
}
spotless {
java {
googleJavaFormat('1.17.0').aosp()
}
}
Linting
- Use Checkstyle for style checks
- Use PMD for code quality
- Use SpotBugs for bug detection
- Configure in
checkstyle.xml,pmd.xml
Testing
- Framework: JUnit 5 (JUnit Jupiter)
- Location:
src/test/java - Coverage: Must meet project threshold (default 95%)
- Assertions: Use AssertJ or JUnit assertions
- Mocking: Use Mockito when needed
Example test structure:
package com.example.myapp;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import static org.assertj.core.api.Assertions.*;
class UserServiceTest {
private UserService userService;
@BeforeEach
void setUp() {
userService = new UserService();
}
@Test
@DisplayName("Should create user with valid data")
void shouldCreateUserWithValidData() {
// Given
UserInput input = new UserInput("test@example.com", "password");
// When
User user = userService.createUser(input);
// Then
assertThat(user).isNotNull();
assertThat(user.getEmail()).isEqualTo("test@example.com");
}
@Test
@DisplayName("Should throw exception for invalid email")
void shouldThrowExceptionForInvalidEmail() {
// Given
UserInput input = new UserInput("invalid", "password");
// When/Then
assertThatThrownBy(() -> userService.createUser(input))
.isInstanceOf(ValidationException.class)
.hasMessageContaining("Invalid email");
}
}
Dependency Management
CRITICAL: Use Maven or Gradle with dependency management.
Maven (pom.xml)
<properties>
<java.version>21</java.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.1</version>
<scope>test</scope>
</dependency>
</dependencies>
Gradle (build.gradle)
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
}
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1'
testImplementation 'org.assertj:assertj-core:3.24.2'
}
test {
useJUnitPlatform()
}
Dependency Guidelines
-
Check for latest versions:
- Use Context7 MCP tool if available
- Check Maven Central for latest releases
- Review changelog for breaking changes
-
Version Management:
- ✅ Use BOM (Bill of Materials) for version consistency
- ✅ Keep dependencies updated regularly
- ✅ Use dependency management in parent POM
- ❌ Don't use SNAPSHOT in production
- ❌ Don't use vulnerable dependencies
Error Handling
- Use exceptions for exceptional cases only
- Create custom exceptions extending RuntimeException or Exception
- Use try-with-resources for resource management
- Log errors appropriately
- Never catch and ignore exceptions
Example:
public class UserService {
public User createUser(UserInput input) throws ValidationException {
if (input.getEmail() == null || input.getEmail().isEmpty()) {
throw new ValidationException("Email is required");
}
try {
return userRepository.save(input);
} catch (DataAccessException e) {
throw new ServiceException("Failed to create user", e);
}
}
}
public class ValidationException extends RuntimeException {
public ValidationException(String message) {
super(message);
}
}
Documentation
- Javadoc: Document all public APIs
- Package Info: Create
package-info.java - Examples: Include usage examples
- Generate:
mvn javadoc:javadocor./gradlew javadoc
Example:
/**
* Processes user data and returns validated result.
*
* <p>This method validates the input data according to business rules
* and returns a validated User object. If validation fails, it throws
* a ValidationException with details about the failure.
*
* @param input the user input data to process
* @return validated User object
* @throws ValidationException if input validation fails
* @throws ServiceException if database operation fails
*
* @see UserInput
* @see ValidationException
*
* @since 1.0.0
*/
public User processUser(UserInput input) throws ValidationException {
// Implementation
return null;
}
Project Structure
project/
├── pom.xml # Maven config (or build.gradle)
├── README.md # Project overview (allowed in root)
├── CHANGELOG.md # Version history (allowed in root)
├── AGENTS.md # AI assistant rules (allowed in root)
├── LICENSE # Project license (allowed in root)
├── CONTRIBUTING.md # Contribution guidelines (allowed in root)
├── CODE_OF_CONDUCT.md # Code of conduct (allowed in root)
├── SECURITY.md # Security policy (allowed in root)
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/
│ │ │ ├── Application.java
│ │ │ ├── controller/
│ │ │ ├── service/
│ │ │ └── repository/
│ │ └── resources/
│ │ └── application.properties
│ └── test/
│ ├── java/
│ │ └── com/example/
│ │ ├── service/
│ │ └── repository/
│ └── resources/
├── target/ # Build output (gitignored)
└── docs/ # Documentation
Modern Java Features
Records (Java 14+)
public record User(String email, String name, LocalDateTime createdAt) {
// Compact constructor
public User {
if (email == null || email.isEmpty()) {
throw new IllegalArgumentException("Email required");
}
}
}
Pattern Matching (Java 17+)
public String processValue(Object value) {
return switch (value) {
case String s -> "String: " + s;
case Integer i -> "Integer: " + i;
case null -> "Null value";
default -> "Unknown type";
};
}
Sealed Classes (Java 17+)
public sealed interface Result<T, E> permits Success, Failure {
// Interface definition
}
public record Success<T, E>(T value) implements Result<T, E> {}
public record Failure<T, E>(E error) implements Result<T, E> {}
CI/CD Requirements
Must include GitHub Actions workflows for:
-
Testing (
java-test.yml):- Test on ubuntu-latest, windows-latest
- Test on Java 17, 21
- Upload coverage to Codecov
-
Linting (
java-lint.yml):- Checkstyle checks
- PMD analysis
- SpotBugs detection
-
Build (
java-build.yml):- Build with Maven/Gradle
- Verify JAR creation
- Check dependencies
Package Publication
Publishing to Maven Central
Prerequisites:
- Sonatype OSSRH account (https://issues.sonatype.org)
- GPG key for signing
- Group ID approval (e.g.,
io.github.username) - Add credentials to GitHub Secrets
Maven (pom.xml) Configuration:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.your-username</groupId>
<artifactId>your-library</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>Your Library</name>
<description>A concise description of your library</description>
<url>https://github.com/your-org/your-library</url>
<licenses>
<license>
<name>MIT License</name>
<url>https://opensource.org/licenses/MIT</url>
</license>
</licenses>
<developers>
<developer>
<name>Your Name</name>
<email>your.email@example.com</email>
<organization>Your Organization</organization>
<organizationUrl>https://your-org.com</organizationUrl>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/your-org/your-library.git</connection>
<developerConnection>scm:git:ssh://github.com:your-org/your-library.git</developerConnection>
<url>https://github.com/your-org/your-library/tree/main</url>
</scm>
<distributionManagement>
<repository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<build>
<plugins>
<!-- Source JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Javadoc JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.3</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- GPG Signing -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Gradle (build.gradle.kts) Configuration:
plugins {
`java-library`
`maven-publish`
signing
id("io.github.gradle-nexus.publish-plugin") version "1.3.0"
}
group = "io.github.your-username"
version = "1.0.0"
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
withSourcesJar()
withJavadocJar()
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
pom {
name.set("Your Library")
description.set("A concise description of your library")
url.set("https://github.com/your-org/your-library")
licenses {
license {
name.set("MIT License")
url.set("https://opensource.org/licenses/MIT")
}
}
developers {
developer {
id.set("your-username")
name.set("Your Name")
email.set("your.email@example.com")
}
}
scm {
connection.set("scm:git:git://github.com/your-org/your-library.git")
developerConnection.set("scm:git:ssh://github.com:your-org/your-library.git")
url.set("https://github.com/your-org/your-library")
}
}
}
}
}
signing {
sign(publishing.publications["mavenJava"])
}
nexusPublishing {
repositories {
sonatype {
nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
}
}
}
Publishing Workflow:
-
Update version in pom.xml/build.gradle
-
Update CHANGELOG.md
-
Run quality checks:
bash# Maven mvn clean test mvn checkstyle:check mvn pmd:check # Gradle ./gradlew test ./gradlew checkstyleMain ./gradlew pmdMain -
Create git tag:
git tag v1.0.0 && git push --tags -
GitHub Actions automatically publishes to Maven Central
-
Or manual publish:
bash# Maven mvn clean deploy -P release # Gradle ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository
Publishing Checklist:
- ✅ All tests passing
- ✅ Checkstyle passes
- ✅ PMD analysis clean
- ✅ SpotBugs finds no issues
- ✅ Version updated
- ✅ CHANGELOG.md updated
- ✅ README.md up to date
- ✅ LICENSE file present
- ✅ Source JAR generated
- ✅ Javadoc JAR generated
- ✅ Artifacts signed with GPG
- ✅ POM metadata complete
GitHub Secrets:
Add these secrets to your repository:
MAVEN_USERNAME: Sonatype usernameMAVEN_PASSWORD: Sonatype passwordGPG_PRIVATE_KEY: Your GPG private key (exported as ASCII)GPG_PASSPHRASE: GPG key passphrase
Alternative: GitHub Packages
For simpler setup, publish to GitHub Packages:
<distributionManagement>
<repository>
<id>github</id>
<url>https://maven.pkg.github.com/your-org/your-library</url>
</repository>
</distributionManagement>
Users can then add to their pom.xml:
<repositories>
<repository>
<id>github</id>
<url>https://maven.pkg.github.com/your-org/*</url>
</repository>
</repositories>
Didn't find tool you were looking for?