CircleCI Orbs for Java Projects

Introduction

CircleCI Orbs are reusable packages of configuration that help automate repeated processes, speed up project setup, and enforce best practices. For Java projects, orbs can streamline CI/CD pipelines with pre-configured jobs for testing, building, and deploying Java applications.

Core Java Orbs

1. Official CircleCI Java Orb

# .circleci/config.yml
version: 2.1
orbs:
java: circleci/[email protected]
maven: circleci/[email protected]
gradle: circleci/[email protected]
workflows:
java-test-workflow:
jobs:
- java/test:
version: '21'
test-task: test

2. Custom Java Orb Structure

# orbs/java-orb.yml
version: 2.1
description: "Custom Java CI/CD Orb"
commands:
setup-java:
description: "Setup Java environment with caching"
parameters:
java-version:
type: string
default: "21"
distribution:
type: string
default: "temurin"
steps:
- checkout
- java/install-jdk:
version: << parameters.java-version >>
distribution: << parameters.distribution >>
- restore_cache:
keys:
- v1-dependencies-{{ checksum "pom.xml" }}-{{ checksum "build.gradle" }}
- v1-dependencies-
run-tests:
description: "Run tests with coverage"
parameters:
test-task:
type: string
default: "test"
coverage-tool:
type: string
default: "jacoco"
steps:
- run:
name: Run Tests
command: |
if [ -f "pom.xml" ]; then
./mvnw << parameters.test-task >>
elif [ -f "build.gradle" ]; then
./gradlew << parameters.test-task >>
fi
- run:
name: Generate Coverage Report
command: |
if [ "<< parameters.coverage-tool >>" == "jacoco" ]; then
if [ -f "pom.xml" ]; then
./mvnw jacoco:report
elif [ -f "build.gradle" ]; then
./gradlew jacocoTestReport
fi
fi
jobs:
test:
docker:
- image: cimg/openjdk:21.0-node
resource_class: medium
steps:
- setup-java
- run-tests
- store_test_results:
path: target/surefire-reports
- store_artifacts:
path: target/site/jacoco
build:
docker:
- image: cimg/openjdk:21.0-node
resource_class: medium
steps:
- setup-java
- run:
name: Build Artifact
command: |
if [ -f "pom.xml" ]; then
./mvnw clean package -DskipTests
elif [ -f "build.gradle" ]; then
./gradlew clean build -x test
fi
- store_artifacts:
path: target/*.jar
destination: build-artifacts
security-scan:
docker:
- image: cimg/openjdk:21.0-node
steps:
- setup-java
- run:
name: Dependency Vulnerability Scan
command: |
if [ -f "pom.xml" ]; then
./mvnw org.owasp:dependency-check-maven:check
elif [ -f "build.gradle" ]; then
./gradlew dependencyCheckAnalyze
fi
- store_artifacts:
path: target/dependency-check-report.html

Complete Java CI/CD Pipeline

1. Maven Project Configuration

# .circleci/config.yml
version: 2.1
orbs:
java: circleci/[email protected]
maven: circleci/[email protected]
sonarcloud: sonarcloud/[email protected]
slack: circleci/[email protected]
aws-cli: circleci/[email protected]
workflows:
java-maven-pipeline:
jobs:
- java/test:
name: test-java-21
version: '21'
test-task: 'test'
post-steps:
- store_test_results:
path: target/surefire-reports
- store_artifacts:
path: target/site/jacoco
- sonarcloud/scan:
name: code-analysis
context: sonarcloud
requires:
- test-java-21
- security-scan:
name: security-scan
requires:
- test-java-21
- build-artifact:
name: build-artifact
requires:
- test-java-21
- code-analysis
- security-scan
filters:
branches:
only: main
- deploy-staging:
name: deploy-staging
requires:
- build-artifact
filters:
branches:
only: main
- integration-tests:
name: integration-tests
requires:
- deploy-staging
filters:
branches:
only: main
- deploy-production:
name: deploy-production
requires:
- integration-tests
filters:
branches:
only: main
context: aws-production
jobs:
security-scan:
executor: java/java21
steps:
- checkout
- java/install-dependencies
- run:
name: OWASP Dependency Check
command: |
./mvnw org.owasp:dependency-check-maven:check -s settings.xml
- store_artifacts:
path: target/dependency-check-report.html
build-artifact:
executor: java/java21
steps:
- checkout
- java/install-dependencies
- run:
name: Build JAR
command: ./mvnw clean package -DskipTests
- persist_to_workspace:
root: target
paths:
- *.jar
deploy-staging:
docker:
- image: cimg/aws:2023.12
steps:
- attach_workspace:
at: target
- aws-cli/setup:
role-arn: arn:aws:iam::123456789:role/CircleCI-Staging
role-session-name: circleci-staging
aws-region: us-east-1
- run:
name: Deploy to Staging
command: |
aws s3 cp target/*.jar s3://my-app-staging/artifacts/
aws ecs update-service --cluster my-app-staging --service api-service --force-new-deployment
integration-tests:
executor: java/java21
steps:
- checkout
- run:
name: Run Integration Tests
command: |
./mvnw verify -Pintegration-tests
environment:
API_BASE_URL: https://staging.myapp.com
- store_test_results:
path: target/failsafe-reports
deploy-production:
docker:
- image: cimg/aws:2023.12
steps:
- attach_workspace:
at: target
- aws-cli/setup:
role-arn: arn:aws:iam::123456789:role/CircleCI-Production
role-session-name: circleci-production
aws-region: us-east-1
- run:
name: Deploy to Production
command: |
aws s3 cp target/*.jar s3://my-app-production/artifacts/
aws ecs update-service --cluster my-app-production --service api-service --force-new-deployment
- slack/notify:
event: pass
template: basic_success_1
channel: deployments

2. Gradle Project Configuration

# .circleci/config.yml
version: 2.1
orbs:
java: circleci/[email protected]
gradle: circleci/[email protected]
codecov: codecov/[email protected]
workflows:
java-gradle-pipeline:
jobs:
- test-with-gradle
- code-analysis
- build-and-scan
- deploy
jobs:
test-with-gradle:
executor: gradle/default
steps:
- checkout
- gradle/load-cache
- gradle/run-tests:
test-command: test
test-result-paths: '**/build/test-results/test/*.xml'
- gradle/save-cache
- store_test_results:
path: build/test-results/test
- store_artifacts:
path: build/reports/tests/test
code-analysis:
executor: gradle/default
steps:
- checkout
- gradle/load-cache
- run:
name: Code Quality Checks
command: |
./gradlew checkstyleMain checkstyleTest pmdMain pmdTest
- store_artifacts:
path: build/reports/checkstyle
- store_artifacts:
path: build/reports/pmd
build-and-scan:
executor: gradle/default
steps:
- checkout
- gradle/load-cache
- run:
name: Build and Security Scan
command: |
./gradlew build -x test
./gradlew dependencyCheckAnalyze
- store_artifacts:
path: build/libs
- store_artifacts:
path: build/reports/dependency-check
deploy:
executor: gradle/default
steps:
- checkout
- gradle/load-cache
- run:
name: Build Distribution
command: ./gradlew assembleDist
- run:
name: Upload to Repository
command: |
./gradlew publish

Advanced Java Orb Features

1. Multi-Module Maven Project Orb

# orbs/multi-module-java.yml
version: 2.1
commands:
setup-multi-module:
description: "Setup for multi-module Maven projects"
parameters:
java-version:
type: string
default: "21"
modules:
type: string
default: "*"
steps:
- checkout
- java/install-jdk:
version: << parameters.java-version >>
- restore_cache:
keys:
- maven-multi-module-{{ checksum "pom.xml" }}-{{ checksum "**/pom.xml" }}
- maven-multi-module-
build-modules:
description: "Build specific modules"
parameters:
modules:
type: string
default: ""
profiles:
type: string
default: ""
steps:
- run:
name: Build Modules
command: |
if [ -n "<< parameters.modules >>" ]; then
MODULE_FLAG="-pl << parameters.modules >>"
fi
if [ -n "<< parameters.profiles >>" ]; then
PROFILE_FLAG="-P << parameters.profiles >>"
fi
./mvnw clean install $MODULE_FLAG $PROFILE_FLAG
test-modules-parallel:
description: "Run tests in parallel across modules"
parameters:
parallel-threads:
type: integer
default: 4
steps:
- run:
name: Parallel Tests
command: |
./mvnw test -T << parameters.parallel-threads >>
jobs:
multi-module-test:
docker:
- image: cimg/openjdk:21.0
resource_class: large
parallelism: 4
steps:
- setup-multi-module
- test-modules-parallel
- store_test_results:
path: */target/surefire-reports
build-docker-images:
docker:
- image: cimg/openjdk:21.0
steps:
- setup-multi-module
- build-modules
- run:
name: Build Docker Images
command: |
./mvnw spring-boot:build-image -DskipTests
- run:
name: Scan Docker Images
command: |
for module in */; do
if [ -f "$module/pom.xml" ]; then
IMAGE_NAME=$(basename $module)
docker scan $IMAGE_NAME:latest
fi
done

