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:
- Standardize builds across multiple Java projects
- Enforce security practices with automated scanning
- Accelerate setup with pre-configured jobs and commands
- Maintain consistency across development teams
- 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.