2. Spring Boot Specific Orb

# orbs/spring-boot-orb.yml
version: 2.1
commands:
setup-spring-boot:
description: "Setup Spring Boot specific environment"
parameters:
spring-boot-version:
type: string
default: "3.2.0"
java-version:
type: string
default: "21"
steps:
- setup-java:
java-version: << parameters.java-version >>
- run:
name: Validate Spring Boot Version
command: |
if [ -f "pom.xml" ]; then
SPRING_VERSION=$(mvn help:evaluate -Dexpression=spring-boot.version -q -DforceStdout)
echo "Using Spring Boot version: $SPRING_VERSION"
fi
spring-boot-test:
description: "Run Spring Boot specific tests"
parameters:
test-profile:
type: string
default: "test"
steps:
- run:
name: Run Spring Tests
command: |
if [ -f "pom.xml" ]; then
./mvnw test -P<< parameters.test-profile >> -Dspring.profiles.active=test
else
./gradlew test -Pspring.profiles.active=test
fi
- run:
name: Test Containers Cleanup
command: |
docker system prune -f
build-spring-native:
description: "Build Spring Native image"
steps:
- run:
name: Build Native Image
command: |
if [ -f "pom.xml" ]; then
./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=myapp:native
else
./gradlew bootBuildImage --imageName=myapp:native
fi
- store_artifacts:
path: build/*.jar
jobs:
spring-boot-build:
docker:
- image: cimg/openjdk:21.0
steps:
- checkout
- setup-spring-boot
- spring-boot-test
- build-spring-native
database-migration:
docker:
- image: cimg/openjdk:21.0
- image: cimg/postgres:15.0
environment:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: testdb
steps:
- checkout
- setup-spring-boot
- run:
name: Run Database Migrations
command: |
./mvnw flyway:migrate -Dflyway.url=jdbc:postgresql://localhost:5432/testdb
environment:
SPRING_PROFILES_ACTIVE: test
api-docs:
docker:
- image: cimg/openjdk:21.0
steps:
- checkout
- setup-spring-boot
- run:
name: Generate API Documentation
command: |
./mvnw spring-restdocs:asciidoc-generate
- store_artifacts:
path: target/generated-docs

Security and Compliance Orb

# orbs/security-compliance.yml
version: 2.1
commands:
license-check:
description: "Check license compliance"
steps:
- run:
name: License Compliance Check
command: |
if [ -f "pom.xml" ]; then
./mvnw org.codehaus.mojo:license-maven-plugin:download-licenses
./mvnw org.codehaus.mojo:license-maven-plugin:check-licenses
elif [ -f "build.gradle" ]; then
./gradlew checkLicense
fi
sbom-generate:
description: "Generate Software Bill of Materials"
steps:
- run:
name: Generate SBOM
command: |
if [ -f "pom.xml" ]; then
./mvnw org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom
elif [ -f "build.gradle" ]; then
./gradlew cyclonedxBom
fi
- store_artifacts:
path: target/bom.xml
security-scan:
description: "Comprehensive security scanning"
steps:
- run:
name: SAST Scan
command: |
if [ -f "pom.xml" ]; then
./mvnw org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
fi
- run:
name: Secret Scanning
command: |
git secrets --scan
jobs:
security-compliance:
docker:
- image: cimg/openjdk:21.0
steps:
- checkout
- setup-java
- license-check
- sbom-generate
- security-scan

Monitoring and Notifications

1. Pipeline Notifications Orb

# orbs/notifications.yml
version: 2.1
commands:
notify-start:
description: "Notify pipeline start"
parameters:
pipeline-url:
type: string
steps:
- slack/notify:
event: start
template: basic_success_1
channel: builds
custom: |
{
"attachments": [
{
"title": "Build Started",
"text": "Pipeline *${CIRCLE_WORKFLOW_ID}* started",
"color": "#3498db"
}
]
}
notify-success:
description: "Notify pipeline success"
steps:
- slack/notify:
event: success
template: basic_success_1
channel: builds
notify-failure:
description: "Notify pipeline failure"
steps:
- slack/notify:
event: fail
template: basic_fail_1
channel: builds-alerts
jobs:
performance-metrics:
docker:
- image: cimg/openjdk:21.0
steps:
- checkout
- run:
name: Collect Build Metrics
command: |
echo "Build time: $CIRCLE_BUILD_TIME seconds"
echo "Test count: $(find . -name "TEST-*.xml" | wc -l)"
when: always
- store_metrics:
path: metrics.xml

Best Practices Configuration

1. Java Project Template

# .circleci/config.yml
version: 2.1
orbs:
java-ci: your-namespace/[email protected]
security: your-namespace/[email protected]
notifications: your-namespace/[email protected]
workflows:
standard-java-pipeline:
jobs:
- java-ci/validate-environment
- java-ci/run-unit-tests:
requires:
- validate-environment
- security/dependency-scan:
requires:
- validate-environment
- security/code-analysis:
requires:
- run-unit-tests
- java-ci/build-artifact:
requires:
- run-unit-tests
- dependency-scan
- java-ci/integration-tests:
requires:
- build-artifact
- java-ci/deploy-staging:
requires:
- integration-tests
filters:
branches:
only: main
- notifications/send-summary:
requires:
- deploy-staging
filters:
branches:
only: main

Conclusion

CircleCI Orbs for Java projects provide powerful, reusable configuration components that can significantly streamline your CI/CD pipelines. By leveraging these orbs, teams can:

  1. Standardize builds across multiple Java projects
  2. Enforce security practices with automated scanning
  3. Accelerate setup with pre-configured jobs and commands
  4. Maintain consistency across development teams
  5. Scale efficiently as projects grow in complexity

The key to successful orb usage is starting with official orbs, creating custom orbs for organization-specific needs, and continuously refining based on team feedback and evolving requirements.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper